Skip to content

Commit

Permalink
Checkpoint: code not compiling. Lifetime issues.
Browse files Browse the repository at this point in the history
  • Loading branch information
sffc committed Dec 29, 2020
1 parent a1a2643 commit 07521bd
Show file tree
Hide file tree
Showing 12 changed files with 279 additions and 305 deletions.
52 changes: 0 additions & 52 deletions components/provider/src/data_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@
// called LICENSE at the top level of the ICU4X source tree
// (online at: https://github.com/unicode-org/icu4x/blob/master/LICENSE ).

use crate::data_receiver::DataReceiver;
use crate::data_receiver::DataReceiverForType;
use crate::resource::ResourceKey;
use crate::resource::ResourcePath;
use icu_locid::LanguageIdentifier;
use std::any::Any;
use std::borrow::Cow;
use std::fmt;
use std::fmt::Debug;
Expand Down Expand Up @@ -74,52 +71,3 @@ where
/// Error with more information.
fn load_payload(&self, req: &DataRequest) -> Result<DataResponse<'d, T>, Error>;
}

/// A type-erased data provider that loads a payload of any type.
pub trait ErasedDataProvider<'d> {
/// Query the provider for data, loading it into a DataReceiver.
///
/// Returns Ok if the request successfully loaded data. If data failed to load, returns an
/// Error with more information.
fn load_to_receiver(
&self,
req: &DataRequest,
receiver: &mut dyn DataReceiver<'d>,
) -> Result<DataResponseMetadata, Error>;
}

/// Helper macro to implement ErasedDataProvider on an object implementing DataProvider for a
/// single type. Calls to `self.load_to_receiver` delegate to `self.load_payload`.
#[macro_export]
macro_rules! impl_erased {
($type:ty, $lifetime:tt) => {
impl<$lifetime> $crate::prelude::ErasedDataProvider<$lifetime> for $type {
fn load_to_receiver(
&self,
req: &$crate::prelude::DataRequest,
receiver: &mut dyn $crate::prelude::DataReceiver<$lifetime>,
) -> Result<$crate::prelude::DataResponseMetadata, $crate::prelude::DataError> {
println!("{:?}", req);
let result = self.load_payload(req)?;
println!("{:?}", result);
receiver.receive_optional_cow(result.payload)?;
Ok(result.metadata)
}
}
};
}

