use core::marker::PhantomData;
use yoke::Yokeable;
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
use crate::prelude::*;
pub trait DataProvider<M>
where
M: DataMarker,
{
fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError>;
}
impl<M, P> DataProvider<M> for &P
where
M: DataMarker,
P: DataProvider<M> + ?Sized,
{
#[inline]
fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
(*self).load(req)
}
}
#[cfg(feature = "alloc")]
impl<M, P> DataProvider<M> for Box<P>
where
M: DataMarker,
P: DataProvider<M> + ?Sized,
{
#[inline]
fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
(**self).load(req)
}
}
#[cfg(feature = "alloc")]
impl<M, P> DataProvider<M> for alloc::rc::Rc<P>
where
M: DataMarker,
P: DataProvider<M> + ?Sized,
{
#[inline]
fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
(**self).load(req)
}
}
#[cfg(target_has_atomic = "ptr")]
#[cfg(feature = "alloc")]
impl<M, P> DataProvider<M> for alloc::sync::Arc<P>
where
M: DataMarker,
P: DataProvider<M> + ?Sized,
{
#[inline]
fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
(**self).load(req)
}
}
pub trait DryDataProvider<M: DataMarker>: DataProvider<M> {
fn dry_load(&self, req: DataRequest) -> Result<DataResponseMetadata, DataError>;
}
impl<M, P> DryDataProvider<M> for &P
where
M: DataMarker,
P: DryDataProvider<M> + ?Sized,
{
#[inline]
fn dry_load(&self, req: DataRequest) -> Result<DataResponseMetadata, DataError> {
(*self).dry_load(req)
}
}
#[cfg(feature = "alloc")]
impl<M, P> DryDataProvider<M> for Box<P>
where
M: DataMarker,
P: DryDataProvider<M> + ?Sized,
{
#[inline]
fn dry_load(&self, req: DataRequest) -> Result<DataResponseMetadata, DataError> {
(**self).dry_load(req)
}
}
#[cfg(feature = "alloc")]
impl<M, P> DryDataProvider<M> for alloc::rc::Rc<P>
where
M: DataMarker,
P: DryDataProvider<M> + ?Sized,
{
#[inline]
fn dry_load(&self, req: DataRequest) -> Result<DataResponseMetadata, DataError> {
(**self).dry_load(req)
}
}
#[cfg(target_has_atomic = "ptr")]
#[cfg(feature = "alloc")]
impl<M, P> DryDataProvider<M> for alloc::sync::Arc<P>
where
M: DataMarker,
P: DryDataProvider<M> + ?Sized,
{
#[inline]
fn dry_load(&self, req: DataRequest) -> Result<DataResponseMetadata, DataError> {
(**self).dry_load(req)
}
}
#[cfg(feature = "alloc")]
pub trait IterableDataProvider<M: DataMarker>: DataProvider<M> {
fn iter_ids(&self) -> Result<alloc::collections::BTreeSet<DataIdentifierCow<'_>>, DataError>;
}
pub trait DynamicDataProvider<M>
where
M: DynamicDataMarker,
{
fn load_data(
&self,
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<DataResponse<M>, DataError>;
}
impl<M, P> DynamicDataProvider<M> for &P
where
M: DynamicDataMarker,
P: DynamicDataProvider<M> + ?Sized,
{
#[inline]
fn load_data(
&self,
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<DataResponse<M>, DataError> {
(*self).load_data(marker, req)
}
}
#[cfg(feature = "alloc")]
impl<M, P> DynamicDataProvider<M> for Box<P>
where
M: DynamicDataMarker,
P: DynamicDataProvider<M> + ?Sized,
{
#[inline]
fn load_data(
&self,
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<DataResponse<M>, DataError> {
(**self).load_data(marker, req)
}
}
#[cfg(feature = "alloc")]
impl<M, P> DynamicDataProvider<M> for alloc::rc::Rc<P>
where
M: DynamicDataMarker,
P: DynamicDataProvider<M> + ?Sized,
{
#[inline]
fn load_data(
&self,
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<DataResponse<M>, DataError> {
(**self).load_data(marker, req)
}
}
#[cfg(target_has_atomic = "ptr")]
#[cfg(feature = "alloc")]
impl<M, P> DynamicDataProvider<M> for alloc::sync::Arc<P>
where
M: DynamicDataMarker,
P: DynamicDataProvider<M> + ?Sized,
{
#[inline]
fn load_data(
&self,
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<DataResponse<M>, DataError> {
(**self).load_data(marker, req)
}
}
pub trait DynamicDryDataProvider<M: DynamicDataMarker>: DynamicDataProvider<M> {
fn dry_load_data(
&self,
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<DataResponseMetadata, DataError>;
}
impl<M, P> DynamicDryDataProvider<M> for &P
where
M: DynamicDataMarker,
P: DynamicDryDataProvider<M> + ?Sized,
{
#[inline]
fn dry_load_data(
&self,
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<DataResponseMetadata, DataError> {
(*self).dry_load_data(marker, req)
}
}
#[cfg(feature = "alloc")]
impl<M, P> DynamicDryDataProvider<M> for Box<P>
where
M: DynamicDataMarker,
P: DynamicDryDataProvider<M> + ?Sized,
{
#[inline]
fn dry_load_data(
&self,
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<DataResponseMetadata, DataError> {
(**self).dry_load_data(marker, req)
}
}
#[cfg(feature = "alloc")]
impl<M, P> DynamicDryDataProvider<M> for alloc::rc::Rc<P>
where
M: DynamicDataMarker,
P: DynamicDryDataProvider<M> + ?Sized,
{
#[inline]
fn dry_load_data(
&self,
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<DataResponseMetadata, DataError> {
(**self).dry_load_data(marker, req)
}
}
#[cfg(target_has_atomic = "ptr")]
#[cfg(feature = "alloc")]
impl<M, P> DynamicDryDataProvider<M> for alloc::sync::Arc<P>
where
M: DynamicDataMarker,
P: DynamicDryDataProvider<M> + ?Sized,
{
#[inline]
fn dry_load_data(
&self,
marker: DataMarkerInfo,
req: DataRequest,
) -> Result<DataResponseMetadata, DataError> {
(**self).dry_load_data(marker, req)
}
}
#[cfg(feature = "alloc")]
pub trait IterableDynamicDataProvider<M: DynamicDataMarker>: DynamicDataProvider<M> {
fn iter_ids_for_marker(
&self,
marker: DataMarkerInfo,
) -> Result<alloc::collections::BTreeSet<DataIdentifierCow<'_>>, DataError>;
}
#[cfg(feature = "alloc")]
impl<M, P> IterableDynamicDataProvider<M> for Box<P>
where
M: DynamicDataMarker,
P: IterableDynamicDataProvider<M> + ?Sized,
{
fn iter_ids_for_marker(
&self,
marker: DataMarkerInfo,
) -> Result<alloc::collections::BTreeSet<DataIdentifierCow<'_>>, DataError> {
(**self).iter_ids_for_marker(marker)
}
}
pub trait BoundDataProvider<M>
where
M: DynamicDataMarker,
{
fn load_bound(&self, req: DataRequest) -> Result<DataResponse<M>, DataError>;
fn bound_marker(&self) -> DataMarkerInfo;
}
impl<M, P> BoundDataProvider<M> for &P
where
M: DynamicDataMarker,
P: BoundDataProvider<M> + ?Sized,
{
#[inline]
fn load_bound(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
(*self).load_bound(req)
}
#[inline]
fn bound_marker(&self) -> DataMarkerInfo {
(*self).bound_marker()
}
}
#[cfg(feature = "alloc")]
impl<M, P> BoundDataProvider<M> for Box<P>
where
M: DynamicDataMarker,
P: BoundDataProvider<M> + ?Sized,
{
#[inline]
fn load_bound(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
(**self).load_bound(req)
}
#[inline]
fn bound_marker(&self) -> DataMarkerInfo {
(**self).bound_marker()
}
}
#[cfg(feature = "alloc")]
impl<M, P> BoundDataProvider<M> for alloc::rc::Rc<P>
where
M: DynamicDataMarker,
P: BoundDataProvider<M> + ?Sized,
{
#[inline]
fn load_bound(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
(**self).load_bound(req)
}
#[inline]
fn bound_marker(&self) -> DataMarkerInfo {
(**self).bound_marker()
}
}
#[cfg(target_has_atomic = "ptr")]
#[cfg(feature = "alloc")]
impl<M, P> BoundDataProvider<M> for alloc::sync::Arc<P>
where
M: DynamicDataMarker,
P: BoundDataProvider<M> + ?Sized,
{
#[inline]
fn load_bound(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
(**self).load_bound(req)
}
#[inline]
fn bound_marker(&self) -> DataMarkerInfo {
(**self).bound_marker()
}
}
#[derive(Debug)]
pub struct DataProviderWithMarker<M, P> {
inner: P,
_marker: PhantomData<M>,
}
impl<M, P> DataProviderWithMarker<M, P>
where
M: DataMarker,
P: DataProvider<M>,
{
pub const fn new(inner: P) -> Self {
Self {
inner,
_marker: PhantomData,
}
}
}
impl<M, M0, Y, P> BoundDataProvider<M0> for DataProviderWithMarker<M, P>
where
M: DataMarker<DataStruct = Y>,
M0: DynamicDataMarker<DataStruct = Y>,
Y: for<'a> Yokeable<'a>,
P: DataProvider<M>,
{
#[inline]
fn load_bound(&self, req: DataRequest) -> Result<DataResponse<M0>, DataError> {
self.inner.load(req).map(DataResponse::cast)
}
#[inline]
fn bound_marker(&self) -> DataMarkerInfo {
M::INFO
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::hello_world::*;
use alloc::borrow::Cow;
use alloc::string::String;
use core::fmt::Debug;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, yoke::Yokeable)]
pub struct HelloAlt {
message: String,
}
data_marker!(HelloAltMarkerV1, HelloAlt);
#[derive(Deserialize, Debug, Clone, Default, PartialEq)]
struct HelloCombined<'data> {
#[serde(borrow)]
pub hello_v1: HelloWorld<'data>,
pub hello_alt: HelloAlt,
}
#[derive(Debug)]
struct DataWarehouse {
hello_v1: HelloWorld<'static>,
hello_alt: HelloAlt,
}
impl DataProvider<HelloWorldV1> for DataWarehouse {
fn load(&self, _: DataRequest) -> Result<DataResponse<HelloWorldV1>, DataError> {
Ok(DataResponse {
metadata: DataResponseMetadata::default(),
payload: DataPayload::from_owned(self.hello_v1.clone()),
})
}
}
#[derive(Debug)]
struct DataProvider2 {
data: DataWarehouse,
}
impl From<DataWarehouse> for DataProvider2 {
fn from(warehouse: DataWarehouse) -> Self {
DataProvider2 { data: warehouse }
}
}
impl DataProvider<HelloWorldV1> for DataProvider2 {
fn load(&self, _: DataRequest) -> Result<DataResponse<HelloWorldV1>, DataError> {
Ok(DataResponse {
metadata: DataResponseMetadata::default(),
payload: DataPayload::from_owned(self.data.hello_v1.clone()),
})
}
}
impl DataProvider<HelloAltMarkerV1> for DataProvider2 {
fn load(&self, _: DataRequest) -> Result<DataResponse<HelloAltMarkerV1>, DataError> {
Ok(DataResponse {
metadata: DataResponseMetadata::default(),
payload: DataPayload::from_owned(self.data.hello_alt.clone()),
})
}
}
const DATA: &str = r#"{
"hello_v1": {
"message": "Hello "
},
"hello_alt": {
"message": "Hello Alt"
}
}"#;
fn get_warehouse(data: &'static str) -> DataWarehouse {
let data: HelloCombined = serde_json::from_str(data).expect("Well-formed data");
DataWarehouse {
hello_v1: data.hello_v1,
hello_alt: data.hello_alt,
}
}
fn get_payload_v1<P: DataProvider<HelloWorldV1> + ?Sized>(
provider: &P,
) -> Result<DataPayload<HelloWorldV1>, DataError> {
provider.load(Default::default()).map(|r| r.payload)
}
fn get_payload_alt<P: DataProvider<HelloAltMarkerV1> + ?Sized>(
provider: &P,
) -> Result<DataPayload<HelloAltMarkerV1>, DataError> {
provider.load(Default::default()).map(|r| r.payload)
}
#[test]
fn test_warehouse_owned() {
let warehouse = get_warehouse(DATA);
let hello_data = get_payload_v1(&warehouse).unwrap();
assert!(matches!(
hello_data.get(),
HelloWorld {
message: Cow::Borrowed(_),
}
));
}
#[test]
fn test_warehouse_owned_dyn_generic() {
let warehouse = get_warehouse(DATA);
let hello_data = get_payload_v1(&warehouse as &dyn DataProvider<HelloWorldV1>).unwrap();
assert!(matches!(
hello_data.get(),
HelloWorld {
message: Cow::Borrowed(_),
}
));
}
#[test]
fn test_provider2() {
let warehouse = get_warehouse(DATA);
let provider = DataProvider2::from(warehouse);
let hello_data = get_payload_v1(&provider).unwrap();
assert!(matches!(
hello_data.get(),
HelloWorld {
message: Cow::Borrowed(_),
}
));
}
#[test]
fn test_provider2_dyn_generic() {
let warehouse = get_warehouse(DATA);
let provider = DataProvider2::from(warehouse);
let hello_data = get_payload_v1(&provider as &dyn DataProvider<HelloWorldV1>).unwrap();
assert!(matches!(
hello_data.get(),
HelloWorld {
message: Cow::Borrowed(_),
}
));
}
#[test]
fn test_provider2_dyn_generic_alt() {
let warehouse = get_warehouse(DATA);
let provider = DataProvider2::from(warehouse);
let hello_data = get_payload_alt(&provider as &dyn DataProvider<HelloAltMarkerV1>).unwrap();
assert!(matches!(hello_data.get(), HelloAlt { .. }));
}
fn check_v1_v2<P>(d: &P)
where
P: DataProvider<HelloWorldV1> + DataProvider<HelloAltMarkerV1> + ?Sized,
{
let v1: DataPayload<HelloWorldV1> = d.load(Default::default()).unwrap().payload;
let v2: DataPayload<HelloAltMarkerV1> = d.load(Default::default()).unwrap().payload;
if v1.get().message == v2.get().message {
panic!()
}
}
#[test]
fn test_v1_v2_generic() {
let warehouse = get_warehouse(DATA);
let provider = DataProvider2::from(warehouse);
check_v1_v2(&provider);
}
}