Skip to main content

DataPayload

Struct DataPayload 

Source
pub struct DataPayload<M: DynamicDataMarker>(/* 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 DynamicDataMarker 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 HelloWorldV1 marker:

use icu_provider::hello_world::*;
use icu_provider::prelude::*;
use std::borrow::Cow;

let payload = DataPayload::<HelloWorldV1>::from_owned(HelloWorld {
    message: Cow::Borrowed("Demo"),
});

assert_eq!("Demo", payload.get().message);

Implementations§

Source§

impl<M> DataPayload<M>

Source

pub fn from_owned(data: M::DataStruct) -> 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 = HelloWorld {
    message: Cow::Owned("example".to_owned()),
};

let payload = DataPayload::<HelloWorldV1>::from_owned(local_struct.clone());

assert_eq!(payload.get(), &local_struct);
Source

pub const fn from_static_ref(data: &'static M::DataStruct) -> Self

Construct a DataPayload from a static reference.

This is mainly used by databake.

Source

pub fn with_mut<'a, F>(&'a mut self, f: F)
where F: 'static + for<'b> FnOnce(&'b mut <M::DataStruct as Yokeable<'a>>::Output), M::DataStruct: ZeroFrom<'static, M::DataStruct>,

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::HelloWorldV1;
use icu_provider::prelude::*;

let mut payload = DataPayload::<HelloWorldV1>::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::HelloWorldV1;
use icu_provider::prelude::*;

let mut payload = DataPayload::<HelloWorldV1>::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);
Source

pub fn get<'a>(&'a self) -> &'a <M::DataStruct 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::HelloWorldV1;
use icu_provider::prelude::*;

let payload = DataPayload::<HelloWorldV1>::from_static_str("Demo");

assert_eq!("Demo", payload.get().message);
Source

pub fn get_static( &self, ) -> Option<&'static <M::DataStruct as Yokeable<'static>>::Output>

Borrows the underlying data statically if possible.

This will succeed if DataPayload is constructed with DataPayload::from_static_ref, which is used by baked providers.

Source

pub fn map_project<M2, F>(self, f: F) -> DataPayload<M2>
where M2: DynamicDataMarker, F: for<'a> FnOnce(<M::DataStruct as Yokeable<'a>>::Output, PhantomData<&'a ()>) -> <M2::DataStruct as Yokeable<'a>>::Output, M::DataStruct: ZeroFrom<'static, M::DataStruct>,

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:

§Examples

Map from HelloWorld 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 DataStruct should be the
// target type, and the Cart should correspond to the type being transformed.

struct HelloWorldV1MessageMarker;
impl DynamicDataMarker for HelloWorldV1MessageMarker {
    type DataStruct = Cow<'static, str>;
}

let p1: DataPayload<HelloWorldV1> = DataPayload::from_owned(HelloWorld {
    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());
Source

pub fn map_project_cloned<'this, M2, F>(&'this self, f: F) -> DataPayload<M2>
where M2: DynamicDataMarker, F: for<'a> FnOnce(&'this <M::DataStruct as Yokeable<'a>>::Output, PhantomData<&'a ()>) -> <M2::DataStruct 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<HelloWorldV1> = DataPayload::from_owned(HelloWorld {
    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());
Source

pub fn try_map_project<M2, F, E>(self, f: F) -> Result<DataPayload<M2>, E>
where M2: DynamicDataMarker, F: for<'a> FnOnce(<M::DataStruct as Yokeable<'a>>::Output, PhantomData<&'a ()>) -> Result<<M2::DataStruct as Yokeable<'a>>::Output, E>, M::DataStruct: ZeroFrom<'static, M::DataStruct>,

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<HelloWorldV1> = DataPayload::from_owned(HelloWorld {
    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());
Source

pub fn try_map_project_cloned<'this, M2, F, E>( &'this self, f: F, ) -> Result<DataPayload<M2>, E>
where M2: DynamicDataMarker, F: for<'a> FnOnce(&'this <M::DataStruct as Yokeable<'a>>::Output, PhantomData<&'a ()>) -> Result<<M2::DataStruct as Yokeable<'a>>::Output, 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<HelloWorldV1> = DataPayload::from_owned(HelloWorld {
    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());
Source

pub fn cast<M2>(self) -> DataPayload<M2>
where M2: DynamicDataMarker<DataStruct = M::DataStruct>,

Convert between two DynamicDataMarker types that are compatible with each other with compile-time type checking.

This happens if they both have the same DynamicDataMarker::DataStruct type.

Can be used to erase the marker of a data payload in cases where multiple markers 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 CustomHelloWorldV1;
impl DynamicDataMarker for CustomHelloWorldV1 {
    type DataStruct = HelloWorld<'static>;
}

let hello_world: DataPayload<HelloWorldV1> = todo!();
let custom: DataPayload<CustomHelloWorldV1> = hello_world.cast();
Source

pub fn cast_ref<M2>(&self) -> &DataPayload<M2>
where M2: DynamicDataMarker<DataStruct = M::DataStruct>,

Convert between two DynamicDataMarker types that are compatible with each other with compile-time type checking.

This happens if they both have the same DynamicDataMarker::DataStruct type.

Can be used to erase the marker of a data payload in cases where multiple markers correspond to the same data struct.

Source

pub fn dynamic_cast<M2>(self) -> Result<DataPayload<M2>, DataError>

Convert a DataPayload to one 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

Short-circuit a data request request based on the marker, returning a result from a different data provider:

use core::any::TypeId;
use icu_locale_core::locale;
use icu_provider::hello_world::*;
use icu_provider::prelude::*;
use icu_provider_adapters::empty::EmptyDataProvider;
use std::borrow::Cow;

struct MyForkingProvider<P0, P1> {
    fallback_provider: P0,
    hello_world_provider: P1,
}

impl<M, P0, P1> DataProvider<M> for MyForkingProvider<P0, P1>
where
    M: DataMarker,
    P0: DataProvider<M>,
    P1: DataProvider<HelloWorldV1>,
{
    #[inline]
    fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
        if TypeId::of::<HelloWorldV1>() == TypeId::of::<M>() {
            let response = DataProvider::<HelloWorldV1>::load(
                &self.hello_world_provider,
                req,
            )?;
            Ok(DataResponse {
                metadata: response.metadata,
                payload: response.payload.dynamic_cast()?,
            })
        } else {
            self.fallback_provider.load(req)
        }
    }
}

let provider = MyForkingProvider {
    fallback_provider: EmptyDataProvider::new(),
    hello_world_provider: HelloWorldProvider,
};

let formatter =
    HelloWorldFormatter::try_new_unstable(&provider, locale!("de").into())
        .unwrap();

// This succeeds because the data was loaded from HelloWorldProvider
// rather than the empty fallback provider.
assert_eq!(formatter.format_to_string(), "Hallo Welt");
Source

pub fn dynamic_cast_mut<M2>( &mut self, ) -> Result<&mut DataPayload<M2>, DataError>

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 marker:

use icu_locale_core::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: DataMarker,
    P: DataProvider<M>,
{
    #[inline]
    fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
        let mut res = self.inner.load(req)?;
        let mut cast_result =
            res.payload.dynamic_cast_mut::<HelloWorldV1>();
        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>

Source

pub fn from_yoked_buffer(yoke: Yoke<&'static [u8], Option<Cart>>) -> Self

Converts a yoked byte buffer into a DataPayload<BufferMarker>.

Source

pub fn from_static_buffer(buffer: &'static [u8]) -> Self

Converts a static byte buffer into a DataPayload<BufferMarker>.

Trait Implementations§

Source§

impl<M> Clone for DataPayload<M>
where M: DynamicDataMarker, for<'a> <M::DataStruct as Yokeable<'a>>::Output: Clone,

Cloning a DataPayload is generally a cheap operation. See notes in the Clone impl for Yoke.

§Examples

use icu_provider::hello_world::*;
use icu_provider::prelude::*;

let resp1: DataPayload<HelloWorldV1> = todo!();
let resp2 = resp1.clone();
Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<M> Debug for DataPayload<M>
where M: DynamicDataMarker, for<'a> &'a <M::DataStruct as Yokeable<'a>>::Output: Debug,

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<M> Default for DataPayload<M>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<M> PartialEq for DataPayload<M>
where M: DynamicDataMarker, for<'a> <M::DataStruct as Yokeable<'a>>::Output: PartialEq,

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<M> Eq for DataPayload<M>
where M: DynamicDataMarker, for<'a> <M::DataStruct as Yokeable<'a>>::Output: Eq,

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.