yoke

Struct Yoke

Source
pub struct Yoke<Y: for<'a> Yokeable<'a>, C> { /* private fields */ }
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, by “erasing” their static lifetime and turning it into a dynamically managed one.

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 mark the erased lifetime and make it dynamic.

C is the “cart”, which Y may contain references to. After the yoke is constructed, the cart serves little purpose except to guarantee that Y’s references remain valid for as long as the yoke remains in memory (by calling the destructor at the appropriate moment).

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.

The key behind this type is Yoke::get(), where calling .get() on a type like Yoke<Cow<'static, str>, _> will get you a short-lived &'a Cow<'a, str>, restricted to the lifetime of the borrow used during .get(). This is entirely safe since the Cow borrows from the cart type C, which cannot be interfered with as long as the Yoke is borrowed by .get (). .get() protects access by essentially reifying the erased lifetime to a safe local one when necessary.

Furthermore, there are various .map_project() methods that allow turning a Yoke into another Yoke containing a different type that may contain elements of the original yoked value. See the Yoke::map_project() docs for more details.

In general, C is a concrete type, but it is also possible for it to be a trait object.

§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(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§

Source§

impl<Y: for<'a> Yokeable<'a>, C: StableDeref> Yoke<Y, C>
where <C as Deref>::Target: 'static,

Source

pub fn attach_to_cart<F>(cart: C, f: F) -> Self
where F: for<'de> FnOnce(&'de <C as Deref>::Target) -> <Y as Yokeable<'de>>::Output, <C as Deref>::Target: 'static,

Construct a Yoke by yokeing an object to a cart in a closure.

The closure can read and write data outside of its scope, but data it returns may borrow only from the argument passed to the closure.

See also Yoke::try_attach_to_cart() to return a Result from the closure.

Call sites for this function may not compile pre-1.61; if this still happens, use Yoke::attach_to_cart_badly() and file a bug.

§Examples

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

Write the number of consumed bytes to a local variable:


fn load_object(
    filename: &str,
) -> (Yoke<Cow<'static, str>, Rc<[u8]>>, usize) {
    let rc: Rc<[u8]> = load_from_cache(filename);
    let mut bytes_remaining = 0;
    let bytes_remaining = &mut bytes_remaining;
    let yoke = Yoke::<Cow<'static, str>, Rc<[u8]>>::attach_to_cart(
        rc,
        |data: &[u8]| {
            let mut d = postcard::Deserializer::from_bytes(data);
            let output = serde::Deserialize::deserialize(&mut d);
            *bytes_remaining = d.finalize().unwrap().len();
            Cow::Borrowed(output.unwrap())
        },
    );
    (yoke, *bytes_remaining)
}

let (yoke, bytes_remaining) = load_object("filename.postcard");
assert_eq!(&**yoke.get(), "hello");
assert!(matches!(yoke.get(), &Cow::Borrowed(_)));
assert_eq!(bytes_remaining, 3);
Source

pub fn try_attach_to_cart<E, F>(cart: C, f: F) -> Result<Self, E>
where F: for<'de> FnOnce(&'de <C as Deref>::Target) -> Result<<Y as Yokeable<'de>>::Output, E>,

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.

Call sites for this function may not compile pre-1.61; if this still happens, use Yoke::try_attach_to_cart_badly() and file a bug.

Source

pub fn attach_to_cart_badly( cart: C, f: for<'de> fn(_: &'de <C as Deref>::Target) -> <Y as Yokeable<'de>>::Output, ) -> Self

👎Deprecated

Use Yoke::attach_to_cart().

This was needed because the pre-1.61 compiler couldn’t always handle the FnOnce trait bound.

Source

pub fn try_attach_to_cart_badly<E>( cart: C, f: for<'de> fn(_: &'de <C as Deref>::Target) -> Result<<Y as Yokeable<'de>>::Output, E>, ) -> Result<Self, E>

👎Deprecated

Use Yoke::try_attach_to_cart().

This was needed because the pre-1.61 compiler couldn’t always handle the FnOnce trait bound.

Source§

impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C>

Source

pub fn get<'a>(&'a self) -> &'a <Y as Yokeable<'a>>::Output

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

pub fn backing_cart(&self) -> &C

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.

Source

pub fn into_backing_cart(self) -> C

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_owned();
let yoke = Yoke::<&'static str, Box<String>>::attach_to_zero_copy_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 std::borrow::Cow;
use yoke::Yoke;