/// Convenience implementation of DataProvider<T> given an ErasedDataProvider trait object.
impl<'a, 'd, T> DataProvider<'d, T> for dyn ErasedDataProvider<'d> + 'a
where
T: serde::Deserialize<'d> + serde::Serialize + Any + Clone + Debug,
{
fn load_payload(&self, req: &DataRequest) -> Result<DataResponse<'d, T>, Error> {
let mut receiver = DataReceiverForType::<T>::new();
let metadata = self.load_to_receiver(req, &mut receiver)?;
Ok(DataResponse {
metadata,
payload: receiver.payload,
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// (online at: https://github.com/unicode-org/icu4x/blob/master/LICENSE ).

use crate::error::Error;
use crate::prelude::*;
use std::any::Any;
use std::any::TypeId;
use std::borrow::Borrow;
Expand All @@ -12,6 +13,9 @@ use std::fmt::Debug;
#[cfg(feature = "invariant")]
use std::default::Default;

/// Re-export erased_serde for the impl_erased! macro
pub use erased_serde;

/// An object capable of accepting data from a variety of forms.
/// Lifetimes:
/// - 'd = lifetime of borrowed data (Cow::Borrowed)
Expand Down Expand Up @@ -102,9 +106,7 @@ pub trait DataReceiver<'d> {
///
/// assert_eq!(receiver.payload, Some(Cow::Owned("".to_string())));
/// ```
fn receive_default(&mut self) -> Result<(), Error> {
Err(Error::NeedsDefault)
}
fn receive_default(&mut self) -> Result<(), Error>;

/// Borrows the value in this DataReceiver as a Serialize trait object.
fn as_serialize(&self) -> Option<&dyn erased_serde::Serialize>;
Expand Down Expand Up @@ -186,7 +188,7 @@ where

impl<'d, T> DataReceiverForType<'d, T>
where
T: serde::Deserialize<'d> + serde::Serialize + Any + Clone + Debug,
T: serde::de::DeserializeOwned + serde::Serialize + Clone + Debug + Any + Default,
{
/// Creates a new, empty DataReceiver, returning it as a boxed trait object.
pub fn new_boxed() -> Box<dyn DataReceiver<'d> + 'd> {
Expand All @@ -197,7 +199,7 @@ where

impl<'d, T> DataReceiver<'d> for DataReceiverForType<'d, T>
where
T: serde::Deserialize<'d> + serde::Serialize + Any + Clone + Debug,
T: serde::de::DeserializeOwned + serde::Serialize + Clone + Debug + Any + Default,
{
fn receive_deserializer(
&mut self,
Expand Down Expand Up @@ -240,6 +242,11 @@ where
Ok(())
}

fn receive_default(&mut self) -> Result<(), Error> {
self.payload = Some(Cow::Owned(T::default()));
Ok(())
}

fn as_serialize(&self) -> Option<&dyn erased_serde::Serialize> {
match &self.payload {
Some(cow) => {
Expand Down Expand Up @@ -301,7 +308,76 @@ impl<'d> DataReceiver<'d> for DataReceiverThrowAway {
Ok(())
}

fn receive_default(&mut self) -> Result<(), Error> {
self.flag = true;
Ok(())
}

fn as_serialize(&self) -> Option<&dyn erased_serde::Serialize> {
None
}
}

/// A type-erased data provider that loads a payload of any type.
pub trait ErasedDataProvider<'d> {
/// Query the provider for data, loading it into a DataReceiver.
///
/// Returns Ok if the request successfully loaded data. If data failed to load, returns an
/// Error with more information.
fn load_to_receiver(
&self,
req: &DataRequest,
receiver: &mut dyn DataReceiver<'d>,
) -> Result<DataResponseMetadata, Error>;

/// Query the provider for data, returning it as a boxed Serialize trait object.
///
/// Returns Ok if the request successfully loaded data. If data failed to load, returns an
/// Error with more information.
fn load_as_serialize(
&self,
req: &DataRequest,
) -> Result<Box<dyn erased_serde::Serialize>, Error>;
}

/// Helper macro to implement ErasedDataProvider on an object implementing DataProvider for a
/// single type. Calls to `self.load_to_receiver` delegate to `self.load_payload`.
#[macro_export]
macro_rules! impl_erased {
($type:ty, $lifetime:tt) => {
impl<$lifetime> $crate::prelude::ErasedDataProvider<$lifetime> for $type {
fn load_to_receiver(
&self,
req: &$crate::prelude::DataRequest,
receiver: &mut dyn $crate::prelude::DataReceiver<$lifetime>,
) -> Result<$crate::prelude::DataResponseMetadata, $crate::prelude::DataError> {
let result = self.load_payload(req)?;
receiver.receive_optional_cow(result.payload)?;
Ok(result.metadata)
}

fn load_as_serialize(
&self,
req: &$crate::prelude::DataRequest,
) -> Result<Box<dyn $crate::erased::erased_serde::Serialize>, $crate::prelude::DataError> {
let result = self.load_payload(req)?;
Ok(Box::new(result.payload.expect("Load was successful").into_owned()))
}
}
};
}

/// Convenience implementation of DataProvider<T> given an ErasedDataProvider trait object.
impl<'a, 'd, T> DataProvider<'d, T> for dyn ErasedDataProvider<'d> + 'a
where
T: serde::de::DeserializeOwned + serde::Serialize + Clone + Debug + Any + Default,
{
fn load_payload(&self, req: &DataRequest) -> Result<DataResponse<'d, T>, Error> {
let mut receiver = DataReceiverForType::<T>::new();
let metadata = self.load_to_receiver(req, &mut receiver)?;
Ok(DataResponse {
metadata,
payload: receiver.payload,
})
}
}
12 changes: 6 additions & 6 deletions components/provider/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ pub enum Error {
/// missing from the request.
NeedsLanguageIdentifier(DataRequest),

/// Default invariant data was requested, but Default is not implemented for the type.
NeedsDefault,
/// The operation cannot be completed without more type information. For example, data
/// cannot be deserialized without the concrete type.
NeedsTypeInfo(DataRequest),

/// The TypeID of the payload does not match the expected TypeID.
MismatchedType {
Expand Down Expand Up @@ -86,10 +87,9 @@ impl fmt::Display for Error {
"Requested key needs language identifier in request: {}",
request
),
Self::NeedsDefault => write!(
f,
"Invariant data requested, but type does not implement Default"
),
Self::NeedsTypeInfo(request) => {
write!(f, "Complete type information is required: {}", request)
}
Self::MismatchedType { actual, generic } => {
write!(f, "Mismatched type: payload is {:?}", actual)?;
if let Some(type_id) = generic {
Expand Down
43 changes: 19 additions & 24 deletions components/provider/src/invariant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// called LICENSE at the top level of the ICU4X source tree
// (online at: https://github.com/unicode-org/icu4x/blob/master/LICENSE ).

use crate::data_receiver::DataReceiverThrowAway;
use crate::erased::DataReceiverThrowAway;
use crate::error::Error;
use crate::iter::IterableDataProvider;
use crate::prelude::*;
Expand All @@ -22,7 +22,6 @@ use std::fmt::Debug;
/// use icu_provider::prelude::*;
/// use icu_provider::structs;
/// use icu_provider::InvariantDataProvider;
/// use icu_locid_macros::langid;
///
/// let provider = InvariantDataProvider;
/// let expected_entries = vec![ResourceOptions::default()];
Expand All @@ -36,7 +35,7 @@ pub struct InvariantDataProvider;

impl<'d, T> DataProvider<'d, T> for InvariantDataProvider
where
T: serde::Deserialize<'d> + serde::Serialize + Clone + Debug + Default + 'd,
T: Clone + Debug + Default + 'd,
{
fn load_payload(&self, _req: &DataRequest) -> Result<DataResponse<'d, T>, Error> {
Ok(DataResponse {
Expand All @@ -49,51 +48,47 @@ where
impl<'d> ErasedDataProvider<'d> for InvariantDataProvider {
fn load_to_receiver(
&self,
req: &DataRequest,
_req: &DataRequest,
receiver: &mut dyn DataReceiver<'d>,
) -> Result<DataResponseMetadata, Error> {
structs::get_invariant(&req.resource_path.key, receiver)?;
receiver.receive_default()?;
Ok(DataResponseMetadata::default())
}

/// Method always fails: a concrete type is required to return a Serialize trait object
fn load_as_serialize(
&self,
req: &DataRequest,
) -> Result<Box<dyn erased_serde::Serialize>, Error> {
Err(Error::NeedsTypeInfo(req.clone()))
}
}

impl IterableDataProvider<'_> for InvariantDataProvider {
fn supported_options_for_key(
&self,
resc_key: &ResourceKey,
_resc_key: &ResourceKey,
) -> Result<Box<dyn Iterator<Item = ResourceOptions>>, Error> {
let mut receiver = DataReceiverThrowAway::default();
structs::get_invariant(resc_key, &mut receiver)?;
let list: Vec<ResourceOptions> = vec![ResourceOptions::default()];
Ok(Box::new(list.into_iter()))
}
}

#[test]
fn test_v2() {
fn test_receiver() {
let provider = InvariantDataProvider;
let mut receiver =
DataReceiverForType::<structs::plurals::PluralRuleStringsV1> { payload: None };
let mut receiver = DataReceiverForType::<structs::icu4x::HelloV1>::new();
provider
.load_to_receiver(
&DataRequest {
resource_path: ResourcePath {
key: structs::plurals::key::CARDINAL_V1,
options: Default::default(),
},
},
&DataRequest::from(structs::icu4x::key::HELLO_V1),
&mut receiver,
)
.unwrap();
let plurals_data: &structs::plurals::PluralRuleStringsV1 = &(receiver.payload.unwrap());
let plurals_data: &structs::icu4x::HelloV1 = &receiver.payload.unwrap();
assert_eq!(
plurals_data,
&structs::plurals::PluralRuleStringsV1 {
zero: None,
one: None,
two: None,
few: None,
many: None,
&structs::icu4x::HelloV1 {
hello: Cow::Borrowed("(und) Hello World")
}
);
}
9 changes: 3 additions & 6 deletions components/provider/src/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ pub trait IterableDataProvider<'d> {

/// Super-trait combining DataProvider and IterableDataProvider, auto-implemented
/// for all types implementing both of those traits.
pub trait IterableTypedDataProvider<'d, T>:
IterableDataProvider<'d> + DataProvider<'d, T>
pub trait IterableTypedDataProvider<'d, T>: IterableDataProvider<'d> + DataProvider<'d, T>
where
T: Clone + Debug + 'd,
{
Expand Down Expand Up @@ -112,16 +111,14 @@ pub trait DataExporter {
if !self.include_resource_options(&resc_options) {
continue;
}
let mut receiver = structs::get_receiver(resc_key)?;
let req = DataRequest {
resource_path: ResourcePath {
key: *resc_key,
options: resc_options,
},
};
provider.load_to_receiver(&req, receiver.as_mut())?;
let payload = receiver.as_serialize();
self.put_payload(&req, &payload)?;
let serialize = provider.load_as_serialize(&req)?;
self.put_payload(&req, &serialize)?;
}
Ok(())
}
Expand Down
14 changes: 7 additions & 7 deletions components/provider/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@
//! filesystem. It can also write out that filesystem structure. More efficient than CldrJsonDataProvider.
//!
//! This crate also contains some concrete implementations for testing purposes:
//!
//!
//! - [`InvariantDataProvider`] returns fixed data that does not vary by locale.
//! - [`StructProvider`] wraps a particular instance of a struct and returns it.
//!
//! ## Additional Traits
//!
//!
//! ### `IterableDataProvider`
//!
//! Data providers can implement [`IterableDataProvider`], allowing iteration over all [`ResourceOptions`]
Expand Down Expand Up @@ -83,10 +83,10 @@
//! [`IterableDataProvider`]: iter::IterableDataProvider
mod data_provider;
mod data_receiver;
mod error;
#[macro_use]
pub mod resource;
pub mod erased;
pub mod iter;
pub mod struct_provider;
pub mod structs;
Expand All @@ -103,10 +103,10 @@ pub mod prelude {
pub use crate::data_provider::DataRequest;
pub use crate::data_provider::DataResponse;
pub use crate::data_provider::DataResponseMetadata;
pub use crate::data_provider::ErasedDataProvider;
pub use crate::data_receiver::DataReceiver;
pub use crate::data_receiver::DataReceiverForType;
pub use crate::data_receiver::DataReceiverThrowAway;
pub use crate::erased::DataReceiver;
pub use crate::erased::DataReceiverForType;
pub use crate::erased::DataReceiverThrowAway;
pub use crate::erased::ErasedDataProvider;
pub use crate::error::Error as DataError;
pub use crate::iter::IterableDataProvider;
pub use crate::iter::KeyedDataProvider;
Expand Down
Loading

0 comments on commit 07521bd

Please sign in to comment.