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>
impl<T> Lazy<T>
Sourcepub fn from_bytes(bytes: Vec<u8>) -> Self
pub fn from_bytes(bytes: Vec<u8>) -> Self
Instantiates a Lazy type with bytes. Does not do any (de)serialization.
Sourcepub fn from_inner(inner: T) -> Self
pub fn from_inner(inner: T) -> Self
Instantiates a Lazy type with the inner type. Does not do any (de)serialization.
Sourcepub fn is_deserialized(&self) -> bool
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>where
T: DeserializeOwned,
impl<T> Lazy<T>where
T: DeserializeOwned,
Sourcepub fn try_inner(&mut self) -> Result<&T, Error>
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.
Sourcepub fn try_take(self) -> Result<T, Error>
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
.
Sourcepub fn inner(&mut self) -> &T
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.
Sourcepub fn take(self) -> T
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,
impl<T> Lazy<T>where
T: Serialize,
Sourcepub fn bytes(&mut self) -> &[u8] ⓘ
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.
Sourcepub fn take_bytes(self) -> Vec<u8> ⓘ
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.