Struct icu_provider::DataPayload
source · pub struct DataPayload<M: DataMarker>(/* private fields */);
Expand description
A container for data payloads returned from a data provider.
DataPayload
is built on top of the yoke
framework, which allows for cheap, zero-copy
operations on data via the use of self-references.
The type of the data stored in DataPayload
is determined by the DataMarker
type parameter.
§Accessing the data
To get a reference to the data inside DataPayload
, use DataPayload::get()
. If you need
to store the data for later use, you need to store the DataPayload
itself, since get
only
returns a reference with an ephemeral lifetime.
§Mutating the data
To modify the data stored in a DataPayload
, use DataPayload::with_mut()
.
§Transforming the data to a different type
To transform a DataPayload
to a different type backed by the same data store (cart), use
DataPayload::map_project()
or one of its sister methods.
§Cargo feature: sync
By default, the payload uses non-concurrent reference counting internally, and hence is neither
Sync
nor Send
; if these traits are required, the sync
Cargo feature can be enabled.
§Examples
Basic usage, using the HelloWorldV1Marker
marker:
use icu_provider::hello_world::*;
use icu_provider::prelude::*;
use std::borrow::Cow;
let payload = DataPayload::<HelloWorldV1Marker>::from_owned(HelloWorldV1 {
message: Cow::Borrowed("Demo"),
});
assert_eq!("Demo", payload.get().message);
Implementations§
source§impl<M> DataPayload<M>where
M: DataMarker,
impl<M> DataPayload<M>where
M: DataMarker,
sourcepub fn from_owned(data: M::Yokeable) -> Self
pub fn from_owned(data: M::Yokeable) -> Self
Convert a fully owned ('static
) data struct into a DataPayload.
This constructor creates 'static
payloads.
§Examples
use icu_provider::hello_world::*;
use icu_provider::prelude::*;
use std::borrow::Cow;
let local_struct = HelloWorldV1 {
message: Cow::Owned("example".to_owned()),
};
let payload =
DataPayload::<HelloWorldV1Marker>::from_owned(local_struct.clone());
assert_eq!(payload.get(), &local_struct);
sourcepub fn try_unwrap_owned(self) -> Result<M::Yokeable, DataError>
pub fn try_unwrap_owned(self) -> Result<M::Yokeable, DataError>
Convert a DataPayload that was created via DataPayload::from_owned()
back into the
concrete type used to construct it.
sourcepub fn with_mut<'a, F>(&'a mut self, f: F)
pub fn with_mut<'a, F>(&'a mut self, f: F)
Mutate the data contained in this DataPayload.
For safety, all mutation operations must take place within a helper function that cannot borrow data from the surrounding context.
§Examples
Basic usage:
use icu_provider::hello_world::HelloWorldV1Marker;
use icu_provider::prelude::*;
let mut payload =
DataPayload::<HelloWorldV1Marker>::from_static_str("Hello");
payload.with_mut(|s| s.message.to_mut().push_str(" World"));
assert_eq!("Hello World", payload.get().message);
To transfer data from the context into the data struct, use the move
keyword:
use icu_provider::hello_world::HelloWorldV1Marker;
use icu_provider::prelude::*;
let mut payload =
DataPayload::<HelloWorldV1Marker>::from_static_str("Hello");
let suffix = " World";
payload.with_mut(move |s| s.message.to_mut().push_str(suffix));
assert_eq!("Hello World", payload.get().message);
sourcepub fn get<'a>(&'a self) -> &'a <M::Yokeable as Yokeable<'a>>::Output
pub fn get<'a>(&'a self) -> &'a <M::Yokeable as Yokeable<'a>>::Output
Borrows the underlying data.
This function should be used like Deref
would normally be used. For more information on
why DataPayload cannot implement Deref
, see the yoke
crate.
§Examples
use icu_provider::hello_world::HelloWorldV1Marker;
use icu_provider::prelude::*;
let payload = DataPayload::<HelloWorldV1Marker>::from_static_str("Demo");
assert_eq!("Demo", payload.get().message);
sourcepub fn map_project<M2, F>(self, f: F) -> DataPayload<M2>
pub fn map_project<M2, F>(self, f: F) -> DataPayload<M2>
Maps DataPayload<M>
to DataPayload<M2>
by projecting it with Yoke::map_project
.
This is accomplished by a function that takes M
’s data type and returns M2
’s data
type. The function takes a second argument which should be ignored. For more details,
see Yoke::map_project()
.
The standard DataPayload::map_project()
function moves self
and cannot capture any
data from its context. Use one of the sister methods if you need these capabilities:
DataPayload::map_project_cloned()
if you don’t have ownership ofself
DataPayload::try_map_project()
to bubble up an errorDataPayload::try_map_project_cloned()
to do both of the above
§Examples
Map from HelloWorldV1
to a Cow<str>
containing just the message:
use icu_provider::hello_world::*;
use icu_provider::prelude::*;
use std::borrow::Cow;
// A custom marker type is required when using `map_project`. The Yokeable should be the
// target type, and the Cart should correspond to the type being transformed.
struct HelloWorldV1MessageMarker;
impl DataMarker for HelloWorldV1MessageMarker {
type Yokeable = Cow<'static, str>;
}
let p1: DataPayload<HelloWorldV1Marker> = DataPayload::from_owned(HelloWorldV1 {
message: Cow::Borrowed("Hello World"),
});
assert_eq!("Hello World", p1.get().message);
let p2: DataPayload<HelloWorldV1MessageMarker> = p1.map_project(|obj, _| obj.message);
// Note: at this point, p1 has been moved.
assert_eq!("Hello World", p2.get());
sourcepub fn map_project_cloned<'this, M2, F>(&'this self, f: F) -> DataPayload<M2>where
M2: DataMarker,
F: for<'a> FnOnce(&'this <M::Yokeable as Yokeable<'a>>::Output, PhantomData<&'a ()>) -> <M2::Yokeable as Yokeable<'a>>::Output,
pub fn map_project_cloned<'this, M2, F>(&'this self, f: F) -> DataPayload<M2>where
M2: DataMarker,
F: for<'a> FnOnce(&'this <M::Yokeable as Yokeable<'a>>::Output, PhantomData<&'a ()>) -> <M2::Yokeable as Yokeable<'a>>::Output,
Version of DataPayload::map_project()
that borrows self
instead of moving self
.
§Examples
Same example as above, but this time, do not move out of p1
:
// Same imports and definitions as above
let p1: DataPayload<HelloWorldV1Marker> =
DataPayload::from_owned(HelloWorldV1 {
message: Cow::Borrowed("Hello World"),
});
assert_eq!("Hello World", p1.get().message);
let p2: DataPayload<HelloWorldV1MessageMarker> =
p1.map_project_cloned(|obj, _| obj.message.clone());
// Note: p1 is still valid.
assert_eq!(p1.get().message, *p2.get());
sourcepub fn try_map_project<M2, F, E>(self, f: F) -> Result<DataPayload<M2>, E>
pub fn try_map_project<M2, F, E>(self, f: F) -> Result<DataPayload<M2>, E>
Version of DataPayload::map_project()
that bubbles up an error from f
.
§Examples
Same example as above, but bubble up an error:
// Same imports and definitions as above
let p1: DataPayload<HelloWorldV1Marker> =
DataPayload::from_owned(HelloWorldV1 {
message: Cow::Borrowed("Hello World"),
});
assert_eq!("Hello World", p1.get().message);
let string_to_append = "Extra";
let p2: DataPayload<HelloWorldV1MessageMarker> =
p1.try_map_project(|mut obj, _| {
if obj.message.is_empty() {
return Err("Example error");
}
obj.message.to_mut().push_str(string_to_append);
Ok(obj.message)
})?;
assert_eq!("Hello WorldExtra", p2.get());
sourcepub fn try_map_project_cloned<'this, M2, F, E>(
&'this self,
f: F
) -> Result<DataPayload<M2>, E>
pub fn try_map_project_cloned<'this, M2, F, E>( &'this self, f: F ) -> Result<DataPayload<M2>, E>
Version of DataPayload::map_project_cloned()
that bubbles up an error from f
.
§Examples
Same example as above, but bubble up an error:
// Same imports and definitions as above
let p1: DataPayload<HelloWorldV1Marker> =
DataPayload::from_owned(HelloWorldV1 {
message: Cow::Borrowed("Hello World"),
});
assert_eq!("Hello World", p1.get().message);
let string_to_append = "Extra";
let p2: DataPayload<HelloWorldV1MessageMarker> = p1
.try_map_project_cloned(|obj, _| {
if obj.message.is_empty() {
return Err("Example error");
}
let mut message = obj.message.clone();
message.to_mut().push_str(string_to_append);
Ok(message)
})?;
// Note: p1 is still valid, but the values no longer equal.
assert_ne!(p1.get().message, *p2.get());
assert_eq!("Hello WorldExtra", p2.get());
sourcepub fn cast<M2>(self) -> DataPayload<M2>where
M2: DataMarker<Yokeable = M::Yokeable>,
pub fn cast<M2>(self) -> DataPayload<M2>where
M2: DataMarker<Yokeable = M::Yokeable>,
Convert between two DataMarker
types that are compatible with each other
with compile-time type checking.
This happens if they both have the same DataMarker::Yokeable
type.
Can be used to erase the key of a data payload in cases where multiple keys correspond to the same data struct.
For runtime dynamic casting, use DataPayload::dynamic_cast_mut()
.
§Examples
use icu_provider::hello_world::*;
use icu_provider::prelude::*;
struct CustomHelloWorldV1Marker;
impl DataMarker for CustomHelloWorldV1Marker {
type Yokeable = HelloWorldV1<'static>;
}
let hello_world: DataPayload<HelloWorldV1Marker> = todo!();
let custom: DataPayload<CustomHelloWorldV1Marker> = hello_world.cast();
sourcepub fn dynamic_cast_mut<M2>(
&mut self
) -> Result<&mut DataPayload<M2>, DataError>where
M2: DataMarker,
pub fn dynamic_cast_mut<M2>(
&mut self
) -> Result<&mut DataPayload<M2>, DataError>where
M2: DataMarker,
Convert a mutable reference of a DataPayload
to another mutable reference
of the same type with runtime type checking.
Primarily useful to convert from a generic to a concrete marker type.
If the M2
type argument does not match the true marker type, a DataError
is returned.
For compile-time static casting, use DataPayload::cast()
.
§Examples
Change the results of a particular request based on key:
use icu_locid::locale;
use icu_provider::hello_world::*;
use icu_provider::prelude::*;
struct MyWrapper<P> {
inner: P,
}
impl<M, P> DataProvider<M> for MyWrapper<P>
where
M: KeyedDataMarker,
P: DataProvider<M>,
{
#[inline]
fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
let mut res = self.inner.load(req)?;
if let Some(ref mut generic_payload) = res.payload {
let mut cast_result =
generic_payload.dynamic_cast_mut::<HelloWorldV1Marker>();
if let Ok(ref mut concrete_payload) = cast_result {
// Add an emoji to the hello world message
concrete_payload.with_mut(|data| {
data.message.to_mut().insert_str(0, "✨ ");
});
}
}
Ok(res)
}
}
let provider = MyWrapper {
inner: HelloWorldProvider,
};
let formatter =
HelloWorldFormatter::try_new_unstable(&provider, &locale!("de").into())
.unwrap();
assert_eq!(formatter.format_to_string(), "✨ Hallo Welt");
source§impl DataPayload<BufferMarker>
impl DataPayload<BufferMarker>
sourcepub fn from_owned_buffer(buffer: Box<[u8]>) -> Self
pub fn from_owned_buffer(buffer: Box<[u8]>) -> Self
Converts an owned byte buffer into a DataPayload<BufferMarker>
.
sourcepub fn from_yoked_buffer(yoke: Yoke<&'static [u8], Option<Cart>>) -> Self
pub fn from_yoked_buffer(yoke: Yoke<&'static [u8], Option<Cart>>) -> Self
Converts a yoked byte buffer into a DataPayload<BufferMarker>
.
sourcepub fn from_static_buffer(buffer: &'static [u8]) -> Self
pub fn from_static_buffer(buffer: &'static [u8]) -> Self
Converts a static byte buffer into a DataPayload<BufferMarker>
.
source§impl<M> DataPayload<M>
impl<M> DataPayload<M>
sourcepub fn wrap_into_any_payload(self) -> AnyPayload
pub fn wrap_into_any_payload(self) -> AnyPayload
Converts this DataPayload into a type-erased AnyPayload
. Unless the payload stores a static
reference, this will move it to the heap.
§Examples
use icu_provider::hello_world::*;
use icu_provider::prelude::*;
use std::borrow::Cow;
let payload: DataPayload<HelloWorldV1Marker> =
DataPayload::from_owned(HelloWorldV1 {
message: Cow::Borrowed("Custom Hello World"),
});
let any_payload = payload.wrap_into_any_payload();
let payload: DataPayload<HelloWorldV1Marker> =
any_payload.downcast().expect("TypeId matches");
assert_eq!("Custom Hello World", payload.get().message);
source§impl DataPayload<AnyMarker>
impl DataPayload<AnyMarker>
sourcepub fn downcast<M>(self) -> Result<DataPayload<M>, DataError>where
M: DataMarker,
for<'a> YokeTraitHack<<M::Yokeable as Yokeable<'a>>::Output>: Clone,
M::Yokeable: ZeroFrom<'static, M::Yokeable> + MaybeSendSync,
pub fn downcast<M>(self) -> Result<DataPayload<M>, DataError>where
M: DataMarker,
for<'a> YokeTraitHack<<M::Yokeable as Yokeable<'a>>::Output>: Clone,
M::Yokeable: ZeroFrom<'static, M::Yokeable> + MaybeSendSync,
Transforms a type-erased DataPayload<AnyMarker>
into a concrete DataPayload<M>
.
source§impl DataPayload<ExportMarker>
impl DataPayload<ExportMarker>
sourcepub fn serialize<S>(&self, serializer: S) -> Result<(), DataError>where
S: Serializer,
S::Ok: 'static,
pub fn serialize<S>(&self, serializer: S) -> Result<(), DataError>where
S: Serializer,
S::Ok: 'static,
Serializes this DataPayload
into a serializer using Serde.
§Examples
use icu_provider::datagen::*;
use icu_provider::dynutil::UpcastDataPayload;
use icu_provider::hello_world::HelloWorldV1Marker;
use icu_provider::prelude::*;
// Create an example DataPayload
let payload: DataPayload<HelloWorldV1Marker> = Default::default();
let export: DataPayload<ExportMarker> = UpcastDataPayload::upcast(payload);
// Serialize the payload to a JSON string
let mut buffer: Vec<u8> = vec![];
export
.serialize(&mut serde_json::Serializer::new(&mut buffer))
.expect("Serialization should succeed");
assert_eq!(r#"{"message":"(und) Hello World"}"#.as_bytes(), buffer);
sourcepub fn tokenize(&self, env: &CrateEnv) -> TokenStream
pub fn tokenize(&self, env: &CrateEnv) -> TokenStream
Serializes this DataPayload
’s value into a TokenStream
using its Bake
implementations.
§Examples
use icu_provider::datagen::*;
use icu_provider::dynutil::UpcastDataPayload;
use icu_provider::hello_world::HelloWorldV1Marker;
use icu_provider::prelude::*;
// Create an example DataPayload
let payload: DataPayload<HelloWorldV1Marker> = Default::default();
let export: DataPayload<ExportMarker> = UpcastDataPayload::upcast(payload);
let env = databake::CrateEnv::default();
let tokens = export.tokenize(&env);
assert_eq!(
quote! {
icu_provider::hello_world::HelloWorldV1 {
message: alloc::borrow::Cow::Borrowed("(und) Hello World"),
}
}
.to_string(),
tokens.to_string()
);
assert_eq!(
env.into_iter().collect::<BTreeSet<_>>(),
["icu_provider", "alloc"]
.into_iter()
.collect::<BTreeSet<_>>()
);
source§impl DataPayload<HelloWorldV1Marker>
impl DataPayload<HelloWorldV1Marker>
sourcepub fn from_static_str(s: &'static str) -> DataPayload<HelloWorldV1Marker>
pub fn from_static_str(s: &'static str) -> DataPayload<HelloWorldV1Marker>
Make a DataPayload
<
HelloWorldV1Marker
>
from a static string slice.
source§impl DataPayload<BufferMarker>
impl DataPayload<BufferMarker>
sourcepub fn into_deserialized<M>(
self,
buffer_format: BufferFormat
) -> Result<DataPayload<M>, DataError>where
M: DataMarker,
for<'de> YokeTraitHack<<M::Yokeable as Yokeable<'de>>::Output>: Deserialize<'de>,
pub fn into_deserialized<M>(
self,
buffer_format: BufferFormat
) -> Result<DataPayload<M>, DataError>where
M: DataMarker,
for<'de> YokeTraitHack<<M::Yokeable as Yokeable<'de>>::Output>: Deserialize<'de>,
Deserialize a DataPayload
<
BufferMarker
>
into a DataPayload
of a
specific concrete type.
This requires enabling the deserialization Cargo feature for the expected format(s):
deserialize_json
deserialize_postcard_1
deserialize_bincode_1
This function takes the buffer format as an argument. When a buffer payload is returned
from a data provider, the buffer format is stored in the DataResponseMetadata
.
§Examples
Requires the deserialize_json
Cargo feature:
use icu_provider::buf::BufferFormat;
use icu_provider::hello_world::*;
use icu_provider::prelude::*;
let buffer: &[u8] = br#"{"message":"Hallo Welt"}"#;
let buffer_payload = DataPayload::from_owned(buffer);
let payload: DataPayload<HelloWorldV1Marker> = buffer_payload
.into_deserialized(BufferFormat::Json)
.expect("Deserialization successful");
assert_eq!(payload.get().message, "Hallo Welt");