Struct yoke::Yoke [−][src]
pub struct Yoke<Y: for<'a> Yokeable<'a>, C> { /* fields omitted */ }
Expand description
A Cow-like borrowed object “yoked” to its backing data.
This allows things like zero copy deserialized data to carry around shared references to their backing buffer.
Y
(the Yokeable
) is the object containing the references,
and will typically be of the form Foo<'static>
. The 'static
is
not the actual lifetime of the data, rather it is a convenient way to erase
the lifetime and make it dynamic.
C
is the “cart”, which Y
may contain references to.
The primary constructor for Yoke
is Yoke::attach_to_cart()
. Several variants of that
constructor are provided to serve numerous types of call sites and Yoke
signatures.
Example
For example, we can use this to store zero-copy deserialized data in a cache:
fn load_object(filename: &str) -> Yoke<Cow<'static, str>, Rc<[u8]>> { let rc: Rc<[u8]> = load_from_cache(filename); Yoke::<Cow<'static, str>, Rc<[u8]>>::attach_to_cart_badly(rc, |data: &[u8]| { // essentially forcing a #[serde(borrow)] Cow::Borrowed(bincode::deserialize(data).unwrap()) }) } let yoke = load_object("filename.bincode"); assert_eq!(&**yoke.get(), "hello"); assert!(matches!(yoke.get(), &Cow::Borrowed(_)));
Implementations
Construct a Yoke
by yokeing an object to a cart in a closure.
See also Yoke::try_attach_to_cart()
to return a Result
from the closure.
Due to compiler bug #84937, call sites
for this function may not compile; if this happens, use
Yoke::attach_to_cart_badly()
instead.
Construct a Yoke
by yokeing an object to a cart. If an error occurs in the
deserializer function, the error is passed up to the caller.
Due to compiler bug #84937, call sites
for this function may not compile; if this happens, use
Yoke::try_attach_to_cart_badly()
instead.
Construct a Yoke
by yokeing an object to a cart in a closure.
For a version of this function that takes a FnOnce
instead of a raw function pointer,
see Yoke::attach_to_cart()
.
Example
For example, we can use this to store zero-copy deserialized data in a cache:
fn load_object(filename: &str) -> Yoke<Cow<'static, str>, Rc<[u8]>> { let rc: Rc<[u8]> = load_from_cache(filename); Yoke::<Cow<'static, str>, Rc<[u8]>>::attach_to_cart_badly(rc, |data: &[u8]| { // essentially forcing a #[serde(borrow)] Cow::Borrowed(bincode::deserialize(data).unwrap()) }) } let yoke: Yoke<Cow<str>, _> = load_object("filename.bincode"); assert_eq!(&**yoke.get(), "hello"); assert!(matches!(yoke.get(), &Cow::Borrowed(_)));
Construct a Yoke
by yokeing an object to a cart. If an error occurs in the
deserializer function, the error is passed up to the caller.
For a version of this function that takes a FnOnce
instead of a raw function pointer,
see Yoke::try_attach_to_cart()
.
Examples
let rc = Rc::new([0xb, 0xa, 0xd]); let yoke_result: Result<Yoke<Cow<str>, Rc<[u8]>>, _> = Yoke::try_attach_to_cart_badly(rc, |data: &[u8]| { bincode::deserialize(data) }); assert!(matches!(yoke_result, Err(_)));
Obtain a valid reference to the yokeable data
This essentially transforms the lifetime of the internal yokeable data to
be valid.
For example, if you’re working with a Yoke<Cow<'static, T>, C>
, this
will return an &'a Cow<'a, T>
Example
// load_object() defined in the example at the top of this page let yoke: Yoke<Cow<str>, _> = load_object("filename.bincode"); assert_eq!(yoke.get(), "hello");
Get a reference to the backing cart.
This can be useful when building caches, etc. However, if you plan to store the cart
separately from the yoke, read the note of caution below in Yoke::into_backing_cart
.
Get the backing cart by value, dropping the yokeable object.
Caution: Calling this method could cause information saved in the yokeable object but not the cart to be lost. Use this method only if the yokeable object cannot contain its own information.
Example
Good example: the yokeable object is only a reference, so no information can be lost.
use yoke::Yoke; let local_data = "foo".to_string(); let yoke = Yoke::< &'static str, Box<String> >::attach_to_box_cart(Box::new(local_data)); assert_eq!(*yoke.get(), "foo"); // Get back the cart let cart = yoke.into_backing_cart(); assert_eq!(&*cart, "foo");
Bad example: information specified in .with_mut()
is lost.
use yoke::Yoke; use std::borrow::Cow; let local_data = "foo".to_string(); let mut yoke = Yoke::< Cow<'static, str>, Box<String> >::attach_to_box_cart(Box::new(local_data)); assert_eq!(yoke.get(), "foo"); // Override data in the cart yoke.with_mut(|cow| { let mut_str = cow.to_mut(); mut_str.clear(); mut_str.push_str("bar"); }); assert_eq!(yoke.get(), "bar"); // Get back the cart let cart = yoke.into_backing_cart(); assert_eq!(&*cart, "foo"); // WHOOPS!
Mutate the stored Yokeable
data.
See Yokeable::transform_mut()
for why this operation is safe.
Example
This can be used to partially mutate the stored data, provided no new borrowed data is introduced.
// also implements Yokeable struct Bar<'a> { numbers: Cow<'a, [u8]>, string: Cow<'a, str>, owned: Vec<u8>, } // `load_object()` deserializes an object from a file let mut bar: Yoke<Bar, _> = load_object("filename.bincode"); assert_eq!(bar.get().string, "hello"); assert!(matches!(bar.get().string, Cow::Borrowed(_))); assert_eq!(&*bar.get().numbers, &[0x68, 0x65, 0x6c, 0x6c, 0x6f]); assert!(matches!(bar.get().numbers, Cow::Borrowed(_))); assert_eq!(&*bar.get().owned, &[]); bar.with_mut(|bar| { bar.string.to_mut().push_str(" world"); bar.owned.extend_from_slice(&[1, 4, 1, 5, 9]); }); assert_eq!(bar.get().string, "hello world"); assert!(matches!(bar.get().string, Cow::Owned(_))); assert_eq!(&*bar.get().owned, &[1, 4, 1, 5, 9]); // Unchanged and still Cow::Borrowed assert_eq!(&*bar.get().numbers, &[0x68, 0x65, 0x6c, 0x6c, 0x6f]); assert!(matches!(bar.get().numbers, Cow::Borrowed(_)));
Construct a new Yoke
from static data. There will be no
references to cart
here since Yokeable
s are 'static
,
this is good for e.g. constructing fully owned
Yoke
s with no internal borrowing.
This is similar to Yoke::new_owned()
but it does not allow you to
mix the Yoke
with borrowed data. This is primarily useful
for using Yoke
in generic scenarios.
Example
let owned: Cow<str> = "hello".to_owned().into(); // this yoke can be intermingled with actually-borrowed Yokes let yoke: Yoke<Cow<str>, ()> = Yoke::new_always_owned(owned); assert_eq!(yoke.get(), "hello");
Construct a new Yoke
from static data. There will be no
references to cart
here since Yokeable
s are 'static
,
this is good for e.g. constructing fully owned
Yoke
s with no internal borrowing.
This can be paired with Yoke::attach_to_option_cart()
to mix owned
and borrowed data.
If you do not wish to pair this with borrowed data, Yoke::new_always_owned()
can
be used to get a Yoke
API on always-owned data.
Example
let owned: Cow<str> = "hello".to_owned().into(); // this yoke can be intermingled with actually-borrowed Yokes let yoke: Yoke<Cow<str>, Option<Rc<[u8]>>> = Yoke::new_owned(owned); assert_eq!(yoke.get(), "hello");
Similar to Yoke::attach_to_cart()
, except it constructs a Yoke<Y, Option<C>>
instead, where the cart is Some(..)
.
This allows mixing Yoke
s constructed from owned and borrowed data, when
paired with Yoke::new_owned()
.
This method is currently unusable due to a compiler bug,
use Yoke::attach_to_option_cart_badly()
instead
Temporary version of Yoke::attach_to_option_cart()
that doesn’t hit https://github.com/rust-lang/rust/issues/84937
See its docs for more details
Allows one to “project” a yoke to perform a transformation on the data, potentially looking at a subfield, and producing a new yoke. This will move cart, and the provided transformation is only allowed to use data known to be borrowed from the cart.
This takes an additional PhantomData<&()>
parameter as a workaround to the issue
described in #86702. This parameter
should just be ignored in the function.
Furthermore,
compiler bug #84937 prevents
this from taking a capturing closure, however Yoke::project_with_capture()
can be used for the same use cases.
This can be used, for example, to transform data from one format to another:
fn slice(y: Yoke<&'static str, Rc<[u8]>>) -> Yoke<&'static [u8], Rc<[u8]>> { y.project(move |yk, _| yk.as_bytes()) }
This can also be used to create a yoke for a subfield
// also safely implements Yokeable<'a> struct Bar<'a> { string_1: &'a str, string_2: &'a str, } fn project_string_1(bar: Yoke<Bar<'static>, Rc<[u8]>>) -> Yoke<&'static str, Rc<[u8]>> { bar.project(|bar, _| bar.string_1) }
pub fn project_cloned<'this, P>(
&'this self,
f: for<'a> fn(_: &'this <Y as Yokeable<'a>>::Output, _: PhantomData<&'a ()>) -> <P as Yokeable<'a>>::Output
) -> Yoke<P, C> where
P: for<'a> Yokeable<'a>,
C: CloneableCart,
pub fn project_cloned<'this, P>(
&'this self,
f: for<'a> fn(_: &'this <Y as Yokeable<'a>>::Output, _: PhantomData<&'a ()>) -> <P as Yokeable<'a>>::Output
) -> Yoke<P, C> where
P: for<'a> Yokeable<'a>,
C: CloneableCart,
This is similar to Yoke::project
, however it does not move
Self
and instead clones the cart (only if the cart is a CloneableCart
)
This is a bit more efficient than cloning the Yoke
and then calling Yoke::project
because then it will not clone fields that are going to be discarded.
pub fn project_with_capture<P, T>(
self,
capture: T,
f: for<'a> fn(_: <Y as Yokeable<'a>>::Output, capture: T, _: PhantomData<&'a ()>) -> <P as Yokeable<'a>>::Output
) -> Yoke<P, C> where
P: for<'a> Yokeable<'a>,
pub fn project_with_capture<P, T>(
self,
capture: T,
f: for<'a> fn(_: <Y as Yokeable<'a>>::Output, capture: T, _: PhantomData<&'a ()>) -> <P as Yokeable<'a>>::Output
) -> Yoke<P, C> where
P: for<'a> Yokeable<'a>,
This is similar to Yoke::project
, however it works around it not being able to
use FnOnce
by using an explicit capture input, until compiler bug #84937
is fixed.
See the docs of Yoke::project
for how this works.
pub fn project_cloned_with_capture<'this, P, T>(
&'this self,
capture: T,
f: for<'a> fn(_: &'this <Y as Yokeable<'a>>::Output, capture: T, _: PhantomData<&'a ()>) -> <P as Yokeable<'a>>::Output
) -> Yoke<P, C> where
P: for<'a> Yokeable<'a>,
C: CloneableCart,
pub fn project_cloned_with_capture<'this, P, T>(
&'this self,
capture: T,
f: for<'a> fn(_: &'this <Y as Yokeable<'a>>::Output, capture: T, _: PhantomData<&'a ()>) -> <P as Yokeable<'a>>::Output
) -> Yoke<P, C> where
P: for<'a> Yokeable<'a>,
C: CloneableCart,
This is similar to Yoke::project_cloned
, however it works around it not being able to
use FnOnce
by using an explicit capture input, until compiler bug #84937
is fixed.
See the docs of Yoke::project_cloned
for how this works.
Construct a Yoke
<Y, &C>
from a borrowed cart by zero-copy cloning the cart to Y
and
then yokeing that object to the cart.
This results in a Yoke
bound to the lifetime of the reference to the borrowed cart.
The type Y
must implement ZeroCopyFrom
<C>
.
Example
use yoke::Yoke; use std::borrow::Cow; let yoke = Yoke::< Cow<'static, str>, &str >::attach_to_borrowed_cart("demo"); assert_eq!("demo", yoke.get());
Construct a Yoke
<Y, Box<C>>
from a boxed cart by zero-copy cloning the cart to Y
and
then yokeing that object to the cart.
This results in a Yoke
bound to the lifetime of data within the cart. If the cart is
fully owned, then the resulting Yoke
will be 'static
.
The type Y
must implement ZeroCopyFrom
<C>
.
Example
use yoke::Yoke; use std::borrow::Cow; let box_cart = Box::new("demo".to_string()); let yoke = Yoke::< Cow<'static, str>, Box<String> >::attach_to_box_cart(box_cart); assert_eq!("demo", yoke.get());
Construct a Yoke
<Y, Rc<C>>
from a reference-counted cart by zero-copy cloning the
cart to Y
and then yokeing that object to the cart.
This results in a Yoke
bound to the lifetime of data within the cart. If the cart is
fully owned, then the resulting Yoke
will be 'static
.
The type Y
must implement ZeroCopyFrom
<C>
.
Example
use yoke::Yoke; use std::borrow::Cow; use std::rc::Rc; let rc_cart = Rc::from("demo".to_string()); let yoke = Yoke::< Cow<'static, str>, Rc<String> >::attach_to_rc_cart(rc_cart); assert_eq!("demo", yoke.get());
Trait Implementations
Clone requires that the cart derefs to the same address after it is cloned. This works for Rc, Arc, and &’a T.
For all other cart types, clone .backing_cart()
and re-use attach_to_cart()
.