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