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