Struct icu_provider::prelude::DataPayload [−][src]
pub struct DataPayload<'data, M> where
M: DataMarker<'data>, { /* fields omitted */ }
Expand description
A container for data payloads returned from a DataProvider
.
DataPayload
is built on top of the yoke
framework, which allows for cheap, zero-copy
operations on data via the use of self-references. A DataPayload
may be backed by one of
several data stores (“carts”):
- Fully-owned structured data (
DataPayload::from_owned()
) - Partially-owned structured data in an
Rc
(DataPayload::from_partial_owned()
) - A reference-counted byte buffer (
DataPayload::try_from_rc_buffer()
)
The type of the data stored in DataPayload
, and the type of the structured data store
(cart), 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, it is recommended to store the DataPayload
itself, not
the ephemeral reference, since the reference results in a short-lived 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.
Downcasting from a trait object
If you have a DataPayload
<
ErasedDataStructMarker
>
, use DataPayload::downcast()
to transform it into a payload of a concrete type.
Examples
Basic usage, using the CowStrMarker
marker:
use icu_provider::prelude::*;
use icu_provider::marker::CowStrMarker;
use std::borrow::Cow;
let payload = DataPayload::<CowStrMarker>::from_owned(Cow::Borrowed("Demo"));
assert_eq!("Demo", payload.get());
Implementations
impl<'data, M> DataPayload<'data, M> where
M: DataMarker<'data>,
M::Yokeable: ZeroCopyFrom<M::Cart>,
impl<'data, M> DataPayload<'data, M> where
M: DataMarker<'data>,
M::Yokeable: ZeroCopyFrom<M::Cart>,
Convert an Rc
<
Cart
>
into a DataPayload
.
The data need not be fully owned; this constructor creates payloads bounded by 'data
.
Examples
use icu_provider::prelude::*;
use icu_provider::hello_world::*;
use std::borrow::Cow;
use std::rc::Rc;
let local_data = "example".to_string();
let rc_struct = Rc::from(HelloWorldV1 {
message: Cow::Borrowed(&local_data),
});
let payload = DataPayload::<HelloWorldV1Marker>::from_partial_owned(rc_struct.clone());
assert_eq!(payload.get(), &*rc_struct);
Convert a byte buffer into a DataPayload
. A function must be provided to perform the
conversion. This can often be a Serde deserialization operation.
This constructor creates 'static
payloads; borrowing is handled by Yoke
.
Due to compiler bug #84937, call sites
for this function may not compile; if this happens, use
try_from_rc_buffer_badly()
instead.
Convert a byte buffer into a DataPayload
. A function must be provided to perform the
conversion. This can often be a Serde deserialization operation.
This constructor creates 'static
payloads; borrowing is handled by Yoke
.
For a version of this function that takes a FnOnce
instead of a raw function pointer,
see try_from_rc_buffer()
.
Examples
use icu_provider::prelude::*;
use icu_provider::hello_world::*;
use std::rc::Rc;
let json_text = "{\"message\":\"Hello World\"}";
let json_rc_buffer: Rc<[u8]> = json_text.as_bytes().into();
let payload = DataPayload::<HelloWorldV1Marker>::try_from_rc_buffer_badly(
json_rc_buffer.clone(),
|bytes| {
serde_json::from_slice(bytes)
}
)
.expect("JSON is valid");
assert_eq!("Hello World", payload.get().message);
Convert a byte buffer into a DataPayload
. A function must be provided to perform the
conversion. This can often be a Serde deserialization operation.
This function is similar to DataPayload::try_from_rc_buffer
, but it accepts a buffer
that is already yoked to an Rc buffer cart.
Examples
use icu_provider::prelude::*;
use icu_provider::hello_world::*;
use std::rc::Rc;
use icu_provider::yoke::Yoke;
let json_text = "{\"message\":\"Hello World\"}";
let json_rc_buffer: Rc<[u8]> = json_text.as_bytes().into();
let payload = DataPayload::<HelloWorldV1Marker>::try_from_yoked_buffer(
Yoke::attach_to_rc_cart(json_rc_buffer),
(),
|bytes, _, _| {
serde_json::from_slice(bytes)
}
)
.expect("JSON is valid");
assert_eq!("Hello World", payload.get().message);
Convert a fully owned ('static
) data struct into a DataPayload.
This constructor creates 'static
payloads.
Examples
use icu_provider::prelude::*;
use icu_provider::hello_world::*;
use std::borrow::Cow;
let local_struct = HelloWorldV1 {
message: Cow::Owned("example".to_string()),
};
let payload = DataPayload::<HelloWorldV1Marker>::from_owned(local_struct.clone());
assert_eq!(payload.get(), &local_struct);
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::prelude::*;
use icu_provider::marker::CowStrMarker;
let mut payload = DataPayload::<CowStrMarker>::from_static_str("Hello");
payload.with_mut(|s| s.to_mut().push_str(" World"));
assert_eq!("Hello World", payload.get());
To transfer data from the context into the data struct, use the move
keyword:
use icu_provider::prelude::*;
use icu_provider::marker::CowStrMarker;
let mut payload = DataPayload::<CowStrMarker>::from_static_str("Hello");
let suffix = " World".to_string();
payload.with_mut(move |s| s.to_mut().push_str(&suffix));
assert_eq!("Hello World", payload.get());
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::prelude::*;
use icu_provider::marker::CowStrMarker;
let payload = DataPayload::<CowStrMarker>::from_static_str("Demo");
assert_eq!("Demo", payload.get());
pub fn map_project<M2>(
self,
f: for<'a> fn(_: <M::Yokeable as Yokeable<'a>>::Output, _: PhantomData<&'a ()>) -> <M2::Yokeable as Yokeable<'a>>::Output
) -> DataPayload<'data, M2> where
M2: DataMarker<'data, Cart = M::Cart>,
pub fn map_project<M2>(
self,
f: for<'a> fn(_: <M::Yokeable as Yokeable<'a>>::Output, _: PhantomData<&'a ()>) -> <M2::Yokeable as Yokeable<'a>>::Output
) -> DataPayload<'data, M2> where
M2: DataMarker<'data, Cart = M::Cart>,
Maps DataPayload<M>
to DataPayload<M2>
by projecting it with Yoke::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::project()
.
Both M
and M2
have the same DataMarker::Cart
. This means that when using
map_project
, it is usually necessary to define a custom DataMarker
type.
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::map_project_with_capture()
to pass context to the mapping functionDataPayload::map_project_cloned_with_capture()
to do both of these things
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<'data> DataMarker<'data> for HelloWorldV1MessageMarker {
type Yokeable = Cow<'static, str>;
type Cart = HelloWorldV1<'data>;
}
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());
pub fn map_project_cloned<'this, M2>(
&'this self,
f: for<'a> fn(_: &'this <M::Yokeable as Yokeable<'a>>::Output, _: PhantomData<&'a ()>) -> <M2::Yokeable as Yokeable<'a>>::Output
) -> DataPayload<'data, M2> where
M2: DataMarker<'data, Cart = M::Cart>,
pub fn map_project_cloned<'this, M2>(
&'this self,
f: for<'a> fn(_: &'this <M::Yokeable as Yokeable<'a>>::Output, _: PhantomData<&'a ()>) -> <M2::Yokeable as Yokeable<'a>>::Output
) -> DataPayload<'data, M2> where
M2: DataMarker<'data, Cart = M::Cart>,
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
:
#1061: The following example requires Rust 1.57.
// 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());
pub fn map_project_with_capture<M2, T>(
self,
capture: T,
f: for<'a> fn(_: <M::Yokeable as Yokeable<'a>>::Output, capture: T, _: PhantomData<&'a ()>) -> <M2::Yokeable as Yokeable<'a>>::Output
) -> DataPayload<'data, M2> where
M2: DataMarker<'data, Cart = M::Cart>,
pub fn map_project_with_capture<M2, T>(
self,
capture: T,
f: for<'a> fn(_: <M::Yokeable as Yokeable<'a>>::Output, capture: T, _: PhantomData<&'a ()>) -> <M2::Yokeable as Yokeable<'a>>::Output
) -> DataPayload<'data, M2> where
M2: DataMarker<'data, Cart = M::Cart>,
Version of DataPayload::map_project()
that moves self
and takes a capture
parameter to pass additional data to f
.
Examples
Capture a string from the context and append it to the message:
#1061: The following example requires Rust 1.57.
// 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_with_capture(
"Extra",
|mut obj, capture, _| {
obj.message.to_mut().push_str(capture);
obj.message
});
assert_eq!("Hello WorldExtra", p2.get());
Prior to Rust 1.57, pass the capture by value instead of by reference:
// 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_with_capture(
"Extra".to_string(),
|mut obj, capture, _| {
obj.message.to_mut().push_str(&capture);
obj.message
});
assert_eq!("Hello WorldExtra", p2.get());
pub fn map_project_cloned_with_capture<'this, M2, T>(
&'this self,
capture: T,
f: for<'a> fn(_: &'this <M::Yokeable as Yokeable<'a>>::Output, capture: T, _: PhantomData<&'a ()>) -> <M2::Yokeable as Yokeable<'a>>::Output
) -> DataPayload<'data, M2> where
M2: DataMarker<'data, Cart = M::Cart>,
pub fn map_project_cloned_with_capture<'this, M2, T>(
&'this self,
capture: T,
f: for<'a> fn(_: &'this <M::Yokeable as Yokeable<'a>>::Output, capture: T, _: PhantomData<&'a ()>) -> <M2::Yokeable as Yokeable<'a>>::Output
) -> DataPayload<'data, M2> where
M2: DataMarker<'data, Cart = M::Cart>,
Version of DataPayload::map_project()
that borrows self
and takes a capture
parameter to pass additional data to f
.
Examples
Same example as above, but this time, do not move out of p1
:
#1061: The following example requires Rust 1.57.
// 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_with_capture(
"Extra",
|obj, capture, _| {
let mut message = obj.message.clone();
message.to_mut().push_str(capture);
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());
pub fn try_map_project_with_capture<M2, T, E>(
self,
capture: T,
f: for<'a> fn(_: <M::Yokeable as Yokeable<'a>>::Output, capture: T, _: PhantomData<&'a ()>) -> Result<<M2::Yokeable as Yokeable<'a>>::Output, E>
) -> Result<DataPayload<'data, M2>, E> where
M2: DataMarker<'data, Cart = M::Cart>,
pub fn try_map_project_with_capture<M2, T, E>(
self,
capture: T,
f: for<'a> fn(_: <M::Yokeable as Yokeable<'a>>::Output, capture: T, _: PhantomData<&'a ()>) -> Result<<M2::Yokeable as Yokeable<'a>>::Output, E>
) -> Result<DataPayload<'data, M2>, E> where
M2: DataMarker<'data, Cart = M::Cart>,
Version of DataPayload::map_project()
that moves self
, takes a capture
parameter to pass additional data to f
, and bubbles up an error from f
.
Examples
Same example as above, but bubble up an error:
#1061: The following example requires Rust 1.57.
// 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.try_map_project_with_capture(
"Extra",
|mut obj, capture, _| {
if obj.message.is_empty() {
return Err("Example error");
}
obj.message.to_mut().push_str(&capture);
Ok(obj.message)
})?;
assert_eq!("Hello WorldExtra", p2.get());
Prior to Rust 1.57, pass the capture by value instead of by reference:
// 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.try_map_project_with_capture(
"Extra".to_string(),
|mut obj, capture, _| {
if obj.message.is_empty() {
return Err(())
}
obj.message.to_mut().push_str(&capture);
Ok(obj.message)
})?;
assert_eq!("Hello WorldExtra", p2.get());
pub fn try_map_project_cloned_with_capture<'this, M2, T, E>(
&'this self,
capture: T,
f: for<'a> fn(_: &'this <M::Yokeable as Yokeable<'a>>::Output, capture: T, _: PhantomData<&'a ()>) -> Result<<M2::Yokeable as Yokeable<'a>>::Output, E>
) -> Result<DataPayload<'data, M2>, E> where
M2: DataMarker<'data, Cart = M::Cart>,
pub fn try_map_project_cloned_with_capture<'this, M2, T, E>(
&'this self,
capture: T,
f: for<'a> fn(_: &'this <M::Yokeable as Yokeable<'a>>::Output, capture: T, _: PhantomData<&'a ()>) -> Result<<M2::Yokeable as Yokeable<'a>>::Output, E>
) -> Result<DataPayload<'data, M2>, E> where
M2: DataMarker<'data, Cart = M::Cart>,
Version of DataPayload::map_project()
that borrows self
, takes a capture
parameter to pass additional data to f
, and bubbles up an error from f
.
Examples
Same example as above, but bubble up an error:
#1061: The following example requires Rust 1.57.
// 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.try_map_project_cloned_with_capture(
"Extra",
|obj, capture, _| {
if obj.message.is_empty() {
return Err("Example error");
}
let mut message = obj.message.clone();
message.to_mut().push_str(capture);
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());
pub fn downcast<M>(self) -> Result<DataPayload<'static, M>, Error> where
M: DataMarker<'static>,
M::Cart: Sized,
M::Yokeable: ZeroCopyFrom<M::Cart>,
pub fn downcast<M>(self) -> Result<DataPayload<'static, M>, Error> where
M: DataMarker<'static>,
M::Cart: Sized,
M::Yokeable: ZeroCopyFrom<M::Cart>,
Convert this DataPayload
of an ErasedDataStruct
into a DataPayload
of a
concrete type.
Returns an error if the type is not compatible.
This is the main way to consume data returned from an ErasedDataProvider
.
Internally, this method reverses the transformation performed by
UpcastDataPayload::upcast
as implemented
for ErasedDataStructMarker
.
Examples
use icu_provider::prelude::*;
use icu_provider::erased::*;
use icu_provider::hello_world::*;
use icu_locid_macros::langid;
let provider = HelloWorldProvider::new_with_placeholder_data();
let erased_payload: DataPayload<ErasedDataStructMarker> = provider
.load_payload(&DataRequest {
resource_path: ResourcePath {
key: key::HELLO_WORLD_V1,
options: ResourceOptions {
variant: None,
langid: Some(langid!("de")),
}
}
})
.expect("Loading should succeed")
.take_payload()
.expect("Data should be present");
let downcast_payload: DataPayload<HelloWorldV1Marker> = erased_payload
.downcast()
.expect("Types should match");
assert_eq!("Hallo Welt", downcast_payload.get().message);
Make a DataPayload
<
CowStrMarker
>
from a static string slice.
Trait Implementations
impl<'data, M> Clone for DataPayload<'data, M> where
M: DataMarker<'data>,
for<'a> YokeTraitHack<<M::Yokeable as Yokeable<'a>>::Output>: Clone,
impl<'data, M> Clone for DataPayload<'data, M> where
M: DataMarker<'data>,
for<'a> YokeTraitHack<<M::Yokeable as Yokeable<'a>>::Output>: Clone,
impl<'data, M> Debug for DataPayload<'data, M> where
M: DataMarker<'data>,
for<'a> &'a <M::Yokeable as Yokeable<'a>>::Output: Debug,
impl<'data, M> Debug for DataPayload<'data, M> where
M: DataMarker<'data>,
for<'a> &'a <M::Yokeable as Yokeable<'a>>::Output: Debug,
impl<'data, M> PartialEq<DataPayload<'data, M>> for DataPayload<'data, M> where
M: DataMarker<'data>,
for<'a> YokeTraitHack<<M::Yokeable as Yokeable<'a>>::Output>: PartialEq,
impl<'data, M> PartialEq<DataPayload<'data, M>> for DataPayload<'data, M> where
M: DataMarker<'data>,
for<'a> YokeTraitHack<<M::Yokeable as Yokeable<'a>>::Output>: PartialEq,
impl<'data, M> TryFrom<DataResponse<'data, M>> for DataPayload<'data, M> where
M: DataMarker<'data>,
impl<'data, M> TryFrom<DataResponse<'data, M>> for DataPayload<'data, M> where
M: DataMarker<'data>,
impl<'data, M> Eq for DataPayload<'data, M> where
M: DataMarker<'data>,
for<'a> YokeTraitHack<<M::Yokeable as Yokeable<'a>>::Output>: Eq,
Auto Trait Implementations
impl<'data, M> !RefUnwindSafe for DataPayload<'data, M>
impl<'data, M> !Send for DataPayload<'data, M>
impl<'data, M> !Sync for DataPayload<'data, M>
impl<'data, M> Unpin for DataPayload<'data, M> where
<M as DataMarker<'data>>::Yokeable: Unpin,
impl<'data, M> UnwindSafe for DataPayload<'data, M> where
<M as DataMarker<'data>>::Cart: RefUnwindSafe,
<M as DataMarker<'data>>::Yokeable: UnwindSafe,
Blanket Implementations
Mutably borrows from an owned value. Read more