Struct Lazy

Source
pub struct Lazy<T> { /* private fields */ }
Expand description

Lazy is a lazy (de)serialization type. It only serializes its data when the entire struct its contained in is serialized and only deserializes into its inner type when specifically asked to do so.

Consider some information about a client. You might want to send this to the client for storage and retrieve it at a later date. However, the struct contains some data only useful to the server. An example:

struct ClientInfo {
    client_id: String,
    server_data: ServerData
}

You don’t want to have to expose the inner structure of ServerData in your public API. But if you serialize it to e.g. JSON, the structure is easily visible to the client. The client might also need to define the structure if they want to conveniently deserialize it. Instead, wrap ServerData in Lazy:

use lazy_borink::Lazy;

#[derive(Serialize, Deserialize)]
struct ClientInfo {
    client_id: String,
    server_data: Lazy<ServerData>
}

Lazy has custom implementations for serde::Serialize and serde::Deserialize to make this all possible. It is compatible with both JSON and MessagePack and has tests for both.

Example serialization:

// ServerData can be anything, as long as it implements Serialize
let server_data = ServerData { data: "some_data".to_owned() };
let client_info = ClientInfo { client_id: "some_id".to_owned(), server_data: Lazy::from_inner(server_data) };
let client_json = serde_json::to_string(&client_info).unwrap();

assert_eq!(client_json, "{\"client_id\":\"some_id\",\"server_data\":\"gaRkYXRhqXNvbWVfZGF0YQ\"}");

Instantiating a Lazy type is free, it doesn’t yet do any serialization. But if we then serialize and deserialize, it will still have the original bytes. However, Lazy<T> implements the trait UnwrapLazy if T implements UnwrapLazy, allowing us to call UnwrapLazy::unwrap_lazy to get the structured data.

use lazy_borink::UnwrapLazy;

let lazy = Lazy::from_inner(server_data);
assert_eq!(format!("{:?}", lazy), "ServerData { data: \"some_data\" }");
let bytes = rmp_serde::encode::to_vec_named(&lazy).unwrap();
let decoded: Lazy<ServerData> = rmp_serde::decode::from_slice(&bytes).unwrap();
assert_eq!(format!("{:?}", decoded), "Lazy { bytes: [129, 164, 100, 97, 116, 97, 169, 115, 111, 109, 101, 95, 100, 97, 116, 97] }");
let structured = decoded.unwrap_lazy();
assert_eq!(format!("{:?}", structured), "ServerData { data: \"some_data\" }");

You can also automatically derive UnwrapLazy (this is gated behind the “derive” feature, which is enabled by default).

Other convenience methods are also available on the Lazy type, in case you only want the serialized binary data or just the inner structured type. See Lazy::inner, Lazy::take, Lazy::bytes, Lazy::take_bytes.

Note that `Lazy`` assumes a correct implementation of Deserialize and Serialize for the inner structs. If one has to deal with possible incorrect data, there is also Lazy::try_inner, Lazy::try_take and UnwrapLazy::try_unwrap_lazy, which return a Result with rmp_serde::decode::Error. Furthermore, it is always true that only one of bytes or inner ever holds a value, never both or neither.

Implementations§

Source§

impl<T> Lazy<T>

Source

pub fn from_bytes(bytes: Vec<u8>) -> Self

Instantiates a Lazy type with bytes. Does not do any (de)serialization.

Source

pub fn from_inner(inner: T) -> Self

Instantiates a Lazy type with the inner type. Does not do any (de)serialization.

Source

pub fn is_deserialized(&self) -> bool

Returns true if the inner type is already deserialized. If this is the case, Lazy::inner and Lazy::take can be safely called.

Source§

impl<T> Lazy<T>

Source

pub fn try_inner(&mut self) -> Result<&T, Error>

Try to get a reference to the inner value. If it is already in its deserialized state, it will simply return a reference. Otherwise, it will try to deserialize the binary data to type T, discarding the binary data in the process. If it is unable to deserialize, it returns the rmp_serde::decode::Error.

Source

pub fn try_take(self) -> Result<T, Error>

Similar to Lazy::try_inner, but moves the data out of the original Lazy type and returns the owned T.

Source

pub fn inner(&mut self) -> &T

Convenience function that unwraps the result from Lazy::try_inner. Panics if deserialization failed. Can be safely called if already in a deserialized state.

Source

pub fn take(self) -> T

Convenience function that unwraps the result from Lazy::try_take. Panics if deserialization failed. Can be safely called if already in a deserialized state.

Source§

impl<T> Lazy<T>
where T: Serialize,

Source

pub fn bytes(&mut self) -> &[u8]

If in a deserialized state, it serializes the inner data using MessagePack and discards the inner T. It stores the serialized data in itself and returns a reference. It assumes the Serialize implementation is correct and does not fail. If it is not in a deserialized state, it will simply return a reference to the inner bytes.

Source

pub fn take_bytes(self) -> Vec<u8>

Similar to Lazy::take_bytes, but moves the data out of the Lazy and returns the owned bytes.

Trait Implementations§

Source§

impl<T: Clone> Clone for Lazy<T>

Source§

fn clone(&self) -> Lazy<T>

Returns a copy 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<T> Debug for Lazy<T>
where T: Debug,

Source§

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

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

impl<'de, T> Deserialize<'de> for Lazy<T>

Source§

fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl<T> From<T> for Lazy<T>

Source§

fn from(value: T) -> Self

Converts to this type from the input type.
Source§

impl<T: PartialEq> PartialEq for Lazy<T>

Source§

fn eq(&self, other: &Lazy<T>) -> 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<T> Serialize for Lazy<T>
where T: Serialize,

Source§

fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl<T> UnwrapLazy for Lazy<T>

Source§

fn unwrap_lazy(self) -> Self

Source§

fn try_unwrap_lazy(self) -> Result<Self, Error>

Source§

impl<T: Eq> Eq for Lazy<T>

Source§

impl<T> StructuralPartialEq for Lazy<T>

Auto Trait Implementations§

§

impl<T> Freeze for Lazy<T>
where T: Freeze,

§

impl<T> RefUnwindSafe for Lazy<T>
where T: RefUnwindSafe,

§

impl<T> Send for Lazy<T>
where T: Send,

§

impl<T> Sync for Lazy<T>
where T: Sync,

§

impl<T> Unpin for Lazy<T>
where T: Unpin,

§

impl<T> UnwindSafe for Lazy<T>
where T: UnwindSafe,

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<!> for T

Source§

fn from(t: !) -> T

Converts to this type from the input type.
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.
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,