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”):

  1. Fully-owned structured data (DataPayload::from_owned())
  2. Partially-owned structured data in an Rc (DataPayload::from_partial_owned())
  3. 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

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

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:

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

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

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

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

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

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

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

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

Examples

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

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

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

Return this boxed trait object as Box<dyn Any>. Read more

Return this trait object reference as &dyn Any. Read more

Performs the conversion.

Performs the conversion.

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)

recently added

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.