yoke/
yoke.rs

1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5use crate::cartable_ptr::{CartableOptionPointer, CartablePointerLike};
6use crate::either::EitherCart;
7#[cfg(feature = "alloc")]
8use crate::erased::{ErasedArcCart, ErasedBoxCart, ErasedRcCart};
9use crate::kinda_sorta_dangling::KindaSortaDangling;
10use crate::Yokeable;
11use core::marker::PhantomData;
12use core::ops::Deref;
13use stable_deref_trait::StableDeref;
14
15#[cfg(feature = "alloc")]
16use alloc::boxed::Box;
17#[cfg(feature = "alloc")]
18use alloc::rc::Rc;
19#[cfg(feature = "alloc")]
20use alloc::sync::Arc;
21
22/// A Cow-like borrowed object "yoked" to its backing data.
23///
24/// This allows things like zero copy deserialized data to carry around
25/// shared references to their backing buffer, by "erasing" their static lifetime
26/// and turning it into a dynamically managed one.
27///
28/// `Y` (the [`Yokeable`]) is the object containing the references,
29/// and will typically be of the form `Foo<'static>`. The `'static` is
30/// not the actual lifetime of the data, rather it is a convenient way to mark the
31/// erased lifetime and make it dynamic.
32///
33/// `C` is the "cart", which `Y` may contain references to. After the yoke is constructed,
34/// the cart serves little purpose except to guarantee that `Y`'s references remain valid
35/// for as long as the yoke remains in memory (by calling the destructor at the appropriate moment).
36///
37/// The primary constructor for [`Yoke`] is [`Yoke::attach_to_cart()`]. Several variants of that
38/// constructor are provided to serve numerous types of call sites and `Yoke` signatures.
39///
40/// The key behind this type is [`Yoke::get()`], where calling [`.get()`][Yoke::get] on a type like
41/// `Yoke<Cow<'static, str>, _>` will get you a short-lived `&'a Cow<'a, str>`, restricted to the
42/// lifetime of the borrow used during `.get()`. This is entirely safe since the `Cow` borrows from
43/// the cart type `C`, which cannot be interfered with as long as the `Yoke` is borrowed by `.get
44/// ()`. `.get()` protects access by essentially reifying the erased lifetime to a safe local one
45/// when necessary.
46///
47/// Furthermore, there are various [`.map_project()`][Yoke::map_project] methods that allow turning a `Yoke`
48/// into another `Yoke` containing a different type that may contain elements of the original yoked
49/// value. See the [`Yoke::map_project()`] docs for more details.
50///
51/// In general, `C` is a concrete type, but it is also possible for it to be a trait object.
52///
53/// # Example
54///
55/// For example, we can use this to store zero-copy deserialized data in a cache:
56///
57/// ```rust
58/// # use yoke::Yoke;
59/// # use std::rc::Rc;
60/// # use std::borrow::Cow;
61/// # fn load_from_cache(_filename: &str) -> Rc<[u8]> {
62/// #     // dummy implementation
63/// #     Rc::new([0x5, 0, 0, 0, 0, 0, 0, 0, 0x68, 0x65, 0x6c, 0x6c, 0x6f])
64/// # }
65///
66/// fn load_object(filename: &str) -> Yoke<Cow<'static, str>, Rc<[u8]>> {
67///     let rc: Rc<[u8]> = load_from_cache(filename);
68///     Yoke::<Cow<'static, str>, Rc<[u8]>>::attach_to_cart(rc, |data: &[u8]| {
69///         // essentially forcing a #[serde(borrow)]
70///         Cow::Borrowed(bincode::deserialize(data).unwrap())
71///     })
72/// }
73///
74/// let yoke = load_object("filename.bincode");
75/// assert_eq!(&**yoke.get(), "hello");
76/// assert!(matches!(yoke.get(), &Cow::Borrowed(_)));
77/// ```
78pub struct Yoke<Y: for<'a> Yokeable<'a>, C> {
79    // must be the first field for drop order
80    // this will have a 'static lifetime parameter, that parameter is a lie
81    yokeable: KindaSortaDangling<Y>,
82    // Safety invariant: this type can be anything, but `yokeable` may only contain references to
83    // StableDeref parts of this cart, and the targets of those references must be valid for the
84    // lifetime of this cart (it must own or borrow them). It's ok for this cart to contain stack
85    // data as long as it is not referenced by `yokeable` during construction. `attach_to_cart`,
86    // the typical constructor of this type, upholds this invariant, but other constructors like
87    // `replace_cart` need to uphold it.
88    // The implementation guarantees that there are no live `yokeable`s that reference data
89    // in a `cart` when the `cart` is dropped; this is guaranteed in the drop glue through field
90    // order.
91    cart: C,
92}
93
94// Manual `Debug` implementation, since the derived one would be unsound.
95// See https://github.com/unicode-org/icu4x/issues/3685
96impl<Y: for<'a> Yokeable<'a>, C: core::fmt::Debug> core::fmt::Debug for Yoke<Y, C>
97where
98    for<'a> <Y as Yokeable<'a>>::Output: core::fmt::Debug,
99{
100    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
101        f.debug_struct("Yoke")
102            .field("yokeable", self.get())
103            .field("cart", self.backing_cart())
104            .finish()
105    }
106}
107
108#[test]
109fn test_debug() {
110    let local_data = "foo".to_owned();
111    let y1 = Yoke::<alloc::borrow::Cow<'static, str>, Rc<String>>::attach_to_zero_copy_cart(
112        Rc::new(local_data),
113    );
114    assert_eq!(
115        format!("{y1:?}"),
116        r#"Yoke { yokeable: "foo", cart: "foo" }"#,
117    );
118}
119
120impl<Y: for<'a> Yokeable<'a>, C: StableDeref> Yoke<Y, C>
121where
122    <C as Deref>::Target: 'static,
123{
124    /// Construct a [`Yoke`] by yokeing an object to a cart in a closure.
125    ///
126    /// The closure can read and write data outside of its scope, but data it returns
127    /// may borrow only from the argument passed to the closure.
128    ///
129    /// See also [`Yoke::try_attach_to_cart()`] to return a `Result` from the closure.
130    ///
131    /// Call sites for this function may not compile pre-1.61; if this still happens, use
132    /// [`Yoke::attach_to_cart_badly()`] and file a bug.
133    ///
134    /// # Examples
135    ///
136    /// ```
137    /// # use yoke::Yoke;
138    /// # use std::rc::Rc;
139    /// # use std::borrow::Cow;
140    /// # fn load_from_cache(_filename: &str) -> Rc<[u8]> {
141    /// #     // dummy implementation
142    /// #     Rc::new([0x5, 0, 0, 0, 0, 0, 0, 0, 0x68, 0x65, 0x6c, 0x6c, 0x6f])
143    /// # }
144    ///
145    /// fn load_object(filename: &str) -> Yoke<Cow<'static, str>, Rc<[u8]>> {
146    ///     let rc: Rc<[u8]> = load_from_cache(filename);
147    ///     Yoke::<Cow<'static, str>, Rc<[u8]>>::attach_to_cart(rc, |data: &[u8]| {
148    ///         // essentially forcing a #[serde(borrow)]
149    ///         Cow::Borrowed(bincode::deserialize(data).unwrap())
150    ///     })
151    /// }
152    ///
153    /// let yoke: Yoke<Cow<str>, _> = load_object("filename.bincode");
154    /// assert_eq!(&**yoke.get(), "hello");
155    /// assert!(matches!(yoke.get(), &Cow::Borrowed(_)));
156    /// ```
157    ///
158    /// Write the number of consumed bytes to a local variable:
159    ///
160    /// ```
161    /// # use yoke::Yoke;
162    /// # use std::rc::Rc;
163    /// # use std::borrow::Cow;
164    /// # fn load_from_cache(_filename: &str) -> Rc<[u8]> {
165    /// #     // dummy implementation
166    /// #     Rc::new([0x5, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0, 0, 0])
167    /// # }
168    ///
169    /// fn load_object(
170    ///     filename: &str,
171    /// ) -> (Yoke<Cow<'static, str>, Rc<[u8]>>, usize) {
172    ///     let rc: Rc<[u8]> = load_from_cache(filename);
173    ///     let mut bytes_remaining = 0;
174    ///     let bytes_remaining = &mut bytes_remaining;
175    ///     let yoke = Yoke::<Cow<'static, str>, Rc<[u8]>>::attach_to_cart(
176    ///         rc,
177    ///         |data: &[u8]| {
178    ///             let mut d = postcard::Deserializer::from_bytes(data);
179    ///             let output = serde::Deserialize::deserialize(&mut d);
180    ///             *bytes_remaining = d.finalize().unwrap().len();
181    ///             Cow::Borrowed(output.unwrap())
182    ///         },
183    ///     );
184    ///     (yoke, *bytes_remaining)
185    /// }
186    ///
187    /// let (yoke, bytes_remaining) = load_object("filename.postcard");
188    /// assert_eq!(&**yoke.get(), "hello");
189    /// assert!(matches!(yoke.get(), &Cow::Borrowed(_)));
190    /// assert_eq!(bytes_remaining, 3);
191    /// ```
192    pub fn attach_to_cart<F>(cart: C, f: F) -> Self
193    where
194        // safety note: This works by enforcing that the *only* place the return value of F
195        // can borrow from is the cart, since `F` must be valid for all lifetimes `'de`
196        //
197        // The <C as Deref>::Target: 'static on the impl is crucial for safety as well
198        //
199        // See safety docs at the bottom of this file for more information
200        F: for<'de> FnOnce(&'de <C as Deref>::Target) -> <Y as Yokeable<'de>>::Output,
201        <C as Deref>::Target: 'static,
202    {
203        let deserialized = f(cart.deref());
204        Self {
205            yokeable: KindaSortaDangling::new(
206                // Safety: the resulting `yokeable` is dropped before the `cart` because
207                // of the Yoke invariant. See the safety docs at the bottom of this file
208                // for the justification of why yokeable could only borrow from the Cart.
209                unsafe { Y::make(deserialized) },
210            ),
211            cart,
212        }
213    }
214
215    /// Construct a [`Yoke`] by yokeing an object to a cart. If an error occurs in the
216    /// deserializer function, the error is passed up to the caller.
217    ///
218    /// Call sites for this function may not compile pre-1.61; if this still happens, use
219    /// [`Yoke::try_attach_to_cart_badly()`] and file a bug.
220    pub fn try_attach_to_cart<E, F>(cart: C, f: F) -> Result<Self, E>
221    where
222        F: for<'de> FnOnce(&'de <C as Deref>::Target) -> Result<<Y as Yokeable<'de>>::Output, E>,
223        <C as Deref>::Target: 'static,
224    {
225        let deserialized = f(cart.deref())?;
226        Ok(Self {
227            yokeable: KindaSortaDangling::new(
228                // Safety: the resulting `yokeable` is dropped before the `cart` because
229                // of the Yoke invariant. See the safety docs at the bottom of this file
230                // for the justification of why yokeable could only borrow from the Cart.
231                unsafe { Y::make(deserialized) },
232            ),
233            cart,
234        })
235    }
236
237    /// Use [`Yoke::attach_to_cart()`].
238    ///
239    /// This was needed because the pre-1.61 compiler couldn't always handle the FnOnce trait bound.
240    #[deprecated]
241    pub fn attach_to_cart_badly(
242        cart: C,
243        f: for<'de> fn(&'de <C as Deref>::Target) -> <Y as Yokeable<'de>>::Output,
244    ) -> Self {
245        Self::attach_to_cart(cart, f)
246    }
247
248    /// Use [`Yoke::try_attach_to_cart()`].
249    ///
250    /// This was needed because the pre-1.61 compiler couldn't always handle the FnOnce trait bound.
251    #[deprecated]
252    pub fn try_attach_to_cart_badly<E>(
253        cart: C,
254        f: for<'de> fn(&'de <C as Deref>::Target) -> Result<<Y as Yokeable<'de>>::Output, E>,
255    ) -> Result<Self, E> {
256        Self::try_attach_to_cart(cart, f)
257    }
258}
259
260impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
261    /// Obtain a valid reference to the yokeable data
262    ///
263    /// This essentially transforms the lifetime of the internal yokeable data to
264    /// be valid.
265    /// For example, if you're working with a `Yoke<Cow<'static, T>, C>`, this
266    /// will return an `&'a Cow<'a, T>`
267    ///
268    /// # Example
269    ///
270    /// ```rust
271    /// # use yoke::Yoke;
272    /// # use std::rc::Rc;
273    /// # use std::borrow::Cow;
274    /// # fn load_from_cache(_filename: &str) -> Rc<[u8]> {
275    /// #     // dummy implementation
276    /// #     Rc::new([0x5, 0, 0, 0, 0, 0, 0, 0, 0x68, 0x65, 0x6c, 0x6c, 0x6f])
277    /// # }
278    /// #
279    /// # fn load_object(filename: &str) -> Yoke<Cow<'static, str>, Rc<[u8]>> {
280    /// #     let rc: Rc<[u8]> = load_from_cache(filename);
281    /// #     Yoke::<Cow<'static, str>, Rc<[u8]>>::attach_to_cart(rc, |data: &[u8]| {
282    /// #         Cow::Borrowed(bincode::deserialize(data).unwrap())
283    /// #     })
284    /// # }
285    ///
286    /// // load_object() defined in the example at the top of this page
287    /// let yoke: Yoke<Cow<str>, _> = load_object("filename.bincode");
288    /// assert_eq!(yoke.get(), "hello");
289    /// ```
290    #[inline]
291    pub fn get<'a>(&'a self) -> &'a <Y as Yokeable<'a>>::Output {
292        self.yokeable.transform()
293    }
294
295    /// Get a reference to the backing cart.
296    ///
297    /// This can be useful when building caches, etc. However, if you plan to store the cart
298    /// separately from the yoke, read the note of caution below in [`Yoke::into_backing_cart`].
299    pub fn backing_cart(&self) -> &C {
300        &self.cart
301    }
302
303    /// Get the backing cart by value, dropping the yokeable object.
304    ///
305    /// **Caution:** Calling this method could cause information saved in the yokeable object but
306    /// not the cart to be lost. Use this method only if the yokeable object cannot contain its
307    /// own information.
308    ///
309    /// # Example
310    ///
311    /// Good example: the yokeable object is only a reference, so no information can be lost.
312    ///
313    /// ```
314    /// use yoke::Yoke;
315    ///
316    /// let local_data = "foo".to_owned();
317    /// let yoke = Yoke::<&'static str, Box<String>>::attach_to_zero_copy_cart(
318    ///     Box::new(local_data),
319    /// );
320    /// assert_eq!(*yoke.get(), "foo");
321    ///
322    /// // Get back the cart
323    /// let cart = yoke.into_backing_cart();
324    /// assert_eq!(&*cart, "foo");
325    /// ```
326    ///
327    /// Bad example: information specified in `.with_mut()` is lost.
328    ///
329    /// ```
330    /// use std::borrow::Cow;
331    /// use yoke::Yoke;
332    ///
333    /// let local_data = "foo".to_owned();
334    /// let mut yoke =
335    ///     Yoke::<Cow<'static, str>, Box<String>>::attach_to_zero_copy_cart(
336    ///         Box::new(local_data),
337    ///     );
338    /// assert_eq!(yoke.get(), "foo");
339    ///
340    /// // Override data in the cart
341    /// yoke.with_mut(|cow| {
342    ///     let mut_str = cow.to_mut();
343    ///     mut_str.clear();
344    ///     mut_str.push_str("bar");
345    /// });
346    /// assert_eq!(yoke.get(), "bar");
347    ///
348    /// // Get back the cart
349    /// let cart = yoke.into_backing_cart();
350    /// assert_eq!(&*cart, "foo"); // WHOOPS!
351    /// ```
352    pub fn into_backing_cart(self) -> C {
353        self.cart
354    }
355
356    /// Unsafe function for replacing the cart with another
357    ///
358    /// This can be used for type-erasing the cart, for example.
359    ///
360    /// # Safety
361    ///
362    /// - `f()` must not panic
363    /// - References from the yokeable `Y` should still be valid for the lifetime of the
364    ///   returned cart type `C`.
365    ///
366    ///   For the purpose of determining this, `Yoke` guarantees that references from the Yokeable
367    ///   `Y` into the cart `C` will never be references into its stack data, only heap data protected
368    ///   by `StableDeref`. This does not necessarily mean that `C` implements `StableDeref`, rather that
369    ///   any data referenced by `Y` must be accessed through a `StableDeref` impl on something `C` owns.
370    ///
371    ///   Concretely, this means that if `C = Option<Rc<T>>`, `Y` may contain references to the `T` but not
372    ///   anything else.
373    /// - Lifetimes inside C must not be lengthened, even if they are themselves contravariant.
374    ///   I.e., if C contains an `fn(&'a u8)`, it cannot be replaced with `fn(&'static u8),
375    ///   even though that is typically safe.
376    ///
377    /// Typically, this means implementing `f` as something which _wraps_ the inner cart type `C`.
378    /// `Yoke` only really cares about destructors for its carts so it's fine to erase other
379    /// information about the cart, as long as the backing data will still be destroyed at the
380    /// same time.
381    #[inline]
382    pub unsafe fn replace_cart<C2>(self, f: impl FnOnce(C) -> C2) -> Yoke<Y, C2> {
383        Yoke {
384            // Safety note: the safety invariant of this function guarantees that
385            // the data that the yokeable references has its ownership (if any)
386            // transferred to the new cart before self.cart is dropped.
387            yokeable: self.yokeable,
388            cart: f(self.cart),
389        }
390    }
391
392    /// Mutate the stored [`Yokeable`] data.
393    ///
394    /// See [`Yokeable::transform_mut()`] for why this operation is safe.
395    ///
396    /// # Example
397    ///
398    /// This can be used to partially mutate the stored data, provided
399    /// no _new_ borrowed data is introduced.
400    ///
401    /// ```rust
402    /// # use yoke::{Yoke, Yokeable};
403    /// # use std::rc::Rc;
404    /// # use std::borrow::Cow;
405    /// # use std::mem;
406    /// # fn load_from_cache(_filename: &str) -> Rc<[u8]> {
407    /// #     // dummy implementation
408    /// #     Rc::new([0x5, 0, 0, 0, 0, 0, 0, 0, 0x68, 0x65, 0x6c, 0x6c, 0x6f])
409    /// # }
410    /// #
411    /// # fn load_object(filename: &str) -> Yoke<Bar<'static>, Rc<[u8]>> {
412    /// #     let rc: Rc<[u8]> = load_from_cache(filename);
413    /// #     Yoke::<Bar<'static>, Rc<[u8]>>::attach_to_cart(rc, |data: &[u8]| {
414    /// #         // A real implementation would properly deserialize `Bar` as a whole
415    /// #         Bar {
416    /// #             numbers: Cow::Borrowed(bincode::deserialize(data).unwrap()),
417    /// #             string: Cow::Borrowed(bincode::deserialize(data).unwrap()),
418    /// #             owned: Vec::new(),
419    /// #         }
420    /// #     })
421    /// # }
422    ///
423    /// // also implements Yokeable
424    /// struct Bar<'a> {
425    ///     numbers: Cow<'a, [u8]>,
426    ///     string: Cow<'a, str>,
427    ///     owned: Vec<u8>,
428    /// }
429    ///
430    /// // `load_object()` deserializes an object from a file
431    /// let mut bar: Yoke<Bar, _> = load_object("filename.bincode");
432    /// assert_eq!(bar.get().string, "hello");
433    /// assert!(matches!(bar.get().string, Cow::Borrowed(_)));
434    /// assert_eq!(&*bar.get().numbers, &[0x68, 0x65, 0x6c, 0x6c, 0x6f]);
435    /// assert!(matches!(bar.get().numbers, Cow::Borrowed(_)));
436    /// assert_eq!(&*bar.get().owned, &[]);
437    ///
438    /// bar.with_mut(|bar| {
439    ///     bar.string.to_mut().push_str(" world");
440    ///     bar.owned.extend_from_slice(&[1, 4, 1, 5, 9]);
441    /// });
442    ///
443    /// assert_eq!(bar.get().string, "hello world");
444    /// assert!(matches!(bar.get().string, Cow::Owned(_)));
445    /// assert_eq!(&*bar.get().owned, &[1, 4, 1, 5, 9]);
446    /// // Unchanged and still Cow::Borrowed
447    /// assert_eq!(&*bar.get().numbers, &[0x68, 0x65, 0x6c, 0x6c, 0x6f]);
448    /// assert!(matches!(bar.get().numbers, Cow::Borrowed(_)));
449    ///
450    /// # unsafe impl<'a> Yokeable<'a> for Bar<'static> {
451    /// #     type Output = Bar<'a>;
452    /// #     fn transform(&'a self) -> &'a Bar<'a> {
453    /// #         self
454    /// #     }
455    /// #
456    /// #     fn transform_owned(self) -> Bar<'a> {
457    /// #         // covariant lifetime cast, can be done safely
458    /// #         self
459    /// #     }
460    /// #
461    /// #     unsafe fn make(from: Bar<'a>) -> Self {
462    /// #         let ret = mem::transmute_copy(&from);
463    /// #         mem::forget(from);
464    /// #         ret
465    /// #     }
466    /// #
467    /// #     fn transform_mut<F>(&'a mut self, f: F)
468    /// #     where
469    /// #         F: 'static + FnOnce(&'a mut Self::Output),
470    /// #     {
471    /// #         unsafe { f(mem::transmute(self)) }
472    /// #     }
473    /// # }
474    /// ```
475    pub fn with_mut<'a, F>(&'a mut self, f: F)
476    where
477        F: 'static + for<'b> FnOnce(&'b mut <Y as Yokeable<'a>>::Output),
478    {
479        self.yokeable.transform_mut(f)
480    }
481
482    /// Helper function allowing one to wrap the cart type `C` in an `Option<T>`.
483    #[inline]
484    pub fn wrap_cart_in_option(self) -> Yoke<Y, Option<C>> {
485        // Safety: the cart is preserved (since it is just wrapped into a Some),
486        // so any data it owns is too.
487        unsafe { self.replace_cart(Some) }
488    }
489}
490
491impl<Y: for<'a> Yokeable<'a>> Yoke<Y, ()> {
492    /// Construct a new [`Yoke`] from static data. There will be no
493    /// references to `cart` here since [`Yokeable`]s are `'static`,
494    /// this is good for e.g. constructing fully owned
495    /// [`Yoke`]s with no internal borrowing.
496    ///
497    /// This is similar to [`Yoke::new_owned()`] but it does not allow you to
498    /// mix the [`Yoke`] with borrowed data. This is primarily useful
499    /// for using [`Yoke`] in generic scenarios.
500    ///
501    /// # Example
502    ///
503    /// ```rust
504    /// # use yoke::Yoke;
505    /// # use std::borrow::Cow;
506    ///
507    /// let owned: Cow<str> = "hello".to_owned().into();
508    /// // this yoke can be intermingled with actually-borrowed Yokes
509    /// let yoke: Yoke<Cow<str>, ()> = Yoke::new_always_owned(owned);
510    ///
511    /// assert_eq!(yoke.get(), "hello");
512    /// ```
513    pub fn new_always_owned(yokeable: Y) -> Self {
514        Self {
515            // Safety note: this `yokeable` certainly does not reference data owned by (), so we do
516            // not have to worry about when the `yokeable` is dropped.
517            yokeable: KindaSortaDangling::new(yokeable),
518            cart: (),
519        }
520    }
521
522    /// Obtain the yokeable out of a `Yoke<Y, ()>`
523    ///
524    /// For most `Yoke` types this would be unsafe but it's
525    /// fine for `Yoke<Y, ()>` since there are no actual internal
526    /// references
527    pub fn into_yokeable(self) -> Y {
528        // Safety note: since `yokeable` cannot reference data owned by `()`, this is certainly
529        // safe.
530        self.yokeable.into_inner()
531    }
532}
533
534// C does not need to be StableDeref here, if the yoke was constructed it's valid,
535// and new_owned() doesn't construct a yokeable that uses references,
536impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, Option<C>> {
537    /// Construct a new [`Yoke`] from static data. There will be no
538    /// references to `cart` here since [`Yokeable`]s are `'static`,
539    /// this is good for e.g. constructing fully owned
540    /// [`Yoke`]s with no internal borrowing.
541    ///
542    /// This can be paired with [`Yoke:: wrap_cart_in_option()`] to mix owned
543    /// and borrowed data.
544    ///
545    /// If you do not wish to pair this with borrowed data, [`Yoke::new_always_owned()`] can
546    /// be used to get a [`Yoke`] API on always-owned data.
547    ///
548    /// # Example
549    ///
550    /// ```rust
551    /// # use yoke::Yoke;
552    /// # use std::borrow::Cow;
553    /// # use std::rc::Rc;
554    ///
555    /// let owned: Cow<str> = "hello".to_owned().into();
556    /// // this yoke can be intermingled with actually-borrowed Yokes
557    /// let yoke: Yoke<Cow<str>, Option<Rc<[u8]>>> = Yoke::new_owned(owned);
558    ///
559    /// assert_eq!(yoke.get(), "hello");
560    /// ```
561    pub const fn new_owned(yokeable: Y) -> Self {
562        Self {
563            // Safety note: this `yokeable` is known not to borrow from the cart.
564            yokeable: KindaSortaDangling::new(yokeable),
565            cart: None,
566        }
567    }
568
569    /// Obtain the yokeable out of a `Yoke<Y, Option<C>>` if possible.
570    ///
571    /// If the cart is `None`, this returns `Ok`, but if the cart is `Some`,
572    /// this returns `self` as an error.
573    pub fn try_into_yokeable(self) -> Result<Y, Self> {
574        // Safety: if the cart is None there is no way for the yokeable to
575        // have references into it because of the cart invariant.
576        match self.cart {
577            Some(_) => Err(self),
578            None => Ok(self.yokeable.into_inner()),
579        }
580    }
581}
582
583impl<Y: for<'a> Yokeable<'a>, C: CartablePointerLike> Yoke<Y, Option<C>> {
584    /// Converts a `Yoke<Y, Option<C>>` to `Yoke<Y, CartableOptionPointer<C>>`
585    /// for better niche optimization when stored as a field.
586    ///
587    /// # Examples
588    ///
589    /// ```
590    /// use std::borrow::Cow;
591    /// use yoke::Yoke;
592    ///
593    /// let yoke: Yoke<Cow<[u8]>, Box<Vec<u8>>> =
594    ///     Yoke::attach_to_cart(vec![10, 20, 30].into(), |c| c.into());
595    ///
596    /// let yoke_option = yoke.wrap_cart_in_option();
597    /// let yoke_option_pointer = yoke_option.convert_cart_into_option_pointer();
598    /// ```
599    ///
600    /// The niche improves stack sizes:
601    ///
602    /// ```
603    /// use yoke::Yoke;
604    /// use yoke::cartable_ptr::CartableOptionPointer;
605    /// use std::mem::size_of;
606    /// use std::rc::Rc;
607    ///
608    /// // The data struct is 6 words:
609    /// # #[derive(yoke::Yokeable)]
610    /// # struct MyDataStruct<'a> {
611    /// #     _s: (usize, usize, usize, usize),
612    /// #     _p: &'a str,
613    /// # }
614    /// const W: usize = core::mem::size_of::<usize>();
615    /// assert_eq!(W * 6, size_of::<MyDataStruct>());
616    ///
617    /// // An enum containing the data struct with an `Option<Rc>` cart is 8 words:
618    /// enum StaticOrYoke1 {
619    ///     Static(&'static MyDataStruct<'static>),
620    ///     Yoke(Yoke<MyDataStruct<'static>, Option<Rc<String>>>),
621    /// }
622    /// assert_eq!(W * 8, size_of::<StaticOrYoke1>());
623    ///
624    /// // When using `CartableOptionPointer``, we need only 7 words for the same behavior:
625    /// enum StaticOrYoke2 {
626    ///     Static(&'static MyDataStruct<'static>),
627    ///     Yoke(Yoke<MyDataStruct<'static>, CartableOptionPointer<Rc<String>>>),
628    /// }
629    /// assert_eq!(W * 7, size_of::<StaticOrYoke2>());
630    /// ```
631    #[inline]
632    pub fn convert_cart_into_option_pointer(self) -> Yoke<Y, CartableOptionPointer<C>> {
633        match self.cart {
634            Some(cart) => Yoke {
635                // Safety note: CartableOptionPointer::from_cartable only wraps the `cart`,
636                // so the data referenced by the yokeable is still live.
637                yokeable: self.yokeable,
638                cart: CartableOptionPointer::from_cartable(cart),
639            },
640            None => Yoke {
641                // Safety note: this Yokeable cannot refer to any data since self.cart is None.
642                yokeable: self.yokeable,
643                cart: CartableOptionPointer::none(),
644            },
645        }
646    }
647}
648
649impl<Y: for<'a> Yokeable<'a>, C: CartablePointerLike> Yoke<Y, CartableOptionPointer<C>> {
650    /// Obtain the yokeable out of a `Yoke<Y, CartableOptionPointer<C>>` if possible.
651    ///
652    /// If the cart is `None`, this returns `Ok`, but if the cart is `Some`,
653    /// this returns `self` as an error.
654    #[inline]
655    pub fn try_into_yokeable(self) -> Result<Y, Self> {
656        if self.cart.is_none() {
657            Ok(self.yokeable.into_inner())
658        } else {
659            Err(self)
660        }
661    }
662}
663
664/// This trait marks cart types that do not change source on cloning
665///
666/// This is conceptually similar to [`stable_deref_trait::CloneStableDeref`],
667/// however [`stable_deref_trait::CloneStableDeref`] is not (and should not) be
668/// implemented on [`Option`] (since it's not [`Deref`]). [`CloneableCart`] essentially is
669/// "if there _is_ data to borrow from here, cloning the cart gives you an additional
670/// handle to the same data".
671///
672/// # Safety
673/// This trait is safe to implement on `StableDeref` types which, once `Clone`d, point to the same underlying data and retain ownership.
674///
675/// This trait can also be implemented on aggregates of such types like `Option<T: CloneableCart>` and `(T: CloneableCart, U: CloneableCart)`.
676///
677/// Essentially, all data that could be referenced by a Yokeable (i.e. data that is referenced via a StableDeref) must retain the same
678/// pointer and ownership semantics once cloned.
679pub unsafe trait CloneableCart: Clone {}
680
681#[cfg(feature = "alloc")]
682// Safety: Rc<T> implements CloneStableDeref.
683unsafe impl<T: ?Sized> CloneableCart for Rc<T> {}
684#[cfg(feature = "alloc")]
685// Safety: Arc<T> implements CloneStableDeref.
686unsafe impl<T: ?Sized> CloneableCart for Arc<T> {}
687// Safety: Option<T> cannot deref to anything that T doesn't already deref to.
688unsafe impl<T: CloneableCart> CloneableCart for Option<T> {}
689// Safety: &'a T is indeed StableDeref, and cloning it refers to the same data.
690// &'a T does not own in the first place, so ownership is preserved.
691unsafe impl<'a, T: ?Sized> CloneableCart for &'a T {}
692// Safety: () cannot deref to anything.
693unsafe impl CloneableCart for () {}
694
695/// Clone requires that the cart type `C` derefs to the same address after it is cloned. This works for
696/// Rc, Arc, and &'a T.
697///
698/// For other cart types, clone `.backing_cart()` and re-use `.attach_to_cart()`; however, doing
699/// so may lose mutations performed via `.with_mut()`.
700///
701/// Cloning a `Yoke` is often a cheap operation requiring no heap allocations, in much the same
702/// way that cloning an `Rc` is a cheap operation. However, if the `yokeable` contains owned data
703/// (e.g., from `.with_mut()`), that data will need to be cloned.
704impl<Y: for<'a> Yokeable<'a>, C: CloneableCart> Clone for Yoke<Y, C>
705where
706    for<'a> <Y as Yokeable<'a>>::Output: Clone,
707{
708    fn clone(&self) -> Self {
709        // We have an &T not a T, and we can clone T
710        let this = self.get().clone();
711        Yoke {
712            yokeable: KindaSortaDangling::new(
713                // Safety: C being a CloneableCart guarantees that the data referenced by the
714                // `yokeable` is kept alive by the clone of the cart.
715                unsafe { Y::make(this) },
716            ),
717            cart: self.cart.clone(),
718        }
719    }
720}
721
722#[test]
723fn test_clone() {
724    let local_data = "foo".to_owned();
725    let y1 = Yoke::<alloc::borrow::Cow<'static, str>, Rc<String>>::attach_to_zero_copy_cart(
726        Rc::new(local_data),
727    );
728
729    // Test basic clone
730    let y2 = y1.clone();
731    assert_eq!(y1.get(), "foo");
732    assert_eq!(y2.get(), "foo");
733
734    // Test clone with mutation on target
735    let mut y3 = y1.clone();
736    y3.with_mut(|y| {
737        y.to_mut().push_str("bar");
738    });
739    assert_eq!(y1.get(), "foo");
740    assert_eq!(y2.get(), "foo");
741    assert_eq!(y3.get(), "foobar");
742
743    // Test that mutations on source do not affect target
744    let y4 = y3.clone();
745    y3.with_mut(|y| {
746        y.to_mut().push_str("baz");
747    });
748    assert_eq!(y1.get(), "foo");
749    assert_eq!(y2.get(), "foo");
750    assert_eq!(y3.get(), "foobarbaz");
751    assert_eq!(y4.get(), "foobar");
752}
753
754impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
755    /// Allows one to "project" a yoke to perform a transformation on the data, potentially
756    /// looking at a subfield, and producing a new yoke. This will move cart, and the provided
757    /// transformation is only allowed to use data known to be borrowed from the cart.
758    ///
759    /// The callback takes an additional `PhantomData<&()>` parameter to anchor lifetimes
760    /// (see [#86702](https://github.com/rust-lang/rust/issues/86702)) This parameter
761    /// should just be ignored in the callback.
762    ///
763    /// This can be used, for example, to transform data from one format to another:
764    ///
765    /// ```
766    /// # use std::rc::Rc;
767    /// # use yoke::Yoke;
768    /// #
769    /// fn slice(y: Yoke<&'static str, Rc<[u8]>>) -> Yoke<&'static [u8], Rc<[u8]>> {
770    ///     y.map_project(move |yk, _| yk.as_bytes())
771    /// }
772    /// ```
773    ///
774    /// This can also be used to create a yoke for a subfield
775    ///
776    /// ```
777    /// # use yoke::{Yoke, Yokeable};
778    /// # use std::mem;
779    /// # use std::rc::Rc;
780    /// #
781    /// // also safely implements Yokeable<'a>
782    /// struct Bar<'a> {
783    ///     string_1: &'a str,
784    ///     string_2: &'a str,
785    /// }
786    ///
787    /// fn map_project_string_1(
788    ///     bar: Yoke<Bar<'static>, Rc<[u8]>>,
789    /// ) -> Yoke<&'static str, Rc<[u8]>> {
790    ///     bar.map_project(|bar, _| bar.string_1)
791    /// }
792    ///
793    /// #
794    /// # unsafe impl<'a> Yokeable<'a> for Bar<'static> {
795    /// #     type Output = Bar<'a>;
796    /// #     fn transform(&'a self) -> &'a Bar<'a> {
797    /// #         self
798    /// #     }
799    /// #
800    /// #     fn transform_owned(self) -> Bar<'a> {
801    /// #         // covariant lifetime cast, can be done safely
802    /// #         self
803    /// #     }
804    /// #
805    /// #     unsafe fn make(from: Bar<'a>) -> Self {
806    /// #         let ret = mem::transmute_copy(&from);
807    /// #         mem::forget(from);
808    /// #         ret
809    /// #     }
810    /// #
811    /// #     fn transform_mut<F>(&'a mut self, f: F)
812    /// #     where
813    /// #         F: 'static + FnOnce(&'a mut Self::Output),
814    /// #     {
815    /// #         unsafe { f(mem::transmute(self)) }
816    /// #     }
817    /// # }
818    /// ```
819    //
820    // Safety docs can be found at the end of the file.
821    pub fn map_project<P, F>(self, f: F) -> Yoke<P, C>
822    where
823        P: for<'a> Yokeable<'a>,
824        F: for<'a> FnOnce(
825            <Y as Yokeable<'a>>::Output,
826            PhantomData<&'a ()>,
827        ) -> <P as Yokeable<'a>>::Output,
828    {
829        let p = f(self.yokeable.into_inner().transform_owned(), PhantomData);
830        Yoke {
831            yokeable: KindaSortaDangling::new(
832                // Safety: the resulting `yokeable` is dropped before the `cart` because
833                // of the Yoke invariant. See the safety docs below for the justification of why
834                // yokeable could only borrow from the Cart.
835                unsafe { P::make(p) },
836            ),
837            cart: self.cart,
838        }
839    }
840
841    /// This is similar to [`Yoke::map_project`], however it does not move
842    /// [`Self`] and instead clones the cart (only if the cart is a [`CloneableCart`])
843    ///
844    /// This is a bit more efficient than cloning the [`Yoke`] and then calling [`Yoke::map_project`]
845    /// because then it will not clone fields that are going to be discarded.
846    pub fn map_project_cloned<'this, P, F>(&'this self, f: F) -> Yoke<P, C>
847    where
848        P: for<'a> Yokeable<'a>,
849        C: CloneableCart,
850        F: for<'a> FnOnce(
851            &'this <Y as Yokeable<'a>>::Output,
852            PhantomData<&'a ()>,
853        ) -> <P as Yokeable<'a>>::Output,
854    {
855        let p = f(self.get(), PhantomData);
856        Yoke {
857            yokeable: KindaSortaDangling::new(
858                // Safety: the resulting `yokeable` is dropped before the `cart` because
859                // of the Yoke invariant. See the safety docs below for the justification of why
860                // yokeable could only borrow from the Cart.
861                unsafe { P::make(p) },
862            ),
863            cart: self.cart.clone(),
864        }
865    }
866
867    /// This is similar to [`Yoke::map_project`], however it can also bubble up an error
868    /// from the callback.
869    ///
870    /// ```
871    /// # use std::rc::Rc;
872    /// # use yoke::Yoke;
873    /// # use std::str::{self, Utf8Error};
874    /// #
875    /// fn slice(
876    ///     y: Yoke<&'static [u8], Rc<[u8]>>,
877    /// ) -> Result<Yoke<&'static str, Rc<[u8]>>, Utf8Error> {
878    ///     y.try_map_project(move |bytes, _| str::from_utf8(bytes))
879    /// }
880    /// ```
881    ///
882    /// This can also be used to create a yoke for a subfield
883    ///
884    /// ```
885    /// # use yoke::{Yoke, Yokeable};
886    /// # use std::mem;
887    /// # use std::rc::Rc;
888    /// # use std::str::{self, Utf8Error};
889    /// #
890    /// // also safely implements Yokeable<'a>
891    /// struct Bar<'a> {
892    ///     bytes_1: &'a [u8],
893    ///     string_2: &'a str,
894    /// }
895    ///
896    /// fn map_project_string_1(
897    ///     bar: Yoke<Bar<'static>, Rc<[u8]>>,
898    /// ) -> Result<Yoke<&'static str, Rc<[u8]>>, Utf8Error> {
899    ///     bar.try_map_project(|bar, _| str::from_utf8(bar.bytes_1))
900    /// }
901    ///
902    /// #
903    /// # unsafe impl<'a> Yokeable<'a> for Bar<'static> {
904    /// #     type Output = Bar<'a>;
905    /// #     fn transform(&'a self) -> &'a Bar<'a> {
906    /// #         self
907    /// #     }
908    /// #
909    /// #     fn transform_owned(self) -> Bar<'a> {
910    /// #         // covariant lifetime cast, can be done safely
911    /// #         self
912    /// #     }
913    /// #
914    /// #     unsafe fn make(from: Bar<'a>) -> Self {
915    /// #         let ret = mem::transmute_copy(&from);
916    /// #         mem::forget(from);
917    /// #         ret
918    /// #     }
919    /// #
920    /// #     fn transform_mut<F>(&'a mut self, f: F)
921    /// #     where
922    /// #         F: 'static + FnOnce(&'a mut Self::Output),
923    /// #     {
924    /// #         unsafe { f(mem::transmute(self)) }
925    /// #     }
926    /// # }
927    /// ```
928    pub fn try_map_project<P, F, E>(self, f: F) -> Result<Yoke<P, C>, E>
929    where
930        P: for<'a> Yokeable<'a>,
931        F: for<'a> FnOnce(
932            <Y as Yokeable<'a>>::Output,
933            PhantomData<&'a ()>,
934        ) -> Result<<P as Yokeable<'a>>::Output, E>,
935    {
936        let p = f(self.yokeable.into_inner().transform_owned(), PhantomData)?;
937        Ok(Yoke {
938            yokeable: KindaSortaDangling::new(
939                // Safety: the resulting `yokeable` is dropped before the `cart` because
940                // of the Yoke invariant. See the safety docs below for the justification of why
941                // yokeable could only borrow from the Cart.
942                unsafe { P::make(p) },
943            ),
944            cart: self.cart,
945        })
946    }
947
948    /// This is similar to [`Yoke::try_map_project`], however it does not move
949    /// [`Self`] and instead clones the cart (only if the cart is a [`CloneableCart`])
950    ///
951    /// This is a bit more efficient than cloning the [`Yoke`] and then calling [`Yoke::map_project`]
952    /// because then it will not clone fields that are going to be discarded.
953    pub fn try_map_project_cloned<'this, P, F, E>(&'this self, f: F) -> Result<Yoke<P, C>, E>
954    where
955        P: for<'a> Yokeable<'a>,
956        C: CloneableCart,
957        F: for<'a> FnOnce(
958            &'this <Y as Yokeable<'a>>::Output,
959            PhantomData<&'a ()>,
960        ) -> Result<<P as Yokeable<'a>>::Output, E>,
961    {
962        let p = f(self.get(), PhantomData)?;
963        Ok(Yoke {
964            yokeable: KindaSortaDangling::new(
965                // Safety: the resulting `yokeable` is dropped before the `cart` because
966                // of the Yoke invariant. See the safety docs below for the justification of why
967                // yokeable could only borrow from the Cart.
968                unsafe { P::make(p) },
969            ),
970            cart: self.cart.clone(),
971        })
972    }
973    /// This is similar to [`Yoke::map_project`], but it works around older versions
974    /// of Rust not being able to use `FnOnce` by using an explicit capture input.
975    /// See [#1061](https://github.com/unicode-org/icu4x/issues/1061).
976    ///
977    /// See the docs of [`Yoke::map_project`] for how this works.
978    pub fn map_project_with_explicit_capture<P, T>(
979        self,
980        capture: T,
981        f: for<'a> fn(
982            <Y as Yokeable<'a>>::Output,
983            capture: T,
984            PhantomData<&'a ()>,
985        ) -> <P as Yokeable<'a>>::Output,
986    ) -> Yoke<P, C>
987    where
988        P: for<'a> Yokeable<'a>,
989    {
990        let p = f(
991            self.yokeable.into_inner().transform_owned(),
992            capture,
993            PhantomData,
994        );
995        Yoke {
996            yokeable: KindaSortaDangling::new(
997                // Safety: the resulting `yokeable` is dropped before the `cart` because
998                // of the Yoke invariant. See the safety docs below for the justification of why
999                // yokeable could only borrow from the Cart.
1000                unsafe { P::make(p) },
1001            ),
1002            cart: self.cart,
1003        }
1004    }
1005
1006    /// This is similar to [`Yoke::map_project_cloned`], but it works around older versions
1007    /// of Rust not being able to use `FnOnce` by using an explicit capture input.
1008    /// See [#1061](https://github.com/unicode-org/icu4x/issues/1061).
1009    ///
1010    /// See the docs of [`Yoke::map_project_cloned`] for how this works.
1011    pub fn map_project_cloned_with_explicit_capture<'this, P, T>(
1012        &'this self,
1013        capture: T,
1014        f: for<'a> fn(
1015            &'this <Y as Yokeable<'a>>::Output,
1016            capture: T,
1017            PhantomData<&'a ()>,
1018        ) -> <P as Yokeable<'a>>::Output,
1019    ) -> Yoke<P, C>
1020    where
1021        P: for<'a> Yokeable<'a>,
1022        C: CloneableCart,
1023    {
1024        let p = f(self.get(), capture, PhantomData);
1025        Yoke {
1026            yokeable: KindaSortaDangling::new(
1027                // Safety: the resulting `yokeable` is dropped before the `cart` because
1028                // of the Yoke invariant. See the safety docs below for the justification of why
1029                // yokeable could only borrow from the Cart.
1030                unsafe { P::make(p) },
1031            ),
1032            cart: self.cart.clone(),
1033        }
1034    }
1035
1036    /// This is similar to [`Yoke::try_map_project`], but it works around older versions
1037    /// of Rust not being able to use `FnOnce` by using an explicit capture input.
1038    /// See [#1061](https://github.com/unicode-org/icu4x/issues/1061).
1039    ///
1040    /// See the docs of [`Yoke::try_map_project`] for how this works.
1041    #[allow(clippy::type_complexity)]
1042    pub fn try_map_project_with_explicit_capture<P, T, E>(
1043        self,
1044        capture: T,
1045        f: for<'a> fn(
1046            <Y as Yokeable<'a>>::Output,
1047            capture: T,
1048            PhantomData<&'a ()>,
1049        ) -> Result<<P as Yokeable<'a>>::Output, E>,
1050    ) -> Result<Yoke<P, C>, E>
1051    where
1052        P: for<'a> Yokeable<'a>,
1053    {
1054        let p = f(
1055            self.yokeable.into_inner().transform_owned(),
1056            capture,
1057            PhantomData,
1058        )?;
1059        Ok(Yoke {
1060            yokeable: KindaSortaDangling::new(
1061                // Safety: the resulting `yokeable` is dropped before the `cart` because
1062                // of the Yoke invariant. See the safety docs below for the justification of why
1063                // yokeable could only borrow from the Cart.
1064                unsafe { P::make(p) },
1065            ),
1066            cart: self.cart,
1067        })
1068    }
1069
1070    /// This is similar to [`Yoke::try_map_project_cloned`], but it works around older versions
1071    /// of Rust not being able to use `FnOnce` by using an explicit capture input.
1072    /// See [#1061](https://github.com/unicode-org/icu4x/issues/1061).
1073    ///
1074    /// See the docs of [`Yoke::try_map_project_cloned`] for how this works.
1075    #[allow(clippy::type_complexity)]
1076    pub fn try_map_project_cloned_with_explicit_capture<'this, P, T, E>(
1077        &'this self,
1078        capture: T,
1079        f: for<'a> fn(
1080            &'this <Y as Yokeable<'a>>::Output,
1081            capture: T,
1082            PhantomData<&'a ()>,
1083        ) -> Result<<P as Yokeable<'a>>::Output, E>,
1084    ) -> Result<Yoke<P, C>, E>
1085    where
1086        P: for<'a> Yokeable<'a>,
1087        C: CloneableCart,
1088    {
1089        let p = f(self.get(), capture, PhantomData)?;
1090        Ok(Yoke {
1091            yokeable: KindaSortaDangling::new(
1092                // Safety: the resulting `yokeable` is dropped before the `cart` because
1093                // of the Yoke invariant. See the safety docs below for the justification of why
1094                // yokeable could only borrow from the Cart.
1095                unsafe { P::make(p) },
1096            ),
1097            cart: self.cart.clone(),
1098        })
1099    }
1100}
1101
1102#[cfg(feature = "alloc")]
1103impl<Y: for<'a> Yokeable<'a>, C: 'static + Sized> Yoke<Y, Rc<C>> {
1104    /// Allows type-erasing the cart in a `Yoke<Y, Rc<C>>`.
1105    ///
1106    /// The yoke only carries around a cart type `C` for its destructor,
1107    /// since it needs to be able to guarantee that its internal references
1108    /// are valid for the lifetime of the Yoke. As such, the actual type of the
1109    /// Cart is not very useful unless you wish to extract data out of it
1110    /// via [`Yoke::backing_cart()`]. Erasing the cart allows for one to mix
1111    /// [`Yoke`]s obtained from different sources.
1112    ///
1113    /// In case the cart type `C` is not already an `Rc<T>`, you can use
1114    /// [`Yoke::wrap_cart_in_rc()`] to wrap it.
1115    ///
1116    /// ✨ *Enabled with the `alloc` Cargo feature.*
1117    ///
1118    /// # Example
1119    ///
1120    /// ```rust
1121    /// use std::rc::Rc;
1122    /// use yoke::erased::ErasedRcCart;
1123    /// use yoke::Yoke;
1124    ///
1125    /// let buffer1: Rc<String> = Rc::new("   foo bar baz  ".into());
1126    /// let buffer2: Box<String> = Box::new("  baz quux  ".into());
1127    ///
1128    /// let yoke1 =
1129    ///     Yoke::<&'static str, _>::attach_to_cart(buffer1, |rc| rc.trim());
1130    /// let yoke2 = Yoke::<&'static str, _>::attach_to_cart(buffer2, |b| b.trim());
1131    ///
1132    /// let erased1: Yoke<_, ErasedRcCart> = yoke1.erase_rc_cart();
1133    /// // Wrap the Box in an Rc to make it compatible
1134    /// let erased2: Yoke<_, ErasedRcCart> =
1135    ///     yoke2.wrap_cart_in_rc().erase_rc_cart();
1136    ///
1137    /// // Now erased1 and erased2 have the same type!
1138    /// ```
1139    pub fn erase_rc_cart(self) -> Yoke<Y, ErasedRcCart> {
1140        // Safety: safe because the cart is preserved, as it is just type-erased
1141        unsafe { self.replace_cart(|c| c as ErasedRcCart) }
1142    }
1143}
1144
1145#[cfg(feature = "alloc")]
1146impl<Y: for<'a> Yokeable<'a>, C: 'static + Sized + Send + Sync> Yoke<Y, Arc<C>> {
1147    /// Allows type-erasing the cart in a `Yoke<Y, Arc<C>>`.
1148    ///
1149    /// The yoke only carries around a cart type `C` for its destructor,
1150    /// since it needs to be able to guarantee that its internal references
1151    /// are valid for the lifetime of the Yoke. As such, the actual type of the
1152    /// Cart is not very useful unless you wish to extract data out of it
1153    /// via [`Yoke::backing_cart()`]. Erasing the cart allows for one to mix
1154    /// [`Yoke`]s obtained from different sources.
1155    ///
1156    /// In case the cart type `C` is not already an `Arc<T>`, you can use
1157    /// [`Yoke::wrap_cart_in_arc()`] to wrap it.
1158    ///
1159    /// ✨ *Enabled with the `alloc` Cargo feature.*
1160    ///
1161    /// # Example
1162    ///
1163    /// ```rust
1164    /// use std::sync::Arc;
1165    /// use yoke::erased::ErasedArcCart;
1166    /// use yoke::Yoke;
1167    ///
1168    /// let buffer1: Arc<String> = Arc::new("   foo bar baz  ".into());
1169    /// let buffer2: Box<String> = Box::new("  baz quux  ".into());
1170    ///
1171    /// let yoke1 =
1172    ///     Yoke::<&'static str, _>::attach_to_cart(buffer1, |arc| arc.trim());
1173    /// let yoke2 = Yoke::<&'static str, _>::attach_to_cart(buffer2, |b| b.trim());
1174    ///
1175    /// let erased1: Yoke<_, ErasedArcCart> = yoke1.erase_arc_cart();
1176    /// // Wrap the Box in an Rc to make it compatible
1177    /// let erased2: Yoke<_, ErasedArcCart> =
1178    ///     yoke2.wrap_cart_in_arc().erase_arc_cart();
1179    ///
1180    /// // Now erased1 and erased2 have the same type!
1181    /// ```
1182    pub fn erase_arc_cart(self) -> Yoke<Y, ErasedArcCart> {
1183        // Safety: safe because the cart is preserved, as it is just type-erased
1184        unsafe { self.replace_cart(|c| c as ErasedArcCart) }
1185    }
1186}
1187
1188#[cfg(feature = "alloc")]
1189impl<Y: for<'a> Yokeable<'a>, C: 'static + Sized> Yoke<Y, Box<C>> {
1190    /// Allows type-erasing the cart in a `Yoke<Y, Box<C>>`.
1191    ///
1192    /// The yoke only carries around a cart type `C` for its destructor,
1193    /// since it needs to be able to guarantee that its internal references
1194    /// are valid for the lifetime of the Yoke. As such, the actual type of the
1195    /// Cart is not very useful unless you wish to extract data out of it
1196    /// via [`Yoke::backing_cart()`]. Erasing the cart allows for one to mix
1197    /// [`Yoke`]s obtained from different sources.
1198    ///
1199    /// In case the cart type `C` is not already `Box<T>`, you can use
1200    /// [`Yoke::wrap_cart_in_box()`] to wrap it.
1201    ///
1202    /// ✨ *Enabled with the `alloc` Cargo feature.*
1203    ///
1204    /// # Example
1205    ///
1206    /// ```rust
1207    /// use std::rc::Rc;
1208    /// use yoke::erased::ErasedBoxCart;
1209    /// use yoke::Yoke;
1210    ///
1211    /// let buffer1: Rc<String> = Rc::new("   foo bar baz  ".into());
1212    /// let buffer2: Box<String> = Box::new("  baz quux  ".into());
1213    ///
1214    /// let yoke1 =
1215    ///     Yoke::<&'static str, _>::attach_to_cart(buffer1, |rc| rc.trim());
1216    /// let yoke2 = Yoke::<&'static str, _>::attach_to_cart(buffer2, |b| b.trim());
1217    ///
1218    /// // Wrap the Rc in an Box to make it compatible
1219    /// let erased1: Yoke<_, ErasedBoxCart> =
1220    ///     yoke1.wrap_cart_in_box().erase_box_cart();
1221    /// let erased2: Yoke<_, ErasedBoxCart> = yoke2.erase_box_cart();
1222    ///
1223    /// // Now erased1 and erased2 have the same type!
1224    /// ```
1225    pub fn erase_box_cart(self) -> Yoke<Y, ErasedBoxCart> {
1226        // Safety: safe because the cart is preserved, as it is just type-erased
1227        unsafe { self.replace_cart(|c| c as ErasedBoxCart) }
1228    }
1229}
1230
1231#[cfg(feature = "alloc")]
1232impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
1233    /// Helper function allowing one to wrap the cart type `C` in a `Box<T>`.
1234    /// Can be paired with [`Yoke::erase_box_cart()`]
1235    ///
1236    /// ✨ *Enabled with the `alloc` Cargo feature.*
1237    #[inline]
1238    pub fn wrap_cart_in_box(self) -> Yoke<Y, Box<C>> {
1239        // Safety: safe because the cart is preserved, as it is just wrapped.
1240        unsafe { self.replace_cart(Box::new) }
1241    }
1242    /// Helper function allowing one to wrap the cart type `C` in an `Rc<T>`.
1243    /// Can be paired with [`Yoke::erase_rc_cart()`], or generally used
1244    /// to make the [`Yoke`] cloneable.
1245    ///
1246    /// ✨ *Enabled with the `alloc` Cargo feature.*
1247    #[inline]
1248    pub fn wrap_cart_in_rc(self) -> Yoke<Y, Rc<C>> {
1249        // Safety: safe because the cart is preserved, as it is just wrapped
1250        unsafe { self.replace_cart(Rc::new) }
1251    }
1252    /// Helper function allowing one to wrap the cart type `C` in an `Rc<T>`.
1253    /// Can be paired with [`Yoke::erase_arc_cart()`], or generally used
1254    /// to make the [`Yoke`] cloneable.
1255    ///
1256    /// ✨ *Enabled with the `alloc` Cargo feature.*
1257    #[inline]
1258    pub fn wrap_cart_in_arc(self) -> Yoke<Y, Arc<C>> {
1259        // Safety: safe because the cart is preserved, as it is just wrapped
1260        unsafe { self.replace_cart(Arc::new) }
1261    }
1262}
1263
1264impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
1265    /// Helper function allowing one to wrap the cart type `C` in an [`EitherCart`].
1266    ///
1267    /// This function wraps the cart into the `A` variant. To wrap it into the
1268    /// `B` variant, use [`Self::wrap_cart_in_either_b()`].
1269    ///
1270    /// For an example, see [`EitherCart`].
1271    #[inline]
1272    pub fn wrap_cart_in_either_a<B>(self) -> Yoke<Y, EitherCart<C, B>> {
1273        // Safety: safe because the cart is preserved, as it is just wrapped.
1274        unsafe { self.replace_cart(EitherCart::A) }
1275    }
1276    /// Helper function allowing one to wrap the cart type `C` in an [`EitherCart`].
1277    ///
1278    /// This function wraps the cart into the `B` variant. To wrap it into the
1279    /// `A` variant, use [`Self::wrap_cart_in_either_a()`].
1280    ///
1281    /// For an example, see [`EitherCart`].
1282    #[inline]
1283    pub fn wrap_cart_in_either_b<A>(self) -> Yoke<Y, EitherCart<A, C>> {
1284        // Safety: safe because the cart is preserved, as it is just wrapped.
1285        unsafe { self.replace_cart(EitherCart::B) }
1286    }
1287}
1288
1289/// # Safety docs for project()
1290///
1291/// (Docs are on a private const to allow the use of compile_fail doctests)
1292///
1293/// This is safe to perform because of the choice of lifetimes on `f`, that is,
1294/// `for<a> fn(<Y as Yokeable<'a>>::Output, &'a ()) -> <P as Yokeable<'a>>::Output`.
1295///
1296/// Note that correctness arguments are similar if you replace `fn` with `FnOnce`.
1297///
1298/// What we want this function to do is take a Yokeable (`Y`) that is borrowing from the cart, and
1299/// produce another Yokeable (`P`) that also borrows from the same cart. There are a couple potential
1300/// hazards here:
1301///
1302/// - `P` ends up borrowing data from `Y` (or elsewhere) that did _not_ come from the cart,
1303///   for example `P` could borrow owned data from a `Cow`. This would make the `Yoke<P>` dependent
1304///   on data owned only by the `Yoke<Y>`.
1305/// - Borrowed data from `Y` escapes with the wrong lifetime
1306///
1307/// Let's walk through these and see how they're prevented.
1308///
1309/// ```rust, compile_fail
1310/// # use std::rc::Rc;
1311/// # use yoke::Yoke;
1312/// # use std::borrow::Cow;
1313/// fn borrow_potentially_owned(y: &Yoke<Cow<'static, str>, Rc<[u8]>>) -> Yoke<&'static str, Rc<[u8]>> {
1314///    y.map_project_cloned(|cow, _| &*cow)   
1315/// }
1316/// ```
1317///
1318/// In this case, the lifetime of `&*cow` is `&'this str`, however the function needs to be able to return
1319/// `&'a str` _for all `'a`_, which isn't possible.
1320///
1321///
1322/// ```rust, compile_fail
1323/// # use std::rc::Rc;
1324/// # use yoke::Yoke;
1325/// # use std::borrow::Cow;
1326/// fn borrow_potentially_owned(y: Yoke<Cow<'static, str>, Rc<[u8]>>) -> Yoke<&'static str, Rc<[u8]>> {
1327///    y.map_project(|cow, _| &*cow)   
1328/// }
1329/// ```
1330///
1331/// This has the same issue, `&*cow` is borrowing for a local lifetime.
1332///
1333/// Similarly, trying to project an owned field of a struct will produce similar errors:
1334///
1335/// ```rust,compile_fail
1336/// # use std::borrow::Cow;
1337/// # use yoke::{Yoke, Yokeable};
1338/// # use std::mem;
1339/// # use std::rc::Rc;
1340/// #
1341/// // also safely implements Yokeable<'a>
1342/// struct Bar<'a> {
1343///     owned: String,
1344///     string_2: &'a str,
1345/// }
1346///
1347/// fn map_project_owned(bar: &Yoke<Bar<'static>, Rc<[u8]>>) -> Yoke<&'static str, Rc<[u8]>> {
1348///     // ERROR (but works if you replace owned with string_2)
1349///     bar.map_project_cloned(|bar, _| &*bar.owned)   
1350/// }
1351///
1352/// #
1353/// # unsafe impl<'a> Yokeable<'a> for Bar<'static> {
1354/// #     type Output = Bar<'a>;
1355/// #     fn transform(&'a self) -> &'a Bar<'a> {
1356/// #         self
1357/// #     }
1358/// #
1359/// #     fn transform_owned(self) -> Bar<'a> {
1360/// #         // covariant lifetime cast, can be done safely
1361/// #         self
1362/// #     }
1363/// #
1364/// #     unsafe fn make(from: Bar<'a>) -> Self {
1365/// #         let ret = mem::transmute_copy(&from);
1366/// #         mem::forget(from);
1367/// #         ret
1368/// #     }
1369/// #
1370/// #     fn transform_mut<F>(&'a mut self, f: F)
1371/// #     where
1372/// #         F: 'static + FnOnce(&'a mut Self::Output),
1373/// #     {
1374/// #         unsafe { f(mem::transmute(self)) }
1375/// #     }
1376/// # }
1377/// ```
1378///
1379/// Borrowed data from `Y` similarly cannot escape with the wrong lifetime because of the `for<'a>`, since
1380/// it will never be valid for the borrowed data to escape for all lifetimes of 'a. Internally, `.project()`
1381/// uses `.get()`, however the signature forces the callers to be able to handle every lifetime.
1382///
1383///  `'a` is the only lifetime that matters here; `Yokeable`s must be `'static` and since
1384/// `Output` is an associated type it can only have one lifetime, `'a` (there's nowhere for it to get another from).
1385/// `Yoke`s can get additional lifetimes via the cart, and indeed, `project()` can operate on `Yoke<_, &'b [u8]>`,
1386/// however this lifetime is inaccessible to the closure, and even if it were accessible the `for<'a>` would force
1387/// it out of the output. All external lifetimes (from other found outside the yoke/closures
1388/// are similarly constrained here.
1389///
1390/// Essentially, safety is achieved by using `for<'a> fn(...)` with `'a` used in both `Yokeable`s to ensure that
1391/// the output yokeable can _only_ have borrowed data flow in to it from the input. All paths of unsoundness require the
1392/// unification of an existential and universal lifetime, which isn't possible.
1393const _: () = ();
1394
1395/// # Safety docs for attach_to_cart()'s signature
1396///
1397/// The `attach_to_cart()` family of methods get by by using the following bound:
1398///
1399/// ```rust,ignore
1400/// F: for<'de> FnOnce(&'de <C as Deref>::Target) -> <Y as Yokeable<'de>>::Output,
1401/// C::Target: 'static
1402/// ```
1403///
1404/// to enforce that the yoking closure produces a yokeable that is *only* allowed to borrow from the cart.
1405/// A way to be sure of this is as follows: imagine if `F` *did* borrow data of lifetime `'a` and stuff it in
1406/// its output. Then that lifetime `'a` would have to live at least as long as `'de` *for all `'de`*.
1407/// The only lifetime that satisfies that is `'static` (since at least one of the potential `'de`s is `'static`),
1408/// and we're fine with that.
1409///
1410/// ## Implied bounds and variance
1411///
1412/// The `C::Target: 'static` bound is tricky, however. Let's imagine a situation where we *didn't* have that bound.
1413///
1414/// One thing to remember is that we are okay with the cart itself borrowing from places,
1415/// e.g. `&[u8]` is a valid cart, as is `Box<&[u8]>`. `C` is not `'static`.
1416///
1417/// (I'm going to use `CT` in prose to refer to `C::Target` here, since almost everything here has to do
1418/// with C::Target and not C itself.)
1419///
1420/// Unfortunately, there's a sneaky additional bound inside `F`. The signature of `F` is *actually*
1421///
1422/// ```rust,ignore
1423/// F: for<'de> where<C::Target: 'de> FnOnce(&'de C::Target) -> <Y as Yokeable<'de>>::Output
1424/// ```
1425///
1426/// using made-up "where clause inside HRTB" syntax to represent a type that can be represented inside the compiler
1427/// and type system but not in Rust code. The `CT: 'de` bond comes from the `&'de C::Target`: any time you
1428/// write `&'a T`, an implied bound of `T: 'a` materializes and is stored alongside it, since references cannot refer
1429/// to data that itself refers to data of shorter lifetimes. If a reference is valid, its referent must be valid for
1430/// the duration of the reference's lifetime, so every reference *inside* its referent must also be valid, giving us `T: 'a`.
1431/// This kind of constraint is often called a "well formedness" constraint: `&'a T` is not "well formed" without that
1432/// bound, and rustc is being helpful by giving it to us for free.
1433///
1434/// Unfortunately, this messes with our universal quantification. The `for<'de>` is no longer "For all lifetimes `'de`",
1435/// it is "for all lifetimes `'de` *where `CT: 'de`*". And if `CT` borrows from somewhere (with lifetime `'ct`), then we get a
1436/// `'ct: 'de` bound, and `'de` candidates that live longer than `'ct` won't actually be considered.
1437/// The neat little logic at the beginning stops working.
1438///
1439/// `attach_to_cart()` will instead enforce that the produced yokeable *either* borrows from the cart (fine), or from
1440/// data that has a lifetime that is at least `'ct`. Which means that `attach_to_cart()` will allow us to borrow locals
1441/// provided they live at least as long as `'ct`.
1442///
1443/// Is this a problem?
1444///
1445/// This is totally fine if CT's lifetime is covariant: if C is something like `Box<&'ct [u8]>`, even if our
1446/// yoked object borrows from locals outliving `'ct`, our Yoke can't outlive that
1447/// lifetime `'ct` anyway (since it's a part of the cart type), so we're fine.
1448///
1449/// However it's completely broken for contravariant carts (e.g. `Box<fn(&'ct u8)>`). In that case
1450/// we still get `'ct: 'de`, and we still end up being able to
1451/// borrow from locals that outlive `'ct`. However, our Yoke _can_ outlive
1452/// that lifetime, because Yoke shares its variance over `'ct`
1453/// with the cart type, and the cart type is contravariant over `'ct`.
1454/// So the Yoke can be upcast to having a longer lifetime than `'ct`, and *that* Yoke
1455/// can outlive `'ct`.
1456///
1457/// We fix this by forcing `C::Target: 'static` in `attach_to_cart()`, which would make it work
1458/// for fewer types, but would also allow Yoke to continue to be covariant over cart lifetimes if necessary.
1459///
1460/// An alternate fix would be to not allowing yoke to ever be upcast over lifetimes contained in the cart
1461/// by forcing them to be invariant. This is a bit more restrictive and affects *all* `Yoke` users, not just
1462/// those using `attach_to_cart()`.
1463///
1464/// See https://github.com/unicode-org/icu4x/issues/2926
1465/// See also https://github.com/rust-lang/rust/issues/106431 for potentially fixing this upstream by
1466/// changing how the bound works.
1467///
1468/// # Tests
1469///
1470/// Here's a broken `attach_to_cart()` that attempts to borrow from a local:
1471///
1472/// ```rust,compile_fail
1473/// use yoke::Yoke;
1474///
1475/// let cart = vec![1, 2, 3, 4].into_boxed_slice();
1476/// let local = vec![4, 5, 6, 7];
1477/// let yoke: Yoke<&[u8], Box<[u8]>> = Yoke::attach_to_cart(cart, |_| &*local);
1478/// ```
1479///
1480/// Fails as expected.
1481///
1482/// And here's a working one with a local borrowed cart that does not do any sneaky borrows whilst attaching.
1483///
1484/// ```rust
1485/// use yoke::Yoke;
1486///
1487/// let cart = vec![1, 2, 3, 4].into_boxed_slice();
1488/// let local = vec![4, 5, 6, 7];
1489/// let yoke: Yoke<&[u8], &[u8]> = Yoke::attach_to_cart(&cart, |c| &*c);
1490/// ```
1491///
1492/// Here's an `attach_to_cart()` that attempts to borrow from a longer-lived local due to
1493/// the cart being covariant. It fails, but would not if the alternate fix of forcing Yoke to be invariant
1494/// were implemented. It is technically a safe operation:
1495///
1496/// ```rust,compile_fail
1497/// use yoke::Yoke;
1498/// // longer lived
1499/// let local = vec![4, 5, 6, 7];
1500///
1501/// let backing = vec![1, 2, 3, 4];
1502/// let cart = Box::new(&*backing);
1503///
1504/// let yoke: Yoke<&[u8], Box<&[u8]>> = Yoke::attach_to_cart(cart, |_| &*local);
1505/// println!("{:?}", yoke.get());
1506/// ```
1507///
1508/// Finally, here's an `attach_to_cart()` that attempts to borrow from a longer lived local
1509/// in the case of a contravariant lifetime. It does not compile, but in and of itself is not dangerous:
1510///
1511/// ```rust,compile_fail
1512/// use yoke::Yoke;
1513///
1514/// type Contra<'a> = fn(&'a ());
1515///
1516/// let local = String::from("Hello World!");
1517/// let yoke: Yoke<&'static str, Box<Contra<'_>>> = Yoke::attach_to_cart(Box::new((|_| {}) as _), |_| &local[..]);
1518/// println!("{:?}", yoke.get());
1519/// ```
1520///
1521/// It is dangerous if allowed to transform (testcase from #2926)
1522///
1523/// ```rust,compile_fail
1524/// use yoke::Yoke;
1525///
1526/// type Contra<'a> = fn(&'a ());
1527///
1528///
1529/// let local = String::from("Hello World!");
1530/// let yoke: Yoke<&'static str, Box<Contra<'_>>> = Yoke::attach_to_cart(Box::new((|_| {}) as _), |_| &local[..]);
1531/// println!("{:?}", yoke.get());
1532/// let yoke_longer: Yoke<&'static str, Box<Contra<'static>>> = yoke;
1533/// let leaked: &'static Yoke<&'static str, Box<Contra<'static>>> = Box::leak(Box::new(yoke_longer));
1534/// let reference: &'static str = leaked.get();
1535///
1536/// println!("pre-drop: {reference}");
1537/// drop(local);
1538/// println!("post-drop: {reference}");
1539/// ```
1540const _: () = ();