pub struct DataPayload<M> where
    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

Moves this DataPayload to the heap (requiring an allocation) and returns it as an erased AnyPayload.

Examples
use icu_provider::hello_world::*;
use icu_provider::prelude::*;
use std::borrow::Cow;
use std::rc::Rc;

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);

Transforms a type-erased DataPayload<AnyMarker> into a concrete DataPayload<M>.

Given a buffer known to be in postcard-0.7 format, attempt to zero-copy deserialize it and record the amount of heap allocations that occurred.

Ideally, this number should be zero.

[dhat]’s profiler must be initialized before using this.

Panics

Panics if the buffer is not in postcard-0.7 format.

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!("{\"message\":\"(und) Hello World\"}".as_bytes(), buffer);

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<_>>()
);

Make a DataPayload<HelloWorldV1Marker> from a static string slice.

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);

Convert a DataPayload that was created via DataPayload::from_owned() back into the concrete type used to construct it.

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);

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);

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 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());

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());

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());

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());

Convert between two DataMarker types that are compatible with each other.

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.

Examples
use icu_locid::locale;
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();

Converts an owned byte buffer into a DataPayload<BufferMarker>.

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

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

Deserialize a DataPayload<BufferMarker> into a DataPayload of a specific concrete type.

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] = b"{\"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");

Trait Implementations

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<HelloWorldV1Marker> = todo!();
let resp2 = resp1.clone();

Returns a copy of the value. Read more

Performs copy-assignment from source. Read more

Formats the value using the given formatter. Read more

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

This method tests for self and other values to be equal, and is used by ==. Read more

This method tests for !=.

The type returned in the event of a conversion error.

Performs the conversion.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

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

The resulting type after obtaining ownership.

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

🔬 This is a nightly-only experimental API. (toowned_clone_into)

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

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.