let local_data = "foo".to_owned();
let mut yoke =
    Yoke::<Cow<'static, str>, Box<String>>::attach_to_zero_copy_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!
Source

pub unsafe fn replace_cart<C2>(self, f: impl FnOnce(C) -> C2) -> Yoke<Y, C2>

Unsafe function for replacing the cart with another

This can be used for type-erasing the cart, for example.

§Safety
  • f() must not panic

  • References from the yokeable Y should still be valid for the lifetime of the returned cart type C.

    For the purpose of determining this, Yoke guarantees that references from the Yokeable Y into the cart C will never be references into its stack data, only heap data protected by StableDeref. This does not necessarily mean that C implements StableDeref, rather that any data referenced by Y must be accessed through a StableDeref impl on something C owns.

    Concretely, this means that if C = Option<Rc<T>>, Y may contain references to the T but not anything else.

  • Lifetimes inside C must not be lengthened, even if they are themselves contravariant. I.e., if C contains an fn(&'a u8), it cannot be replaced with `fn(&’static u8), even though that is typically safe.

Typically, this means implementing f as something which wraps the inner cart type C. Yoke only really cares about destructors for its carts so it’s fine to erase other information about the cart, as long as the backing data will still be destroyed at the same time.

Source

pub fn with_mut<'a, F>(&'a mut self, f: F)
where F: 'static + for<'b> FnOnce(&'b mut <Y as Yokeable<'a>>::Output),

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

pub fn wrap_cart_in_option(self) -> Yoke<Y, Option<C>>

Helper function allowing one to wrap the cart type C in an Option<T>.

Source§

impl<Y: for<'a> Yokeable<'a>> Yoke<Y, ()>

Source

pub fn new_always_owned(yokeable: Y) -> Self

Construct a new Yoke from static data. There will be no references to cart here since Yokeables are 'static, this is good for e.g. constructing fully owned Yokes 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");
Source

pub fn into_yokeable(self) -> Y

Obtain the yokeable out of a Yoke<Y, ()>

For most Yoke types this would be unsafe but it’s fine for Yoke<Y, ()> since there are no actual internal references

Source§

impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, Option<C>>

Source

pub const fn new_owned(yokeable: Y) -> Self

Construct a new Yoke from static data. There will be no references to cart here since Yokeables are 'static, this is good for e.g. constructing fully owned Yokes with no internal borrowing.

This can be paired with [Yoke:: wrap_cart_in_option()] 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");
Source

pub fn try_into_yokeable(self) -> Result<Y, Self>

Obtain the yokeable out of a Yoke<Y, Option<C>> if possible.

If the cart is None, this returns Ok, but if the cart is Some, this returns self as an error.

Source§

impl<Y: for<'a> Yokeable<'a>, C: CartablePointerLike> Yoke<Y, Option<C>>

Source

pub fn convert_cart_into_option_pointer( self, ) -> Yoke<Y, CartableOptionPointer<C>>

Converts a Yoke<Y, Option<C>> to Yoke<Y, CartableOptionPointer<C>> for better niche optimization when stored as a field.

§Examples
use std::borrow::Cow;
use yoke::Yoke;

let yoke: Yoke<Cow<[u8]>, Box<Vec<u8>>> =
    Yoke::attach_to_cart(vec![10, 20, 30].into(), |c| c.into());

let yoke_option = yoke.wrap_cart_in_option();
let yoke_option_pointer = yoke_option.convert_cart_into_option_pointer();

The niche improves stack sizes:

use yoke::Yoke;
use yoke::cartable_ptr::CartableOptionPointer;
use std::mem::size_of;
use std::rc::Rc;

// The data struct is 6 words:
const W: usize = core::mem::size_of::<usize>();
assert_eq!(W * 6, size_of::<MyDataStruct>());

