1use core::marker::PhantomData;
6use yoke::Yokeable;
7
8use crate::prelude::*;
9
10pub trait DataProvider<M>
12where
13 M: DataMarker,
14{
15 fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError>;
20}
21
22impl<M, P> DataProvider<M> for &P
23where
24 M: DataMarker,
25 P: DataProvider<M> + ?Sized,
26{
27 #[inline]
28 fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
29 (*self).load(req)
30 }
31}
32
33#[cfg(feature = "alloc")]
34impl<M, P> DataProvider<M> for alloc::boxed::Box<P>
35where
36 M: DataMarker,
37 P: DataProvider<M> + ?Sized,
38{
39 #[inline]
40 fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
41 (**self).load(req)
42 }
43}
44
45#[cfg(feature = "alloc")]
46impl<M, P> DataProvider<M> for alloc::rc::Rc<P>
47where
48 M: DataMarker,
49 P: DataProvider<M> + ?Sized,
50{
51 #[inline]
52 fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
53 (**self).load(req)
54 }
55}
56
57#[cfg(target_has_atomic = "ptr")]
58#[cfg(feature = "alloc")]
59impl<M, P> DataProvider<M> for alloc::sync::Arc<P>
60where
61 M: DataMarker,
62 P: DataProvider<M> + ?Sized,
63{
64 #[inline]
65 fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
66 (**self).load(req)
67 }
68}
69
70pub trait DryDataProvider<M: DataMarker>: DataProvider<M> {
73 fn dry_load(&self, req: DataRequest) -> Result<DataResponseMetadata, DataError>;
81}
82
83impl<M, P> DryDataProvider<M> for &P
84where
85 M: DataMarker,
86 P: DryDataProvider<M> + ?Sized,
87{
88 #[inline]
89 fn dry_load(&self, req: DataRequest) -> Result<DataResponseMetadata, DataError> {
90 (*self).dry_load(req)
91 }
92}
93
94#[cfg(feature = "alloc")]
95impl<M, P> DryDataProvider<M> for alloc::boxed::Box<P>
96where
97 M: DataMarker,
98 P: DryDataProvider<M> + ?Sized,
99{
100 #[inline]
101 fn dry_load(&self, req: DataRequest) -> Result<DataResponseMetadata, DataError> {
102 (**self).dry_load(req)
103 }
104}
105
106#[cfg(feature = "alloc")]
107impl<M, P> DryDataProvider<M> for alloc::rc::Rc<P>
108where
109 M: DataMarker,
110 P: DryDataProvider<M> + ?Sized,
111{
112 #[inline]
113 fn dry_load(&self, req: DataRequest) -> Result<DataResponseMetadata, DataError> {
114 (**self).dry_load(req)
115 }
116}
117
118#[cfg(target_has_atomic = "ptr")]
119#[cfg(feature = "alloc")]
120impl<M, P> DryDataProvider<M> for alloc::sync::Arc<P>
121where
122 M: DataMarker,
123 P: DryDataProvider<M> + ?Sized,
124{
125 #[inline]
126 fn dry_load(&self, req: DataRequest) -> Result<DataResponseMetadata, DataError> {
127 (**self).dry_load(req)
128 }
129}
130
131#[cfg(feature = "alloc")]
136pub trait IterableDataProvider<M: DataMarker>: DataProvider<M> {
137 fn iter_ids(&self) -> Result<alloc::collections::BTreeSet<DataIdentifierCow>, DataError>;
139}
140
141pub trait DynamicDataProvider<M>
145where
146 M: DynamicDataMarker,
147{
148 fn load_data(
153 &self,
154 marker: DataMarkerInfo,
155 req: DataRequest,
156 ) -> Result<DataResponse<M>, DataError>;
157}
158
159impl<M, P> DynamicDataProvider<M> for &P
160where
161 M: DynamicDataMarker,
162 P: DynamicDataProvider<M> + ?Sized,
163{
164 #[inline]
165 fn load_data(
166 &self,
167 marker: DataMarkerInfo,
168 req: DataRequest,
169 ) -> Result<DataResponse<M>, DataError> {
170 (*self).load_data(marker, req)
171 }
172}
173
174#[cfg(feature = "alloc")]
175impl<M, P> DynamicDataProvider<M> for alloc::boxed::Box<P>
176where
177 M: DynamicDataMarker,
178 P: DynamicDataProvider<M> + ?Sized,
179{
180 #[inline]
181 fn load_data(
182 &self,
183 marker: DataMarkerInfo,
184 req: DataRequest,
185 ) -> Result<DataResponse<M>, DataError> {
186 (**self).load_data(marker, req)
187 }
188}
189
190#[cfg(feature = "alloc")]
191impl<M, P> DynamicDataProvider<M> for alloc::rc::Rc<P>
192where
193 M: DynamicDataMarker,
194 P: DynamicDataProvider<M> + ?Sized,
195{
196 #[inline]
197 fn load_data(
198 &self,
199 marker: DataMarkerInfo,
200 req: DataRequest,
201 ) -> Result<DataResponse<M>, DataError> {
202 (**self).load_data(marker, req)
203 }
204}
205
206#[cfg(target_has_atomic = "ptr")]
207#[cfg(feature = "alloc")]
208impl<M, P> DynamicDataProvider<M> for alloc::sync::Arc<P>
209where
210 M: DynamicDataMarker,
211 P: DynamicDataProvider<M> + ?Sized,
212{
213 #[inline]
214 fn load_data(
215 &self,
216 marker: DataMarkerInfo,
217 req: DataRequest,
218 ) -> Result<DataResponse<M>, DataError> {
219 (**self).load_data(marker, req)
220 }
221}
222
223pub trait DynamicDryDataProvider<M: DynamicDataMarker>: DynamicDataProvider<M> {
226 fn dry_load_data(
234 &self,
235 marker: DataMarkerInfo,
236 req: DataRequest,
237 ) -> Result<DataResponseMetadata, DataError>;
238}
239
240impl<M, P> DynamicDryDataProvider<M> for &P
241where
242 M: DynamicDataMarker,
243 P: DynamicDryDataProvider<M> + ?Sized,
244{
245 #[inline]
246 fn dry_load_data(
247 &self,
248 marker: DataMarkerInfo,
249 req: DataRequest,
250 ) -> Result<DataResponseMetadata, DataError> {
251 (*self).dry_load_data(marker, req)
252 }
253}
254
255#[cfg(feature = "alloc")]
256impl<M, P> DynamicDryDataProvider<M> for alloc::boxed::Box<P>
257where
258 M: DynamicDataMarker,
259 P: DynamicDryDataProvider<M> + ?Sized,
260{
261 #[inline]
262 fn dry_load_data(
263 &self,
264 marker: DataMarkerInfo,
265 req: DataRequest,
266 ) -> Result<DataResponseMetadata, DataError> {
267 (**self).dry_load_data(marker, req)
268 }
269}
270
271#[cfg(feature = "alloc")]
272impl<M, P> DynamicDryDataProvider<M> for alloc::rc::Rc<P>
273where
274 M: DynamicDataMarker,
275 P: DynamicDryDataProvider<M> + ?Sized,
276{
277 #[inline]
278 fn dry_load_data(
279 &self,
280 marker: DataMarkerInfo,
281 req: DataRequest,
282 ) -> Result<DataResponseMetadata, DataError> {
283 (**self).dry_load_data(marker, req)
284 }
285}
286
287#[cfg(target_has_atomic = "ptr")]
288#[cfg(feature = "alloc")]
289impl<M, P> DynamicDryDataProvider<M> for alloc::sync::Arc<P>
290where
291 M: DynamicDataMarker,
292 P: DynamicDryDataProvider<M> + ?Sized,
293{
294 #[inline]
295 fn dry_load_data(
296 &self,
297 marker: DataMarkerInfo,
298 req: DataRequest,
299 ) -> Result<DataResponseMetadata, DataError> {
300 (**self).dry_load_data(marker, req)
301 }
302}
303
304#[cfg(feature = "alloc")]
309pub trait IterableDynamicDataProvider<M: DynamicDataMarker>: DynamicDataProvider<M> {
310 fn iter_ids_for_marker(
312 &self,
313 marker: DataMarkerInfo,
314 ) -> Result<alloc::collections::BTreeSet<DataIdentifierCow>, DataError>;
315}
316
317#[cfg(feature = "alloc")]
318impl<M, P> IterableDynamicDataProvider<M> for alloc::boxed::Box<P>
319where
320 M: DynamicDataMarker,
321 P: IterableDynamicDataProvider<M> + ?Sized,
322{
323 fn iter_ids_for_marker(
324 &self,
325 marker: DataMarkerInfo,
326 ) -> Result<alloc::collections::BTreeSet<DataIdentifierCow>, DataError> {
327 (**self).iter_ids_for_marker(marker)
328 }
329}
330
331pub trait BoundDataProvider<M>
340where
341 M: DynamicDataMarker,
342{
343 fn load_bound(&self, req: DataRequest) -> Result<DataResponse<M>, DataError>;
348 fn bound_marker(&self) -> DataMarkerInfo;
350}
351
352impl<M, P> BoundDataProvider<M> for &P
353where
354 M: DynamicDataMarker,
355 P: BoundDataProvider<M> + ?Sized,
356{
357 #[inline]
358 fn load_bound(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
359 (*self).load_bound(req)
360 }
361 #[inline]
362 fn bound_marker(&self) -> DataMarkerInfo {
363 (*self).bound_marker()
364 }
365}
366
367#[cfg(feature = "alloc")]
368impl<M, P> BoundDataProvider<M> for alloc::boxed::Box<P>
369where
370 M: DynamicDataMarker,
371 P: BoundDataProvider<M> + ?Sized,
372{
373 #[inline]
374 fn load_bound(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
375 (**self).load_bound(req)
376 }
377 #[inline]
378 fn bound_marker(&self) -> DataMarkerInfo {
379 (**self).bound_marker()
380 }
381}
382
383#[cfg(feature = "alloc")]
384impl<M, P> BoundDataProvider<M> for alloc::rc::Rc<P>
385where
386 M: DynamicDataMarker,
387 P: BoundDataProvider<M> + ?Sized,
388{
389 #[inline]
390 fn load_bound(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
391 (**self).load_bound(req)
392 }
393 #[inline]
394 fn bound_marker(&self) -> DataMarkerInfo {
395 (**self).bound_marker()
396 }
397}
398
399#[cfg(target_has_atomic = "ptr")]
400#[cfg(feature = "alloc")]
401impl<M, P> BoundDataProvider<M> for alloc::sync::Arc<P>
402where
403 M: DynamicDataMarker,
404 P: BoundDataProvider<M> + ?Sized,
405{
406 #[inline]
407 fn load_bound(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
408 (**self).load_bound(req)
409 }
410 #[inline]
411 fn bound_marker(&self) -> DataMarkerInfo {
412 (**self).bound_marker()
413 }
414}
415
416#[derive(Debug)]
420pub struct DataProviderWithMarker<M, P> {
421 inner: P,
422 _marker: PhantomData<M>,
423}
424
425impl<M, P> DataProviderWithMarker<M, P>
426where
427 M: DataMarker,
428 P: DataProvider<M>,
429{
430 pub const fn new(inner: P) -> Self {
432 Self {
433 inner,
434 _marker: PhantomData,
435 }
436 }
437}
438
439impl<M, M0, Y, P> BoundDataProvider<M0> for DataProviderWithMarker<M, P>
440where
441 M: DataMarker<DataStruct = Y>,
442 M0: DynamicDataMarker<DataStruct = Y>,
443 Y: for<'a> Yokeable<'a>,
444 P: DataProvider<M>,
445{
446 #[inline]
447 fn load_bound(&self, req: DataRequest) -> Result<DataResponse<M0>, DataError> {
448 self.inner.load(req).map(DataResponse::cast)
449 }
450 #[inline]
451 fn bound_marker(&self) -> DataMarkerInfo {
452 M::INFO
453 }
454}
455
456#[cfg(test)]
457mod test {
458
459 use super::*;
460 use crate::hello_world::*;
461 use alloc::borrow::Cow;
462 use alloc::string::String;
463 use core::fmt::Debug;
464 use serde::{Deserialize, Serialize};
465
466 #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, yoke::Yokeable)]
471 pub struct HelloAlt {
472 message: String,
473 }
474
475 data_marker!(HelloAltMarkerV1, HelloAlt);
476
477 #[derive(Deserialize, Debug, Clone, Default, PartialEq)]
478 struct HelloCombined<'data> {
479 #[serde(borrow)]
480 pub hello_v1: HelloWorld<'data>,
481 pub hello_alt: HelloAlt,
482 }
483
484 #[derive(Debug)]
487 struct DataWarehouse {
488 hello_v1: HelloWorld<'static>,
489 hello_alt: HelloAlt,
490 }
491
492 impl DataProvider<HelloWorldV1> for DataWarehouse {
493 fn load(&self, _: DataRequest) -> Result<DataResponse<HelloWorldV1>, DataError> {
494 Ok(DataResponse {
495 metadata: DataResponseMetadata::default(),
496 payload: DataPayload::from_owned(self.hello_v1.clone()),
497 })
498 }
499 }
500
501 #[derive(Debug)]
503 struct DataProvider2 {
504 data: DataWarehouse,
505 }
506
507 impl From<DataWarehouse> for DataProvider2 {
508 fn from(warehouse: DataWarehouse) -> Self {
509 DataProvider2 { data: warehouse }
510 }
511 }
512
513 impl DataProvider<HelloWorldV1> for DataProvider2 {
514 fn load(&self, _: DataRequest) -> Result<DataResponse<HelloWorldV1>, DataError> {
515 Ok(DataResponse {
516 metadata: DataResponseMetadata::default(),
517 payload: DataPayload::from_owned(self.data.hello_v1.clone()),
518 })
519 }
520 }
521
522 impl DataProvider<HelloAltMarkerV1> for DataProvider2 {
523 fn load(&self, _: DataRequest) -> Result<DataResponse<HelloAltMarkerV1>, DataError> {
524 Ok(DataResponse {
525 metadata: DataResponseMetadata::default(),
526 payload: DataPayload::from_owned(self.data.hello_alt.clone()),
527 })
528 }
529 }
530
531 const DATA: &str = r#"{
532 "hello_v1": {
533 "message": "Hello "
534 },
535 "hello_alt": {
536 "message": "Hello Alt"
537 }
538 }"#;
539
540 fn get_warehouse(data: &'static str) -> DataWarehouse {
541 let data: HelloCombined = serde_json::from_str(data).expect("Well-formed data");
542 DataWarehouse {
543 hello_v1: data.hello_v1,
544 hello_alt: data.hello_alt,
545 }
546 }
547
548 fn get_payload_v1<P: DataProvider<HelloWorldV1> + ?Sized>(
549 provider: &P,
550 ) -> Result<DataPayload<HelloWorldV1>, DataError> {
551 provider.load(Default::default()).map(|r| r.payload)
552 }
553
554 fn get_payload_alt<P: DataProvider<HelloAltMarkerV1> + ?Sized>(
555 provider: &P,
556 ) -> Result<DataPayload<HelloAltMarkerV1>, DataError> {
557 provider.load(Default::default()).map(|r| r.payload)
558 }
559
560 #[test]
561 fn test_warehouse_owned() {
562 let warehouse = get_warehouse(DATA);
563 let hello_data = get_payload_v1(&warehouse).unwrap();
564 assert!(matches!(
565 hello_data.get(),
566 HelloWorld {
567 message: Cow::Borrowed(_),
568 }
569 ));
570 }
571
572 #[test]
573 fn test_warehouse_owned_dyn_generic() {
574 let warehouse = get_warehouse(DATA);
575 let hello_data = get_payload_v1(&warehouse as &dyn DataProvider<HelloWorldV1>).unwrap();
576 assert!(matches!(
577 hello_data.get(),
578 HelloWorld {
579 message: Cow::Borrowed(_),
580 }
581 ));
582 }
583
584 #[test]
585 fn test_provider2() {
586 let warehouse = get_warehouse(DATA);
587 let provider = DataProvider2::from(warehouse);
588 let hello_data = get_payload_v1(&provider).unwrap();
589 assert!(matches!(
590 hello_data.get(),
591 HelloWorld {
592 message: Cow::Borrowed(_),
593 }
594 ));
595 }
596
597 #[test]
598 fn test_provider2_dyn_generic() {
599 let warehouse = get_warehouse(DATA);
600 let provider = DataProvider2::from(warehouse);
601 let hello_data = get_payload_v1(&provider as &dyn DataProvider<HelloWorldV1>).unwrap();
602 assert!(matches!(
603 hello_data.get(),
604 HelloWorld {
605 message: Cow::Borrowed(_),
606 }
607 ));
608 }
609
610 #[test]
611 fn test_provider2_dyn_generic_alt() {
612 let warehouse = get_warehouse(DATA);
613 let provider = DataProvider2::from(warehouse);
614 let hello_data = get_payload_alt(&provider as &dyn DataProvider<HelloAltMarkerV1>).unwrap();
615 assert!(matches!(hello_data.get(), HelloAlt { .. }));
616 }
617
618 fn check_v1_v2<P>(d: &P)
619 where
620 P: DataProvider<HelloWorldV1> + DataProvider<HelloAltMarkerV1> + ?Sized,
621 {
622 let v1: DataPayload<HelloWorldV1> = d.load(Default::default()).unwrap().payload;
623 let v2: DataPayload<HelloAltMarkerV1> = d.load(Default::default()).unwrap().payload;
624 if v1.get().message == v2.get().message {
625 panic!()
626 }
627 }
628
629 #[test]
630 fn test_v1_v2_generic() {
631 let warehouse = get_warehouse(DATA);
632 let provider = DataProvider2::from(warehouse);
633 check_v1_v2(&provider);
634 }
635}