// An enum containing the data struct with an `Option<Rc>` cart is 8 words:
enum StaticOrYoke1 {
    Static(&'static MyDataStruct<'static>),
    Yoke(Yoke<MyDataStruct<'static>, Option<Rc<String>>>),
}
assert_eq!(W * 8, size_of::<StaticOrYoke1>());

// When using `CartableOptionPointer``, we need only 7 words for the same behavior:
enum StaticOrYoke2 {
    Static(&'static MyDataStruct<'static>),
    Yoke(Yoke<MyDataStruct<'static>, CartableOptionPointer<Rc<String>>>),
}
assert_eq!(W * 7, size_of::<StaticOrYoke2>());
Source§

impl<Y: for<'a> Yokeable<'a>, C: CartablePointerLike> Yoke<Y, CartableOptionPointer<C>>

Source

pub fn try_into_yokeable(self) -> Result<Y, Self>

Obtain the yokeable out of a Yoke<Y, CartableOptionPointer<C>> if possible.

If the cart is None, this returns Ok, but if the cart is Some, this returns self as an error.

Source§

impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C>

Source

pub fn map_project<P, F>(self, f: F) -> Yoke<P, C>
where P: for<'a> Yokeable<'a>, F: for<'a> FnOnce(<Y as Yokeable<'a>>::Output, PhantomData<&'a ()>) -> <P as Yokeable<'a>>::Output,

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.

The callback takes an additional PhantomData<&()> parameter to anchor lifetimes (see #86702) This parameter should just be ignored in the callback.

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.map_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 map_project_string_1(
    bar: Yoke<Bar<'static>, Rc<[u8]>>,
) -> Yoke<&'static str, Rc<[u8]>> {
    bar.map_project(|bar, _| bar.string_1)
}
Source

pub fn map_project_cloned<'this, P, F>(&'this self, f: F) -> Yoke<P, C>
where P: for<'a> Yokeable<'a>, C: CloneableCart, F: for<'a> FnOnce(&'this <Y as Yokeable<'a>>::Output, PhantomData<&'a ()>) -> <P as Yokeable<'a>>::Output,

This is similar to Yoke::map_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::map_project because then it will not clone fields that are going to be discarded.

Source

pub fn try_map_project<P, F, E>(self, f: F) -> Result<Yoke<P, C>, E>
where P: for<'a> Yokeable<'a>, F: for<'a> FnOnce(<Y as Yokeable<'a>>::Output, PhantomData<&'a ()>) -> Result<<P as Yokeable<'a>>::Output, E>,

This is similar to Yoke::map_project, however it can also bubble up an error from the callback.

fn slice(
    y: Yoke<&'static [u8], Rc<[u8]>>,
) -> Result<Yoke<&'static str, Rc<[u8]>>, Utf8Error> {
    y.try_map_project(move |bytes, _| str::from_utf8(bytes))
}

This can also be used to create a yoke for a subfield

// also safely implements Yokeable<'a>
struct Bar<'a> {
    bytes_1: &'a [u8],
    string_2: &'a str,
}

fn map_project_string_1(
    bar: Yoke<Bar<'static>, Rc<[u8]>>,
) -> Result<Yoke<&'static str, Rc<[u8]>>, Utf8Error> {
    bar.try_map_project(|bar, _| str::from_utf8(bar.bytes_1))
}
Source

pub fn try_map_project_cloned<'this, P, F, E>( &'this self, f: F, ) -> Result<Yoke<P, C>, E>
where P: for<'a> Yokeable<'a>, C: CloneableCart, F: for<'a> FnOnce(&'this <Y as Yokeable<'a>>::Output, PhantomData<&'a ()>) -> Result<<P as Yokeable<'a>>::Output, E>,

This is similar to Yoke::try_map_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::map_project because then it will not clone fields that are going to be discarded.

Source

pub fn map_project_with_explicit_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::map_project, but it works around older versions of Rust not being able to use FnOnce by using an explicit capture input. See #1061.

See the docs of Yoke::map_project for how this works.

Source

pub fn map_project_cloned_with_explicit_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::map_project_cloned, but it works around older versions of Rust not being able to use FnOnce by using an explicit capture input. See #1061.

See the docs of Yoke::map_project_cloned for how this works.

Source

pub fn try_map_project_with_explicit_capture<P, T, E>( self, capture: T, f: for<'a> fn(_: <Y as Yokeable<'a>>::Output, capture: T, _: PhantomData<&'a ()>) -> Result<<P as Yokeable<'a>>::Output, E>, ) -> Result<Yoke<P, C>, E>
where P: for<'a> Yokeable<'a>,

This is similar to Yoke::try_map_project, but it works around older versions of Rust not being able to use FnOnce by using an explicit capture input. See #1061.

See the docs of Yoke::try_map_project for how this works.

Source

pub fn try_map_project_cloned_with_explicit_capture<'this, P, T, E>( &'this self, capture: T, f: for<'a> fn(_: &'this <Y as Yokeable<'a>>::Output, capture: T, _: PhantomData<&'a ()>) -> Result<<P as Yokeable<'a>>::Output, E>, ) -> Result<Yoke<P, C>, E>
where P: for<'a> Yokeable<'a>, C: CloneableCart,

This is similar to Yoke::try_map_project_cloned, but it works around older versions of Rust not being able to use FnOnce by using an explicit capture input. See #1061.

See the docs of Yoke::try_map_project_cloned for how this works.

Source§

impl<Y: for<'a> Yokeable<'a>, C: 'static + Sized> Yoke<Y, Rc<C>>

Source

pub fn erase_rc_cart(self) -> Yoke<Y, ErasedRcCart>

Allows type-erasing the cart in a Yoke<Y, Rc<C>>.

The yoke only carries around a cart type C for its destructor, since it needs to be able to guarantee that its internal references are valid for the lifetime of the Yoke. As such, the actual type of the Cart is not very useful unless you wish to extract data out of it via Yoke::backing_cart(). Erasing the cart allows for one to mix Yokes obtained from different sources.

In case the cart type C is not already an Rc<T>, you can use Yoke::wrap_cart_in_rc() to wrap it.

Enabled with the alloc Cargo feature.

§Example
use std::rc::Rc;
use yoke::erased::ErasedRcCart;
use yoke::Yoke;

let buffer1: Rc<String> = Rc::new("   foo bar baz  ".into());
let buffer2: Box<String> = Box::new("  baz quux  ".into());

let yoke1 =
    Yoke::<&'static str, _>::attach_to_cart(buffer1, |rc| rc.trim());
let yoke2 = Yoke::<&'static str, _>::attach_to_cart(buffer2, |b| b.trim());

let erased1: Yoke<_, ErasedRcCart> = yoke1.erase_rc_cart();
// Wrap the Box in an Rc to make it compatible
let erased2: Yoke<_, ErasedRcCart> =
    yoke2.wrap_cart_in_rc().erase_rc_cart();

// Now erased1 and erased2 have the same type!
Source§

impl<Y: for<'a> Yokeable<'a>, C: 'static + Sized + Send + Sync> Yoke<Y, Arc<C>>

Source

pub fn erase_arc_cart(self) -> Yoke<Y, ErasedArcCart>

Allows type-erasing the cart in a Yoke<Y, Arc<C>>.

The yoke only carries around a cart type C for its destructor, since it needs to be able to guarantee that its internal references are valid for the lifetime of the Yoke. As such, the actual type of the Cart is not very useful unless you wish to extract data out of it via Yoke::backing_cart(). Erasing the cart allows for one to mix Yokes obtained from different sources.

In case the cart type C is not already an Arc<T>, you can use Yoke::wrap_cart_in_arc() to wrap it.

Enabled with the alloc Cargo feature.

§Example
use std::sync::Arc;
use yoke::erased::ErasedArcCart;
use yoke::Yoke;

let buffer1: Arc<String> = Arc::new("   foo bar baz  ".into());
let buffer2: Box<String> = Box::new("  baz quux  ".into());

let yoke1 =
    Yoke::<&'static str, _>::attach_to_cart(buffer1, |arc| arc.trim());
let yoke2 = Yoke::<&'static str, _>::attach_to_cart(buffer2, |b| b.trim());

let erased1: Yoke<_, ErasedArcCart> = yoke1.erase_arc_cart();
// Wrap the Box in an Rc to make it compatible
let erased2: Yoke<_, ErasedArcCart> =
    yoke2.wrap_cart_in_arc().erase_arc_cart();

// Now erased1 and erased2 have the same type!
Source§

impl<Y: for<'a> Yokeable<'a>, C: 'static + Sized> Yoke<Y, Box<C>>

Source

pub fn erase_box_cart(self) -> Yoke<Y, ErasedBoxCart>

Allows type-erasing the cart in a Yoke<Y, Box<C>>.

The yoke only carries around a cart type C for its destructor, since it needs to be able to guarantee that its internal references are valid for the lifetime of the Yoke. As such, the actual type of the Cart is not very useful unless you wish to extract data out of it via Yoke::backing_cart(). Erasing the cart allows for one to mix Yokes obtained from different sources.

In case the cart type C is not already Box<T>, you can use Yoke::wrap_cart_in_box() to wrap it.

Enabled with the alloc Cargo feature.

§Example
use std::rc::Rc;
use yoke::erased::ErasedBoxCart;
use yoke::Yoke;

let buffer1: Rc<String> = Rc::new("   foo bar baz  ".into());
let buffer2: Box<String> = Box::new("  baz quux  ".into());

let yoke1 =
    Yoke::<&'static str, _>::attach_to_cart(buffer1, |rc| rc.trim());
let yoke2 = Yoke::<&'static str, _>::attach_to_cart(buffer2, |b| b.trim());

// Wrap the Rc in an Box to make it compatible
let erased1: Yoke<_, ErasedBoxCart> =
    yoke1.wrap_cart_in_box().erase_box_cart();
let erased2: Yoke<_, ErasedBoxCart> = yoke2.erase_box_cart();

// Now erased1 and erased2 have the same type!
Source§

impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C>

Source

pub fn wrap_cart_in_box(self) -> Yoke<Y, Box<C>>

Helper function allowing one to wrap the cart type C in a Box<T>. Can be paired with Yoke::erase_box_cart()

Enabled with the alloc Cargo feature.

Source

pub fn wrap_cart_in_rc(self) -> Yoke<Y, Rc<C>>

Helper function allowing one to wrap the cart type C in an Rc<T>. Can be paired with Yoke::erase_rc_cart(), or generally used to make the Yoke cloneable.

Enabled with the alloc Cargo feature.

Source

pub fn wrap_cart_in_arc(self) -> Yoke<Y, Arc<C>>

Helper function allowing one to wrap the cart type C in an Rc<T>. Can be paired with Yoke::erase_arc_cart(), or generally used to make the Yoke cloneable.

Enabled with the alloc Cargo feature.

Source§

impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C>

Source

pub fn wrap_cart_in_either_a<B>(self) -> Yoke<Y, EitherCart<C, B>>

Helper function allowing one to wrap the cart type C in an EitherCart.

This function wraps the cart into the A variant. To wrap it into the B variant, use Self::wrap_cart_in_either_b().

For an example, see EitherCart.

Source

pub fn wrap_cart_in_either_b<A>(self) -> Yoke<Y, EitherCart<A, C>>

Helper function allowing one to wrap the cart type C in an EitherCart.

This function wraps the cart into the B variant. To wrap it into the A variant, use Self::wrap_cart_in_either_a().

For an example, see EitherCart.

Source§

impl<Y, C> Yoke<Y, C>
where Y: for<'a> Yokeable<'a>, for<'a> YokeTraitHack<<Y as Yokeable<'a>>::Output>: ZeroFrom<'a, <C as Deref>::Target>, C: StableDeref + Deref, <C as Deref>::Target: 'static,

Source

pub fn attach_to_zero_copy_cart(cart: C) -> Self

Construct a Yoke<Y, C> from a cart implementing StableDeref by zero-copy cloning the cart to Y and then yokeing that object to the cart.

The type Y must implement ZeroFrom<C::Target>. This trait is auto-implemented on many common types and can be custom implemented or derived in order to make it easier to construct a Yoke.

§Example

Attach to a cart:

use std::borrow::Cow;
use yoke::Yoke;

let yoke = Yoke::<Cow<'static, str>, String>::attach_to_zero_copy_cart(
    "demo".to_owned(),
);

assert_eq!("demo", yoke.get());

Trait Implementations§

Source§

impl<Y: for<'a> Yokeable<'a>, C: CloneableCart> Clone for Yoke<Y, C>
where for<'a> YokeTraitHack<<Y as Yokeable<'a>>::Output>: Clone,

Clone requires that the cart type C derefs to the same address after it is cloned. This works for Rc, Arc, and &’a T.

For other cart types, clone .backing_cart() and re-use .attach_to_cart(); however, doing so may lose mutations performed via .with_mut().

Cloning a Yoke is often a cheap operation requiring no heap allocations, in much the same way that cloning an Rc is a cheap operation. However, if the yokeable contains owned data (e.g., from .with_mut()), that data will need to be cloned.

Source§

fn clone(&self) -> Self

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<Y: for<'a> Yokeable<'a>, C: Debug> Debug for Yoke<Y, C>
where for<'a> <Y as Yokeable<'a>>::Output: Debug,

Source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<Y, C> Freeze for Yoke<Y, C>
where C: Freeze, Y: Freeze,

§

impl<Y, C> RefUnwindSafe for Yoke<Y, C>

§

impl<Y, C> Send for Yoke<Y, C>
where C: Send, Y: Send,

§

impl<Y, C> Sync for Yoke<Y, C>
where C: Sync, Y: Sync,

§

impl<Y, C> Unpin for Yoke<Y, C>
where C: Unpin, Y: Unpin,

§

impl<Y, C> UnwindSafe for Yoke<Y, C>
where C: UnwindSafe, Y: 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, dst: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
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> ErasedDestructor for T
where T: 'static,