Skip to main content

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::utils;
11use crate::Yokeable;
12use core::marker::PhantomData;
13use core::mem::ManuallyDrop;
14use core::ops::Deref;
15use stable_deref_trait::StableDeref;
16
17#[cfg(feature = "alloc")]
18use alloc::boxed::Box;
19#[cfg(feature = "alloc")]
20use alloc::rc::Rc;
21#[cfg(feature = "alloc")]
22use alloc::sync::Arc;
23
24/// A Cow-like borrowed object "yoked" to its backing data.
25///
26/// This allows things like zero copy deserialized data to carry around
27/// shared references to their backing buffer, by "erasing" their static lifetime
28/// and turning it into a dynamically managed one.
29///
30/// `Y` (the [`Yokeable`]) is the object containing the references,
31/// and will typically be of the form `Foo<'static>`. The `'static` is
32/// not the actual lifetime of the data, rather it is a convenient way to mark the
33/// erased lifetime and make it dynamic.
34///
35/// `C` is the "cart", which `Y` may contain references to. After the yoke is constructed,
36/// the cart serves little purpose except to guarantee that `Y`'s references remain valid
37/// for as long as the yoke remains in memory (by calling the destructor at the appropriate moment).
38///
39/// The primary constructor for [`Yoke`] is [`Yoke::attach_to_cart()`]. Several variants of that
40/// constructor are provided to serve numerous types of call sites and `Yoke` signatures.
41///
42/// The key behind this type is [`Yoke::get()`], where calling [`.get()`][Yoke::get] on a type like
43/// `Yoke<Cow<'static, str>, _>` will get you a short-lived `&'a Cow<'a, str>`, restricted to the
44/// lifetime of the borrow used during `.get()`. This is entirely safe since the `Cow` borrows from
45/// the cart type `C`, which cannot be interfered with as long as the `Yoke` is borrowed by `.get
46/// ()`. `.get()` protects access by essentially reifying the erased lifetime to a safe local one
47/// when necessary.
48///
49/// Furthermore, there are various [`.map_project()`][Yoke::map_project] methods that allow turning a `Yoke`
50/// into another `Yoke` containing a different type that may contain elements of the original yoked
51/// value. See the [`Yoke::map_project()`] docs for more details.
52///
53/// In general, `C` is a concrete type, but it is also possible for it to be a trait object.
54///
55/// # Example
56///
57/// For example, we can use this to store zero-copy deserialized data in a cache:
58///
59/// ```rust
60/// # use yoke::Yoke;
61/// # use std::rc::Rc;
62/// # use std::borrow::Cow;
63/// # fn load_from_cache(_filename: &str) -> Rc<[u8]> {
64/// #     // dummy implementation
65/// #     Rc::new([0x5, 0, 0, 0, 0, 0, 0, 0, 0x68, 0x65, 0x6c, 0x6c, 0x6f])
66/// # }
67///
68/// fn load_object(filename: &str) -> Yoke<Cow<'static, str>, Rc<[u8]>> {
69///     let rc: Rc<[u8]> = load_from_cache(filename);
70///     Yoke::<Cow<'static, str>, Rc<[u8]>>::attach_to_cart(rc, |data: &[u8]| {
71///         // essentially forcing a #[serde(borrow)]
72///         Cow::Borrowed(bincode::deserialize(data).unwrap())
73///     })
74/// }
75///
76/// let yoke = load_object("filename.bincode");
77/// assert_eq!(&**yoke.get(), "hello");
78/// assert!(matches!(yoke.get(), &Cow::Borrowed(_)));
79/// ```
80pub struct Yoke<Y: for<'a> Yokeable<'a>, C> {
81    // must be the first field for drop order
82    // this will have a 'static lifetime parameter, that parameter is a lie
83    yokeable: KindaSortaDangling<Y>,
84    // Safety invariant: this type can be anything, but `yokeable` may only contain references to
85    // StableDeref parts of this cart, and the targets of those references must be valid for the
86    // lifetime of this cart (it must own or borrow them). It's ok for this cart to contain stack
87    // data as long as it is not referenced by `yokeable` during construction. `attach_to_cart`,
88    // the typical constructor of this type, upholds this invariant, but other constructors like
89    // `replace_cart` need to uphold it.
90    // The implementation guarantees that there are no live `yokeable`s that reference data
91    // in a `cart` when the `cart` is dropped; this is guaranteed in the drop glue through field
92    // order.
93    cart: C,
94}
95
96// Manual `Debug` implementation, since the derived one would be unsound.
97// See https://github.com/unicode-org/icu4x/issues/3685
98impl<Y: for<'a> Yokeable<'a>, C: core::fmt::Debug> core::fmt::Debug for Yoke<Y, C>
99where
100    for<'a> <Y as Yokeable<'a>>::Output: core::fmt::Debug,
101{
102    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
103        f.debug_struct("Yoke")
104            .field("yokeable", self.get())
105            .field("cart", self.backing_cart())
106            .finish()
107    }
108}
109
110impl<Y, C> core::fmt::Display for Yoke<Y, C>
111where
112    Y: for<'a> Yokeable<'a>,
113    for<'a> <Y as Yokeable<'a>>::Output: core::fmt::Display,
114{
115    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
116        core::fmt::Display::fmt(self.get(), f)
117    }
118}
119
120impl<Y, C> PartialEq for Yoke<Y, C>
121where
122    Y: for<'a> Yokeable<'a>,
123    for<'a> <Y as Yokeable<'a>>::Output: PartialEq,
124{
125    fn eq(&self, other: &Self) -> bool {
126        self.get() == other.get()
127    }
128}
129
130impl<Y, C> Eq for Yoke<Y, C>
131where
132    Y: for<'a> Yokeable<'a>,
133    for<'a> <Y as Yokeable<'a>>::Output: Eq,
134{
135}
136
137impl<Y, C> PartialOrd for Yoke<Y, C>
138where
139    Y: for<'a> Yokeable<'a>,
140    for<'a> <Y as Yokeable<'a>>::Output: PartialOrd,
141{
142    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
143        self.get().partial_cmp(other.get())
144    }
145}
146
147impl<Y, C> Ord for Yoke<Y, C>
148where
149    Y: for<'a> Yokeable<'a>,
150    for<'a> <Y as Yokeable<'a>>::Output: Ord,
151{
152    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
153        self.get().cmp(other.get())
154    }
155}
156
157#[test]
158fn test_debug() {
159    let local_data = "foo".to_owned();
160    let y1 = Yoke::<alloc::borrow::Cow<'static, str>, Rc<String>>::attach_to_zero_copy_cart(
161        Rc::new(local_data),
162    );
163    assert_eq!(
164        format!("{y1:?}"),
165        r#"Yoke { yokeable: "foo", cart: "foo" }"#,
166    );
167}
168
169#[test]
170fn test_display() {
171    let local_data = "hello".to_owned();
172    let y = Yoke::<alloc::borrow::Cow<'static, str>, Rc<String>>::attach_to_zero_copy_cart(
173        Rc::new(local_data),
174    );
175    assert_eq!(format!("{}", y), "hello");
176}
177
178#[test]
179fn test_partialeq() {
180    let a = Rc::new("same".to_string());
181    let b = Rc::new("same".to_string());
182
183    let y1 = Yoke::<alloc::borrow::Cow<'static, str>, Rc<String>>::attach_to_zero_copy_cart(a);
184    let y2 = Yoke::<alloc::borrow::Cow<'static, str>, Rc<String>>::attach_to_zero_copy_cart(b);
185
186    assert_eq!(y1, y2);
187}
188
189#[test]
190fn test_eq_trait() {
191    let x = Rc::new("equal".to_string());
192    let y = Rc::new("equal".to_string());
193
194    let y1 = Yoke::<alloc::borrow::Cow<'static, str>, Rc<String>>::attach_to_zero_copy_cart(x);
195    let y2 = Yoke::<alloc::borrow::Cow<'static, str>, Rc<String>>::attach_to_zero_copy_cart(y);
196
197    assert!(y1 == y2);
198
199    let vec = [y1];
200    assert!(vec.contains(&y2));
201}
202
203#[test]
204fn test_partialord_ord() {
205    let a = Rc::new("a".to_string());
206    let b = Rc::new("b".to_string());
207
208    let y1 = Yoke::<alloc::borrow::Cow<'static, str>, Rc<String>>::attach_to_zero_copy_cart(a);
209    let y2 = Yoke::<alloc::borrow::Cow<'static, str>, Rc<String>>::attach_to_zero_copy_cart(b);
210
211    assert!(y1 < y2);
212    assert_eq!(y1.partial_cmp(&y2), Some(core::cmp::Ordering::Less));
213}
214
215impl<Y: for<'a> Yokeable<'a>, C: StableDeref> Yoke<Y, C>
216where
217    <C as Deref>::Target: 'static,
218{
219    /// Construct a [`Yoke`] by yokeing an object to a cart in a closure.
220    ///
221    /// The closure can read and write data outside of its scope, but data it returns
222    /// may borrow only from the argument passed to the closure.
223    ///
224    /// See also [`Yoke::try_attach_to_cart()`] to return a `Result` from the closure.
225    ///
226    /// Call sites for this function may not compile pre-1.61; if this still happens, use
227    /// [`Yoke::attach_to_cart_badly()`] and file a bug.
228    ///
229    /// # Examples
230    ///
231    /// ```
232    /// # use yoke::Yoke;
233    /// # use std::rc::Rc;
234    /// # use std::borrow::Cow;
235    /// # fn load_from_cache(_filename: &str) -> Rc<[u8]> {
236    /// #     // dummy implementation
237    /// #     Rc::new([0x5, 0, 0, 0, 0, 0, 0, 0, 0x68, 0x65, 0x6c, 0x6c, 0x6f])
238    /// # }
239    ///
240    /// fn load_object(filename: &str) -> Yoke<Cow<'static, str>, Rc<[u8]>> {
241    ///     let rc: Rc<[u8]> = load_from_cache(filename);
242    ///     Yoke::<Cow<'static, str>, Rc<[u8]>>::attach_to_cart(rc, |data: &[u8]| {
243    ///         // essentially forcing a #[serde(borrow)]
244    ///         Cow::Borrowed(bincode::deserialize(data).unwrap())
245    ///     })
246    /// }
247    ///
248    /// let yoke: Yoke<Cow<str>, _> = load_object("filename.bincode");
249    /// assert_eq!(&**yoke.get(), "hello");
250    /// assert!(matches!(yoke.get(), &Cow::Borrowed(_)));
251    /// ```
252    ///
253    /// Write the number of consumed bytes to a local variable:
254    ///
255    /// ```
256    /// # use yoke::Yoke;
257    /// # use std::rc::Rc;
258    /// # use std::borrow::Cow;
259    /// # fn load_from_cache(_filename: &str) -> Rc<[u8]> {
260    /// #     // dummy implementation
261    /// #     Rc::new([0x5, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0, 0, 0])
262    /// # }
263    ///
264    /// fn load_object(
265    ///     filename: &str,
266    /// ) -> (Yoke<Cow<'static, str>, Rc<[u8]>>, usize) {
267    ///     let rc: Rc<[u8]> = load_from_cache(filename);
268    ///     let mut bytes_remaining = 0;
269    ///     let bytes_remaining = &mut bytes_remaining;
270    ///     let yoke = Yoke::<Cow<'static, str>, Rc<[u8]>>::attach_to_cart(
271    ///         rc,
272    ///         |data: &[u8]| {
273    ///             let mut d = postcard::Deserializer::from_bytes(data);
274    ///             let output = serde::Deserialize::deserialize(&mut d);
275    ///             *bytes_remaining = d.finalize().unwrap().len();
276    ///             Cow::Borrowed(output.unwrap())
277    ///         },
278    ///     );
279    ///     (yoke, *bytes_remaining)
280    /// }
281    ///
282    /// let (yoke, bytes_remaining) = load_object("filename.postcard");
283    /// assert_eq!(&**yoke.get(), "hello");
284    /// assert!(matches!(yoke.get(), &Cow::Borrowed(_)));
285    /// assert_eq!(bytes_remaining, 3);
286    /// ```
287    pub fn attach_to_cart<F>(cart: C, f: F) -> Self
288    where
289        // safety note: This works by enforcing that the *only* place the return value of F
290        // can borrow from is the cart, since `F` must be valid for all lifetimes `'de`
291        //
292        // The <C as Deref>::Target: 'static on the impl is crucial for safety as well
293        //
294        // See safety docs at the bottom of this file for more information
295        F: for<'de> FnOnce(&'de <C as Deref>::Target) -> <Y as Yokeable<'de>>::Output,
296        <C as Deref>::Target: 'static,
297    {
298        let deserialized = f(cart.deref());
299        Self {
300            yokeable: KindaSortaDangling::new(
301                // Safety: the resulting `yokeable` is dropped before the `cart` because
302                // of the Yoke invariant. See the safety docs at the bottom of this file
303                // for the justification of why yokeable could only borrow from the Cart.
304                unsafe { Y::make(deserialized) },
305            ),
306            cart,
307        }
308    }
309
310    /// Construct a [`Yoke`] by yokeing an object to a cart. If an error occurs in the
311    /// deserializer function, the error is passed up to the caller.
312    ///
313    /// Call sites for this function may not compile pre-1.61; if this still happens, use
314    /// [`Yoke::try_attach_to_cart_badly()`] and file a bug.
315    pub fn try_attach_to_cart<E, F>(cart: C, f: F) -> Result<Self, E>
316    where
317        F: for<'de> FnOnce(&'de <C as Deref>::Target) -> Result<<Y as Yokeable<'de>>::Output, E>,
318        <C as Deref>::Target: 'static,
319    {
320        let deserialized = f(cart.deref())?;
321        Ok(Self {
322            yokeable: KindaSortaDangling::new(
323                // Safety: the resulting `yokeable` is dropped before the `cart` because
324                // of the Yoke invariant. See the safety docs at the bottom of this file
325                // for the justification of why yokeable could only borrow from the Cart.
326                unsafe { Y::make(deserialized) },
327            ),
328            cart,
329        })
330    }
331
332    /// Use [`Yoke::attach_to_cart()`].
333    ///
334    /// This was needed because the pre-1.61 compiler couldn't always handle the [`FnOnce`] trait bound.
335    #[deprecated]
336    pub fn attach_to_cart_badly(
337        cart: C,
338        f: for<'de> fn(&'de <C as Deref>::Target) -> <Y as Yokeable<'de>>::Output,
339    ) -> Self {
340        Self::attach_to_cart(cart, f)
341    }
342
343    /// Use [`Yoke::try_attach_to_cart()`].
344    ///
345    /// This was needed because the pre-1.61 compiler couldn't always handle the [`FnOnce`] trait bound.
346    #[deprecated]
347    pub fn try_attach_to_cart_badly<E>(
348        cart: C,
349        f: for<'de> fn(&'de <C as Deref>::Target) -> Result<<Y as Yokeable<'de>>::Output, E>,
350    ) -> Result<Self, E> {
351        Self::try_attach_to_cart(cart, f)
352    }
353}
354
355impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
356    /// Obtain a valid reference to the yokeable data
357    ///
358    /// This essentially transforms the lifetime of the internal yokeable data to
359    /// be valid.
360    /// For example, if you're working with a `Yoke<Cow<'static, T>, C>`, this
361    /// will return an `&'a Cow<'a, T>`
362    ///
363    /// # Example
364    ///
365    /// ```rust
366    /// # use yoke::Yoke;
367    /// # use std::rc::Rc;
368    /// # use std::borrow::Cow;
369    /// # fn load_from_cache(_filename: &str) -> Rc<[u8]> {
370    /// #     // dummy implementation
371    /// #     Rc::new([0x5, 0, 0, 0, 0, 0, 0, 0, 0x68, 0x65, 0x6c, 0x6c, 0x6f])
372    /// # }
373    /// #
374    /// # fn load_object(filename: &str) -> Yoke<Cow<'static, str>, Rc<[u8]>> {
375    /// #     let rc: Rc<[u8]> = load_from_cache(filename);
376    /// #     Yoke::<Cow<'static, str>, Rc<[u8]>>::attach_to_cart(rc, |data: &[u8]| {
377    /// #         Cow::Borrowed(bincode::deserialize(data).unwrap())
378    /// #     })
379    /// # }
380    ///
381    /// // load_object() defined in the example at the top of this page
382    /// let yoke: Yoke<Cow<str>, _> = load_object("filename.bincode");
383    /// assert_eq!(yoke.get(), "hello");
384    /// ```
385    #[inline]
386    pub fn get<'a>(&'a self) -> &'a <Y as Yokeable<'a>>::Output {
387        self.yokeable.transform()
388    }
389
390    /// Get a reference to the backing cart.
391    ///
392    /// This can be useful when building caches, etc. However, if you plan to store the cart
393    /// separately from the yoke, read the note of caution below in [`Yoke::into_backing_cart`].
394    pub fn backing_cart(&self) -> &C {
395        &self.cart
396    }
397
398    /// Get the backing cart by value, dropping the yokeable object.
399    ///
400    /// **Caution:** Calling this method could cause information saved in the yokeable object but
401    /// not the cart to be lost. Use this method only if the yokeable object cannot contain its
402    /// own information.
403    ///
404    /// # Example
405    ///
406    /// Good example: the yokeable object is only a reference, so no information can be lost.
407    ///
408    /// ```
409    /// use yoke::Yoke;
410    ///
411    /// let local_data = "foo".to_owned();
412    /// let yoke = Yoke::<&'static str, Box<String>>::attach_to_zero_copy_cart(
413    ///     Box::new(local_data),
414    /// );
415    /// assert_eq!(*yoke.get(), "foo");
416    ///
417    /// // Get back the cart
418    /// let cart = yoke.into_backing_cart();
419    /// assert_eq!(&*cart, "foo");
420    /// ```
421    ///
422    /// Bad example: information specified in `.with_mut()` is lost.
423    ///
424    /// ```
425    /// use std::borrow::Cow;
426    /// use yoke::Yoke;
427    ///
428    /// let local_data = "foo".to_owned();
429    /// let mut yoke =
430    ///     Yoke::<Cow<'static, str>, Box<String>>::attach_to_zero_copy_cart(
431    ///         Box::new(local_data),
432    ///     );
433    /// assert_eq!(yoke.get(), "foo");
434    ///
435    /// // Override data in the cart
436    /// yoke.with_mut(|cow| {
437    ///     let mut_str = cow.to_mut();
438    ///     mut_str.clear();
439    ///     mut_str.push_str("bar");
440    /// });
441    /// assert_eq!(yoke.get(), "bar");
442    ///
443    /// // Get back the cart
444    /// let cart = yoke.into_backing_cart();
445    /// assert_eq!(&*cart, "foo"); // WHOOPS!
446    /// ```
447    pub fn into_backing_cart(self) -> C {
448        self.cart
449    }
450
451    /// Unsafe function for replacing the cart with another
452    ///
453    /// This can be used for type-erasing the cart, for example.
454    ///
455    /// # Safety
456    ///
457    /// - References from the yokeable `Y` should still be valid for the lifetime of the
458    ///   returned cart type `C`.
459    ///
460    ///   For the purpose of determining this, `Yoke` guarantees that references from the Yokeable
461    ///   `Y` into the cart `C` will never be references into its stack data, only heap data protected
462    ///   by `StableDeref`. This does not necessarily mean that `C` implements `StableDeref`, rather that
463    ///   any data referenced by `Y` must be accessed through a `StableDeref` impl on something `C` owns.
464    ///
465    ///   Concretely, this means that if `C = Option<Rc<T>>`, `Y` may contain references to the `T` but not
466    ///   anything else.
467    /// - Lifetimes inside C must not be lengthened, even if they are themselves contravariant.
468    ///   I.e., if C contains an `fn(&'a u8)`, it cannot be replaced with `fn(&'static u8)`,
469    ///   even though that is typically safe.
470    ///
471    /// Note: `f` *is* allowed to panic.
472    ///
473    /// Typically, this means implementing `f` as something which _wraps_ the inner cart type `C`.
474    /// `Yoke` only really cares about destructors for its carts so it's fine to erase other
475    /// information about the cart, as long as the backing data will still be destroyed at the
476    /// same time.
477    #[inline]
478    pub unsafe fn replace_cart<C2>(self, f: impl FnOnce(C) -> C2) -> Yoke<Y, C2> {
479        let yokeable = ManuallyDrop::new(self.yokeable);
480        let cart = f(self.cart);
481        Yoke {
482            // Safety note: the safety invariant of this function guarantees that
483            // the data that the yokeable references has its ownership (if any)
484            // transferred to the new cart before self.cart is dropped, unless
485            // `f` panics, in which case the above `ManuallyDrop` ensures that
486            // the yokeable is leaked (preventing any UB from dropping the
487            // yokeable after its cart).
488            yokeable: ManuallyDrop::into_inner(yokeable),
489            cart,
490        }
491    }
492
493    /// Mutate the stored [`Yokeable`] data.
494    ///
495    /// If the callback needs to return `'static` data, then [`Yoke::with_mut_return`] can be
496    /// used until the next breaking release of `yoke`, at which time the callback to this
497    /// function will be able to return any `'static` data.
498    ///
499    /// See [`Yokeable::transform_mut()`] for why this operation is safe.
500    ///
501    /// # Example
502    ///
503    /// This can be used to partially mutate the stored data, provided
504    /// no _new_ borrowed data is introduced.
505    ///
506    /// ```rust
507    /// # use yoke::{Yoke, Yokeable};
508    /// # use std::rc::Rc;
509    /// # use std::borrow::Cow;
510    /// # use std::mem;
511    /// # fn load_from_cache(_filename: &str) -> Rc<[u8]> {
512    /// #     // dummy implementation
513    /// #     Rc::new([0x5, 0, 0, 0, 0, 0, 0, 0, 0x68, 0x65, 0x6c, 0x6c, 0x6f])
514    /// # }
515    /// #
516    /// # fn load_object(filename: &str) -> Yoke<Bar<'static>, Rc<[u8]>> {
517    /// #     let rc: Rc<[u8]> = load_from_cache(filename);
518    /// #     Yoke::<Bar<'static>, Rc<[u8]>>::attach_to_cart(rc, |data: &[u8]| {
519    /// #         // A real implementation would properly deserialize `Bar` as a whole
520    /// #         Bar {
521    /// #             numbers: Cow::Borrowed(bincode::deserialize(data).unwrap()),
522    /// #             string: Cow::Borrowed(bincode::deserialize(data).unwrap()),
523    /// #             owned: Vec::new(),
524    /// #         }
525    /// #     })
526    /// # }
527    ///
528    /// #[derive(Yokeable)]
529    /// struct Bar<'a> {
530    ///     numbers: Cow<'a, [u8]>,
531    ///     string: Cow<'a, str>,
532    ///     owned: Vec<u8>,
533    /// }
534    ///
535    /// // `load_object()` deserializes an object from a file
536    /// let mut bar: Yoke<Bar, _> = load_object("filename.bincode");
537    /// assert_eq!(bar.get().string, "hello");
538    /// assert!(matches!(bar.get().string, Cow::Borrowed(_)));
539    /// assert_eq!(&*bar.get().numbers, &[0x68, 0x65, 0x6c, 0x6c, 0x6f]);
540    /// assert!(matches!(bar.get().numbers, Cow::Borrowed(_)));
541    /// assert_eq!(&*bar.get().owned, &[]);
542    ///
543    /// bar.with_mut(|bar| {
544    ///     bar.string.to_mut().push_str(" world");
545    ///     bar.owned.extend_from_slice(&[1, 4, 1, 5, 9]);
546    /// });
547    ///
548    /// assert_eq!(bar.get().string, "hello world");
549    /// assert!(matches!(bar.get().string, Cow::Owned(_)));
550    /// assert_eq!(&*bar.get().owned, &[1, 4, 1, 5, 9]);
551    /// // Unchanged and still Cow::Borrowed
552    /// assert_eq!(&*bar.get().numbers, &[0x68, 0x65, 0x6c, 0x6c, 0x6f]);
553    /// assert!(matches!(bar.get().numbers, Cow::Borrowed(_)));
554    /// ```
555    pub fn with_mut<'a, F>(&'a mut self, f: F)
556    where
557        F: 'static + for<'b> FnOnce(&'b mut <Y as Yokeable<'a>>::Output),
558    {
559        self.yokeable.transform_mut(f);
560    }
561
562    /// Mutate the stored [`Yokeable`] data, and return `'static` data (possibly just `()`).
563    ///
564    /// See [`Yokeable::transform_mut()`] for why this operation is safe, noting that no
565    /// `'static`.
566    ///
567    /// ### Will be removed
568    /// This method will be removed on the next breaking release of `yoke`, when the callback of
569    /// [`Yoke::with_mut`] will gain the ability to return any `R: 'static` and supersede this
570    /// method.
571    pub fn with_mut_return<'a, F, R>(&'a mut self, f: F) -> R
572    where
573        F: 'static + for<'b> FnOnce(&'b mut <Y as Yokeable<'a>>::Output) -> R,
574        R: 'static,
575    {
576        utils::transform_mut_yokeable(&mut *self.yokeable, f)
577    }
578
579    /// Helper function allowing one to wrap the cart type `C` in an `Option<T>`.
580    #[inline]
581    pub fn wrap_cart_in_option(self) -> Yoke<Y, Option<C>> {
582        // Safety: the cart is preserved (since it is just wrapped into a Some),
583        // so any data it owns is too.
584        unsafe { self.replace_cart(Some) }
585    }
586}
587
588impl<Y: for<'a> Yokeable<'a>> Yoke<Y, ()> {
589    /// Construct a new [`Yoke`] from static data. There will be no
590    /// references to `cart` here since [`Yokeable`]s are `'static`,
591    /// this is good for e.g. constructing fully owned
592    /// [`Yoke`]s with no internal borrowing.
593    ///
594    /// This is similar to [`Yoke::new_owned()`] but it does not allow you to
595    /// mix the [`Yoke`] with borrowed data. This is primarily useful
596    /// for using [`Yoke`] in generic scenarios.
597    ///
598    /// # Example
599    ///
600    /// ```rust
601    /// # use yoke::Yoke;
602    /// # use std::borrow::Cow;
603    ///
604    /// let owned: Cow<str> = "hello".to_owned().into();
605    /// // this yoke can be intermingled with actually-borrowed Yokes
606    /// let yoke: Yoke<Cow<str>, ()> = Yoke::new_always_owned(owned);
607    ///
608    /// assert_eq!(yoke.get(), "hello");
609    /// ```
610    pub fn new_always_owned(yokeable: Y) -> Self {
611        Self {
612            // Safety note: this `yokeable` certainly does not reference data owned by (), so we do
613            // not have to worry about when the `yokeable` is dropped.
614            yokeable: KindaSortaDangling::new(yokeable),
615            cart: (),
616        }
617    }
618
619    /// Obtain the yokeable out of a `Yoke<Y, ()>`
620    ///
621    /// For most `Yoke` types this would be unsafe but it's
622    /// fine for `Yoke<Y, ()>` since there are no actual internal
623    /// references
624    pub fn into_yokeable(self) -> Y {
625        // Safety note: since `yokeable` cannot reference data owned by `()`, this is certainly
626        // safe.
627        self.yokeable.into_inner()
628    }
629}
630
631// C does not need to be StableDeref here, if the yoke was constructed it's valid,
632// and new_owned() doesn't construct a yokeable that uses references,
633impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, Option<C>> {
634    /// Construct a new [`Yoke`] from static data. There will be no
635    /// references to `cart` here since [`Yokeable`]s are `'static`,
636    /// this is good for e.g. constructing fully owned
637    /// [`Yoke`]s with no internal borrowing.
638    ///
639    /// This can be paired with [`Yoke:: wrap_cart_in_option()`] to mix owned
640    /// and borrowed data.
641    ///
642    /// If you do not wish to pair this with borrowed data, [`Yoke::new_always_owned()`] can
643    /// be used to get a [`Yoke`] API on always-owned data.
644    ///
645    /// # Example
646    ///
647    /// ```rust
648    /// # use yoke::Yoke;
649    /// # use std::borrow::Cow;
650    /// # use std::rc::Rc;
651    ///
652    /// let owned: Cow<str> = "hello".to_owned().into();
653    /// // this yoke can be intermingled with actually-borrowed Yokes
654    /// let yoke: Yoke<Cow<str>, Option<Rc<[u8]>>> = Yoke::new_owned(owned);
655    ///
656    /// assert_eq!(yoke.get(), "hello");
657    /// ```
658    pub const fn new_owned(yokeable: Y) -> Self {
659        Self {
660            // Safety note: this `yokeable` is known not to borrow from the cart.
661            yokeable: KindaSortaDangling::new(yokeable),
662            cart: None,
663        }
664    }
665
666    /// Obtain the yokeable out of a `Yoke<Y, Option<C>>` if possible.
667    ///
668    /// If the cart is `None`, this returns `Ok`, but if the cart is `Some`,
669    /// this returns `self` as an error.
670    pub fn try_into_yokeable(self) -> Result<Y, Self> {
671        // Safety: if the cart is None there is no way for the yokeable to
672        // have references into it because of the cart invariant.
673        match self.cart {
674            Some(_) => Err(self),
675            None => Ok(self.yokeable.into_inner()),
676        }
677    }
678}
679
680impl<Y: for<'a> Yokeable<'a>, C: CartablePointerLike> Yoke<Y, Option<C>> {
681    /// Converts a `Yoke<Y, Option<C>>` to `Yoke<Y, CartableOptionPointer<C>>`
682    /// for better niche optimization when stored as a field.
683    ///
684    /// # Examples
685    ///
686    /// ```
687    /// use std::borrow::Cow;
688    /// use yoke::Yoke;
689    ///
690    /// let yoke: Yoke<Cow<[u8]>, Box<Vec<u8>>> =
691    ///     Yoke::attach_to_cart(vec![10, 20, 30].into(), |c| c.into());
692    ///
693    /// let yoke_option = yoke.wrap_cart_in_option();
694    /// let yoke_option_pointer = yoke_option.convert_cart_into_option_pointer();
695    /// ```
696    ///
697    /// The niche improves stack sizes:
698    ///
699    /// ```
700    /// use yoke::Yoke;
701    /// use yoke::cartable_ptr::CartableOptionPointer;
702    /// use std::rc::Rc;
703    ///
704    /// // The data struct is 6 words:
705    /// # #[derive(yoke::Yokeable)]
706    /// # struct MyDataStruct<'a> {
707    /// #     _s: (usize, usize, usize, usize),
708    /// #     _p: &'a str,
709    /// # }
710    /// const W: usize = size_of::<usize>();
711    /// assert_eq!(W * 6, size_of::<MyDataStruct>());
712    ///
713    /// // An enum containing the data struct with an `Option<Rc>` cart is 8 words:
714    /// enum StaticOrYoke1 {
715    ///     Static(&'static MyDataStruct<'static>),
716    ///     Yoke(Yoke<MyDataStruct<'static>, Option<Rc<String>>>),
717    /// }
718    /// assert_eq!(W * 8, size_of::<StaticOrYoke1>());
719    ///
720    /// // When using `CartableOptionPointer``, we need only 7 words for the same behavior:
721    /// enum StaticOrYoke2 {
722    ///     Static(&'static MyDataStruct<'static>),
723    ///     Yoke(Yoke<MyDataStruct<'static>, CartableOptionPointer<Rc<String>>>),
724    /// }
725    /// assert_eq!(W * 7, size_of::<StaticOrYoke2>());
726    /// ```
727    #[inline]
728    pub fn convert_cart_into_option_pointer(self) -> Yoke<Y, CartableOptionPointer<C>> {
729        match self.cart {
730            Some(cart) => Yoke {
731                // Safety note: CartableOptionPointer::from_cartable only wraps the `cart`,
732                // so the data referenced by the yokeable is still live.
733                yokeable: self.yokeable,
734                cart: CartableOptionPointer::from_cartable(cart),
735            },
736            None => Yoke {
737                // Safety note: this Yokeable cannot refer to any data since self.cart is None.
738                yokeable: self.yokeable,
739                cart: CartableOptionPointer::none(),
740            },
741        }
742    }
743}
744
745impl<Y: for<'a> Yokeable<'a>, C: CartablePointerLike> Yoke<Y, CartableOptionPointer<C>> {
746    /// Obtain the yokeable out of a `Yoke<Y, CartableOptionPointer<C>>` if possible.
747    ///
748    /// If the cart is `None`, this returns `Ok`, but if the cart is `Some`,
749    /// this returns `self` as an error.
750    #[inline]
751    pub fn try_into_yokeable(self) -> Result<Y, Self> {
752        if self.cart.is_none() {
753            Ok(self.yokeable.into_inner())
754        } else {
755            Err(self)
756        }
757    }
758}
759
760/// This trait marks cart types that do not change source on cloning
761///
762/// This is conceptually similar to [`stable_deref_trait::CloneStableDeref`],
763/// however [`stable_deref_trait::CloneStableDeref`] is not (and should not) be
764/// implemented on [`Option`] (since it's not [`Deref`]). [`CloneableCart`] essentially is
765/// "if there _is_ data to borrow from here, cloning the cart gives you an additional
766/// handle to the same data".
767///
768/// # Safety
769/// This trait is safe to implement on `StableDeref` types which, once `Clone`d, point to the same underlying data and retain ownership.
770///
771/// This trait can also be implemented on aggregates of such types like `Option<T: CloneableCart>` and `(T: CloneableCart, U: CloneableCart)`.
772///
773/// Essentially, all data that could be referenced by a Yokeable (i.e. data that is referenced via a [`StableDeref`]) must retain the same
774/// pointer and ownership semantics once cloned.
775pub unsafe trait CloneableCart: Clone {}
776
777#[cfg(feature = "alloc")]
778// Safety: Rc<T> implements CloneStableDeref.
779unsafe impl<T: ?Sized> CloneableCart for Rc<T> {}
780#[cfg(feature = "alloc")]
781// Safety: Arc<T> implements CloneStableDeref.
782unsafe impl<T: ?Sized> CloneableCart for Arc<T> {}
783// Safety: Option<T> cannot deref to anything that T doesn't already deref to.
784unsafe impl<T: CloneableCart> CloneableCart for Option<T> {}
785// Safety: &'a T is indeed StableDeref, and cloning it refers to the same data.
786// &'a T does not own in the first place, so ownership is preserved.
787unsafe impl<'a, T: ?Sized> CloneableCart for &'a T {}
788// Safety: () cannot deref to anything.
789unsafe impl CloneableCart for () {}
790
791/// Clone requires that the cart type `C` derefs to the same address after it is cloned. This works for
792/// Rc, Arc, and &'a T.
793///
794/// For other cart types, clone `.backing_cart()` and re-use `.attach_to_cart()`; however, doing
795/// so may lose mutations performed via `.with_mut()`.
796///
797/// Cloning a `Yoke` is often a cheap operation requiring no heap allocations, in much the same
798/// way that cloning an `Rc` is a cheap operation. However, if the `yokeable` contains owned data
799/// (e.g., from `.with_mut()`), that data will need to be cloned.
800impl<Y: for<'a> Yokeable<'a>, C: CloneableCart> Clone for Yoke<Y, C>
801where
802    for<'a> <Y as Yokeable<'a>>::Output: Clone,
803{
804    fn clone(&self) -> Self {
805        // We have an &T not a T, and we can clone T
806        let this = self.get().clone();
807        Yoke {
808            yokeable: KindaSortaDangling::new(
809                // Safety: C being a CloneableCart guarantees that the data referenced by the
810                // `yokeable` is kept alive by the clone of the cart.
811                unsafe { Y::make(this) },
812            ),
813            cart: self.cart.clone(),
814        }
815    }
816}
817
818#[test]
819fn test_clone() {
820    let local_data = "foo".to_owned();
821    let y1 = Yoke::<alloc::borrow::Cow<'static, str>, Rc<String>>::attach_to_zero_copy_cart(
822        Rc::new(local_data),
823    );
824
825    // Test basic clone
826    let y2 = y1.clone();
827    assert_eq!(y1.get(), "foo");
828    assert_eq!(y2.get(), "foo");
829
830    // Test clone with mutation on target
831    let mut y3 = y1.clone();
832    y3.with_mut(|y| {
833        y.to_mut().push_str("bar");
834    });
835    assert_eq!(y1.get(), "foo");
836    assert_eq!(y2.get(), "foo");
837    assert_eq!(y3.get(), "foobar");
838
839    // Test that mutations on source do not affect target
840    let y4 = y3.clone();
841    y3.with_mut(|y| {
842        y.to_mut().push_str("baz");
843    });
844    assert_eq!(y1.get(), "foo");
845    assert_eq!(y2.get(), "foo");
846    assert_eq!(y3.get(), "foobarbaz");
847    assert_eq!(y4.get(), "foobar");
848}
849
850impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
851    /// Allows one to "project" a yoke to perform a transformation on the data, potentially
852    /// looking at a subfield, and producing a new yoke. This will move cart, and the provided
853    /// transformation is only allowed to use data known to be borrowed from the cart.
854    ///
855    /// If producing the new [`Yokeable`] `P` requires access to the cart in addition to the old
856    /// `Y`, then [`Yoke::map_with_cart`] can be used if the cart satisfies additional constraints.
857    ///
858    /// The callback takes an additional `PhantomData<&()>` parameter to anchor lifetimes
859    /// (see [#86702](https://github.com/rust-lang/rust/issues/86702)) This parameter
860    /// should just be ignored in the callback.
861    ///
862    /// This can be used, for example, to transform data from one format to another:
863    ///
864    /// ```
865    /// # use std::rc::Rc;
866    /// # use yoke::Yoke;
867    /// #
868    /// fn slice(y: Yoke<&'static str, Rc<[u8]>>) -> Yoke<&'static [u8], Rc<[u8]>> {
869    ///     y.map_project(move |yk, _| yk.as_bytes())
870    /// }
871    /// ```
872    ///
873    /// This can also be used to create a yoke for a subfield
874    ///
875    /// ```
876    /// # use yoke::{Yoke, Yokeable};
877    /// # use std::mem;
878    /// # use std::rc::Rc;
879    /// #
880    /// // also safely implements Yokeable<'a>
881    /// struct Bar<'a> {
882    ///     string_1: &'a str,
883    ///     string_2: &'a str,
884    /// }
885    ///
886    /// fn map_project_string_1(
887    ///     bar: Yoke<Bar<'static>, Rc<[u8]>>,
888    /// ) -> Yoke<&'static str, Rc<[u8]>> {
889    ///     bar.map_project(|bar, _| bar.string_1)
890    /// }
891    ///
892    /// #
893    /// # unsafe impl<'a> Yokeable<'a> for Bar<'static> {
894    /// #     type Output = Bar<'a>;
895    /// #     fn transform(&'a self) -> &'a Bar<'a> {
896    /// #         self
897    /// #     }
898    /// #
899    /// #     fn transform_owned(self) -> Bar<'a> {
900    /// #         // covariant lifetime cast, can be done safely
901    /// #         self
902    /// #     }
903    /// #
904    /// #     unsafe fn make(from: Bar<'a>) -> Self {
905    /// #         unsafe { mem::transmute(from) }
906    /// #     }
907    /// #
908    /// #     fn transform_mut<F>(&'a mut self, f: F)
909    /// #     where
910    /// #         F: 'static + FnOnce(&'a mut Self::Output),
911    /// #     {
912    /// #         unsafe { f(mem::transmute(self)) }
913    /// #     }
914    /// # }
915    /// ```
916    //
917    // Safety docs can be found at the end of the file.
918    pub fn map_project<P, F>(self, f: F) -> Yoke<P, C>
919    where
920        P: for<'a> Yokeable<'a>,
921        F: for<'a> FnOnce(
922            <Y as Yokeable<'a>>::Output,
923            PhantomData<&'a ()>,
924        ) -> <P as Yokeable<'a>>::Output,
925    {
926        let p = f(self.yokeable.into_inner().transform_owned(), PhantomData);
927        Yoke {
928            yokeable: KindaSortaDangling::new(
929                // Safety: the resulting `yokeable` is dropped before the `cart` because
930                // of the Yoke invariant. See the safety docs below for the justification of why
931                // yokeable could only borrow from the Cart.
932                unsafe { P::make(p) },
933            ),
934            cart: self.cart,
935        }
936    }
937
938    /// This is similar to [`Yoke::map_project`], however it does not move
939    /// [`Self`] and instead clones the cart (only if the cart is a [`CloneableCart`])
940    ///
941    /// This is a bit more efficient than cloning the [`Yoke`] and then calling [`Yoke::map_project`]
942    /// because then it will not clone fields that are going to be discarded.
943    pub fn map_project_cloned<'this, P, F>(&'this self, f: F) -> Yoke<P, C>
944    where
945        P: for<'a> Yokeable<'a>,
946        C: CloneableCart,
947        F: for<'a> FnOnce(
948            &'this <Y as Yokeable<'a>>::Output,
949            PhantomData<&'a ()>,
950        ) -> <P as Yokeable<'a>>::Output,
951    {
952        let p = f(self.get(), PhantomData);
953        Yoke {
954            yokeable: KindaSortaDangling::new(
955                // Safety: the resulting `yokeable` is dropped before the `cart` because
956                // of the Yoke invariant. See the safety docs below for the justification of why
957                // yokeable could only borrow from the Cart.
958                unsafe { P::make(p) },
959            ),
960            cart: self.cart.clone(),
961        }
962    }
963
964    /// This is similar to [`Yoke::map_project`], however it can also bubble up an error
965    /// from the callback.
966    ///
967    /// ```
968    /// # use std::rc::Rc;
969    /// # use yoke::Yoke;
970    /// # use std::str::{self, Utf8Error};
971    /// #
972    /// fn slice(
973    ///     y: Yoke<&'static [u8], Rc<[u8]>>,
974    /// ) -> Result<Yoke<&'static str, Rc<[u8]>>, Utf8Error> {
975    ///     y.try_map_project(move |bytes, _| str::from_utf8(bytes))
976    /// }
977    /// ```
978    ///
979    /// This can also be used to create a yoke for a subfield
980    ///
981    /// ```
982    /// # use yoke::{Yoke, Yokeable};
983    /// # use std::mem;
984    /// # use std::rc::Rc;
985    /// # use std::str::{self, Utf8Error};
986    /// #
987    /// // also safely implements Yokeable<'a>
988    /// struct Bar<'a> {
989    ///     bytes_1: &'a [u8],
990    ///     string_2: &'a str,
991    /// }
992    ///
993    /// fn map_project_string_1(
994    ///     bar: Yoke<Bar<'static>, Rc<[u8]>>,
995    /// ) -> Result<Yoke<&'static str, Rc<[u8]>>, Utf8Error> {
996    ///     bar.try_map_project(|bar, _| str::from_utf8(bar.bytes_1))
997    /// }
998    ///
999    /// #
1000    /// # unsafe impl<'a> Yokeable<'a> for Bar<'static> {
1001    /// #     type Output = Bar<'a>;
1002    /// #     fn transform(&'a self) -> &'a Bar<'a> {
1003    /// #         self
1004    /// #     }
1005    /// #
1006    /// #     fn transform_owned(self) -> Bar<'a> {
1007    /// #         // covariant lifetime cast, can be done safely
1008    /// #         self
1009    /// #     }
1010    /// #
1011    /// #     unsafe fn make(from: Bar<'a>) -> Self {
1012    /// #         unsafe { mem::transmute(from) }
1013    /// #     }
1014    /// #
1015    /// #     fn transform_mut<F>(&'a mut self, f: F)
1016    /// #     where
1017    /// #         F: 'static + FnOnce(&'a mut Self::Output),
1018    /// #     {
1019    /// #         unsafe { f(mem::transmute(self)) }
1020    /// #     }
1021    /// # }
1022    /// ```
1023    pub fn try_map_project<P, F, E>(self, f: F) -> Result<Yoke<P, C>, E>
1024    where
1025        P: for<'a> Yokeable<'a>,
1026        F: for<'a> FnOnce(
1027            <Y as Yokeable<'a>>::Output,
1028            PhantomData<&'a ()>,
1029        ) -> Result<<P as Yokeable<'a>>::Output, E>,
1030    {
1031        let p = f(self.yokeable.into_inner().transform_owned(), PhantomData)?;
1032        Ok(Yoke {
1033            yokeable: KindaSortaDangling::new(
1034                // Safety: the resulting `yokeable` is dropped before the `cart` because
1035                // of the Yoke invariant. See the safety docs below for the justification of why
1036                // yokeable could only borrow from the Cart.
1037                unsafe { P::make(p) },
1038            ),
1039            cart: self.cart,
1040        })
1041    }
1042
1043    /// This is similar to [`Yoke::try_map_project`], however it does not move
1044    /// [`Self`] and instead clones the cart (only if the cart is a [`CloneableCart`])
1045    ///
1046    /// This is a bit more efficient than cloning the [`Yoke`] and then calling [`Yoke::map_project`]
1047    /// because then it will not clone fields that are going to be discarded.
1048    pub fn try_map_project_cloned<'this, P, F, E>(&'this self, f: F) -> Result<Yoke<P, C>, E>
1049    where
1050        P: for<'a> Yokeable<'a>,
1051        C: CloneableCart,
1052        F: for<'a> FnOnce(
1053            &'this <Y as Yokeable<'a>>::Output,
1054            PhantomData<&'a ()>,
1055        ) -> Result<<P as Yokeable<'a>>::Output, E>,
1056    {
1057        let p = f(self.get(), PhantomData)?;
1058        Ok(Yoke {
1059            yokeable: KindaSortaDangling::new(
1060                // Safety: the resulting `yokeable` is dropped before the `cart` because
1061                // of the Yoke invariant. See the safety docs below for the justification of why
1062                // yokeable could only borrow from the Cart.
1063                unsafe { P::make(p) },
1064            ),
1065            cart: self.cart.clone(),
1066        })
1067    }
1068    /// This is similar to [`Yoke::map_project`], but it works around older versions
1069    /// of Rust not being able to use `FnOnce` by using an explicit capture input.
1070    /// See [#1061](https://github.com/unicode-org/icu4x/issues/1061).
1071    ///
1072    /// See the docs of [`Yoke::map_project`] for how this works.
1073    pub fn map_project_with_explicit_capture<P, T>(
1074        self,
1075        capture: T,
1076        f: for<'a> fn(
1077            <Y as Yokeable<'a>>::Output,
1078            capture: T,
1079            PhantomData<&'a ()>,
1080        ) -> <P as Yokeable<'a>>::Output,
1081    ) -> Yoke<P, C>
1082    where
1083        P: for<'a> Yokeable<'a>,
1084    {
1085        let p = f(
1086            self.yokeable.into_inner().transform_owned(),
1087            capture,
1088            PhantomData,
1089        );
1090        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,
1098        }
1099    }
1100
1101    /// This is similar to [`Yoke::map_project_cloned`], but it works around older versions
1102    /// of Rust not being able to use `FnOnce` by using an explicit capture input.
1103    /// See [#1061](https://github.com/unicode-org/icu4x/issues/1061).
1104    ///
1105    /// See the docs of [`Yoke::map_project_cloned`] for how this works.
1106    pub fn map_project_cloned_with_explicit_capture<'this, P, T>(
1107        &'this self,
1108        capture: T,
1109        f: for<'a> fn(
1110            &'this <Y as Yokeable<'a>>::Output,
1111            capture: T,
1112            PhantomData<&'a ()>,
1113        ) -> <P as Yokeable<'a>>::Output,
1114    ) -> Yoke<P, C>
1115    where
1116        P: for<'a> Yokeable<'a>,
1117        C: CloneableCart,
1118    {
1119        let p = f(self.get(), capture, PhantomData);
1120        Yoke {
1121            yokeable: KindaSortaDangling::new(
1122                // Safety: the resulting `yokeable` is dropped before the `cart` because
1123                // of the Yoke invariant. See the safety docs below for the justification of why
1124                // yokeable could only borrow from the Cart.
1125                unsafe { P::make(p) },
1126            ),
1127            cart: self.cart.clone(),
1128        }
1129    }
1130
1131    /// This is similar to [`Yoke::try_map_project`], but it works around older versions
1132    /// of Rust not being able to use `FnOnce` by using an explicit capture input.
1133    /// See [#1061](https://github.com/unicode-org/icu4x/issues/1061).
1134    ///
1135    /// See the docs of [`Yoke::try_map_project`] for how this works.
1136    #[expect(clippy::type_complexity)]
1137    pub fn try_map_project_with_explicit_capture<P, T, E>(
1138        self,
1139        capture: T,
1140        f: for<'a> fn(
1141            <Y as Yokeable<'a>>::Output,
1142            capture: T,
1143            PhantomData<&'a ()>,
1144        ) -> Result<<P as Yokeable<'a>>::Output, E>,
1145    ) -> Result<Yoke<P, C>, E>
1146    where
1147        P: for<'a> Yokeable<'a>,
1148    {
1149        let p = f(
1150            self.yokeable.into_inner().transform_owned(),
1151            capture,
1152            PhantomData,
1153        )?;
1154        Ok(Yoke {
1155            yokeable: KindaSortaDangling::new(
1156                // Safety: the resulting `yokeable` is dropped before the `cart` because
1157                // of the Yoke invariant. See the safety docs below for the justification of why
1158                // yokeable could only borrow from the Cart.
1159                unsafe { P::make(p) },
1160            ),
1161            cart: self.cart,
1162        })
1163    }
1164
1165    /// This is similar to [`Yoke::try_map_project_cloned`], but it works around older versions
1166    /// of Rust not being able to use `FnOnce` by using an explicit capture input.
1167    /// See [#1061](https://github.com/unicode-org/icu4x/issues/1061).
1168    ///
1169    /// See the docs of [`Yoke::try_map_project_cloned`] for how this works.
1170    #[expect(clippy::type_complexity)]
1171    pub fn try_map_project_cloned_with_explicit_capture<'this, P, T, E>(
1172        &'this self,
1173        capture: T,
1174        f: for<'a> fn(
1175            &'this <Y as Yokeable<'a>>::Output,
1176            capture: T,
1177            PhantomData<&'a ()>,
1178        ) -> Result<<P as Yokeable<'a>>::Output, E>,
1179    ) -> Result<Yoke<P, C>, E>
1180    where
1181        P: for<'a> Yokeable<'a>,
1182        C: CloneableCart,
1183    {
1184        let p = f(self.get(), capture, PhantomData)?;
1185        Ok(Yoke {
1186            yokeable: KindaSortaDangling::new(
1187                // Safety: the resulting `yokeable` is dropped before the `cart` because
1188                // of the Yoke invariant. See the safety docs below for the justification of why
1189                // yokeable could only borrow from the Cart.
1190                unsafe { P::make(p) },
1191            ),
1192            cart: self.cart.clone(),
1193        })
1194    }
1195}
1196
1197impl<Y: for<'a> Yokeable<'a>, C: StableDeref> Yoke<Y, C>
1198where
1199    <C as Deref>::Target: 'static,
1200{
1201    /// Allows one to produce a new yoke from both the cart and the old yoke. This will move the
1202    /// cart, and the provided transformation is only allowed to use data known to be borrowed from
1203    /// the cart.
1204    ///
1205    /// If access to the old [`Yokeable`] `Y` is sufficient to produce the new [`Yokeable`] `P`,
1206    /// then [`Yoke::map_project`] should be preferred, as `map_with_cart` places additional
1207    /// constraints on the cart.
1208    ///
1209    /// This can be used, for example, to transform data between two formats, one of which contains
1210    /// more data:
1211    ///
1212    /// ```
1213    /// # use yoke::{Yoke, Yokeable};
1214    /// # use std::mem;
1215    /// # use std::rc::Rc;
1216    /// #
1217    /// // Both structs have `first_line`, which won't need to be recomputed in `map_with_cart`.
1218    /// // They also safely implement `Yokeable<'a>`
1219    /// struct Foo<'a> {
1220    ///     first_line: Option<&'a str>,
1221    /// }
1222    /// struct Bar<'a> {
1223    ///     first_line: Option<&'a str>,
1224    ///     last_line: Option<&'a str>,
1225    /// }
1226    ///
1227    /// fn foo_to_bar(
1228    ///     foo: Yoke<Foo<'static>, Rc<str>>,
1229    /// ) -> Yoke<Bar<'static>, Rc<str>> {
1230    ///     foo.map_with_cart(|foo, cart| {
1231    ///         Bar {
1232    ///             first_line: foo.first_line,
1233    ///             last_line: cart.lines().next_back(),
1234    ///         }
1235    ///     })
1236    /// }
1237    ///
1238    /// fn bar_to_foo(
1239    ///     bar: Yoke<Bar<'static>, Rc<str>>,
1240    /// ) -> Yoke<Foo<'static>, Rc<str>> {
1241    ///     bar.map_project(|bar, _| {
1242    ///         Foo {
1243    ///             first_line: bar.first_line,
1244    ///         }
1245    ///     })
1246    /// }
1247    ///
1248    /// #
1249    /// # unsafe impl<'a> Yokeable<'a> for Foo<'static> {
1250    /// #     type Output = Foo<'a>;
1251    /// #     fn transform(&'a self) -> &'a Foo<'a> {
1252    /// #         self
1253    /// #     }
1254    /// #
1255    /// #     fn transform_owned(self) -> Foo<'a> {
1256    /// #         // covariant lifetime cast, can be done safely
1257    /// #         self
1258    /// #     }
1259    /// #
1260    /// #     unsafe fn make(from: Foo<'a>) -> Self {
1261    /// #         unsafe { mem::transmute(from) }
1262    /// #     }
1263    /// #
1264    /// #     fn transform_mut<F>(&'a mut self, f: F)
1265    /// #     where
1266    /// #         F: 'static + FnOnce(&'a mut Self::Output),
1267    /// #     {
1268    /// #         unsafe { f(mem::transmute(self)) }
1269    /// #     }
1270    /// # }
1271    /// #
1272    /// # unsafe impl<'a> Yokeable<'a> for Bar<'static> {
1273    /// #     type Output = Bar<'a>;
1274    /// #     fn transform(&'a self) -> &'a Bar<'a> {
1275    /// #         self
1276    /// #     }
1277    /// #
1278    /// #     fn transform_owned(self) -> Bar<'a> {
1279    /// #         // covariant lifetime cast, can be done safely
1280    /// #         self
1281    /// #     }
1282    /// #
1283    /// #     unsafe fn make(from: Bar<'a>) -> Self {
1284    /// #         unsafe { mem::transmute(from) }
1285    /// #     }
1286    /// #
1287    /// #     fn transform_mut<F>(&'a mut self, f: F)
1288    /// #     where
1289    /// #         F: 'static + FnOnce(&'a mut Self::Output),
1290    /// #     {
1291    /// #         unsafe { f(mem::transmute(self)) }
1292    /// #     }
1293    /// # }
1294    /// ```
1295    //
1296    // Safety docs can be found at the end of the file.
1297    pub fn map_with_cart<P, F>(self, f: F) -> Yoke<P, C>
1298    where
1299        P: for<'a> Yokeable<'a>,
1300        F: for<'a> FnOnce(
1301            <Y as Yokeable<'a>>::Output,
1302            &'a <C as Deref>::Target,
1303        ) -> <P as Yokeable<'a>>::Output,
1304        <C as Deref>::Target: 'static,
1305    {
1306        let p = f(
1307            self.yokeable.into_inner().transform_owned(),
1308            self.cart.deref(),
1309        );
1310        Yoke {
1311            yokeable: KindaSortaDangling::new(
1312                // Safety: the resulting `yokeable` is dropped before the `cart` because
1313                // of the Yoke invariant. See the safety docs below for the justification of why
1314                // yokeable could only borrow from the Cart.
1315                unsafe { P::make(p) },
1316            ),
1317            cart: self.cart,
1318        }
1319    }
1320
1321    /// This is similar to [`Yoke::map_with_cart`], but it does not move [`Self`] and instead
1322    /// clones the cart (only if the cart is a [`CloneableCart`]).
1323    ///
1324    /// This is a bit more efficient than cloning the [`Yoke`] and then calling
1325    /// [`Yoke::map_with_cart`] because it will not clone fields that are going to be discarded.
1326    ///
1327    /// If access to the old [`Yokeable`] `Y` is sufficient to produce the new [`Yokeable`] `P`,
1328    /// then [`Yoke::map_project_cloned`] should be preferred, as `map_with_cart_cloned` places
1329    /// additional constraints on the cart.
1330    pub fn map_with_cart_cloned<'this, P, F>(&'this self, f: F) -> Yoke<P, C>
1331    where
1332        P: for<'a> Yokeable<'a>,
1333        F: for<'a> FnOnce(
1334            &'this <Y as Yokeable<'a>>::Output,
1335            &'a <C as Deref>::Target,
1336        ) -> <P as Yokeable<'a>>::Output,
1337        C: CloneableCart,
1338        <C as Deref>::Target: 'static,
1339    {
1340        let p = f(self.get(), self.cart.deref());
1341        Yoke {
1342            yokeable: KindaSortaDangling::new(
1343                // Safety: the resulting `yokeable` is dropped before the `cart` because
1344                // of the Yoke invariant. See the safety docs below for the justification of why
1345                // yokeable could only borrow from the Cart.
1346                unsafe { P::make(p) },
1347            ),
1348            cart: self.cart.clone(),
1349        }
1350    }
1351
1352    /// This is similar to [`Yoke::map_with_cart`], but it can also bubble up an error
1353    /// from the callback.
1354    ///
1355    /// If access to the old [`Yokeable`] `Y` is sufficient to produce the new [`Yokeable`] `P`,
1356    /// then [`Yoke::try_map_project`] should be preferred, as `try_map_with_cart` places
1357    /// additional constraints on the cart.
1358    ///
1359    /// ```
1360    /// # use std::rc::Rc;
1361    /// # use yoke::Yoke;
1362    /// # use std::str::{self, Utf8Error};
1363    /// #
1364    /// // Implements `Yokeable`
1365    /// type P<'a> = (&'a str, Option<&'a u8>);
1366    ///
1367    /// fn slice(
1368    ///     y: Yoke<&'static [u8], Rc<[u8]>>,
1369    /// ) -> Result<Yoke<P<'static>, Rc<[u8]>>, Utf8Error> {
1370    ///     y.try_map_with_cart(move |bytes, cart| {
1371    ///         Ok((str::from_utf8(bytes)?, bytes.first()))
1372    ///     })
1373    /// }
1374    /// ```
1375    pub fn try_map_with_cart<P, F, E>(self, f: F) -> Result<Yoke<P, C>, E>
1376    where
1377        P: for<'a> Yokeable<'a>,
1378        F: for<'a> FnOnce(
1379            <Y as Yokeable<'a>>::Output,
1380            &'a <C as Deref>::Target,
1381        ) -> Result<<P as Yokeable<'a>>::Output, E>,
1382        <C as Deref>::Target: 'static,
1383    {
1384        let p = f(
1385            self.yokeable.into_inner().transform_owned(),
1386            self.cart.deref(),
1387        )?;
1388        Ok(Yoke {
1389            yokeable: KindaSortaDangling::new(
1390                // Safety: the resulting `yokeable` is dropped before the `cart` because
1391                // of the Yoke invariant. See the safety docs below for the justification of why
1392                // yokeable could only borrow from the Cart.
1393                unsafe { P::make(p) },
1394            ),
1395            cart: self.cart,
1396        })
1397    }
1398
1399    /// This is similar to [`Yoke::try_map_with_cart`], but it does not move [`Self`] and instead
1400    /// clones the cart (only if the cart is a [`CloneableCart`]).
1401    ///
1402    /// This is a bit more efficient than cloning the [`Yoke`] and then calling
1403    /// [`Yoke::try_map_with_cart`] because it will not clone fields that are going to be discarded.
1404    ///
1405    /// If access to the old [`Yokeable`] `Y` is sufficient to producethe new [`Yokeable`] `P`,
1406    /// then [`Yoke::try_map_project_cloned`] should be preferred, as `try_map_with_cart_cloned`
1407    /// places additional constraints on the cart.
1408    pub fn try_map_with_cart_cloned<'this, P, F, E>(&'this self, f: F) -> Result<Yoke<P, C>, E>
1409    where
1410        P: for<'a> Yokeable<'a>,
1411        C: CloneableCart,
1412        F: for<'a> FnOnce(
1413            &'this <Y as Yokeable<'a>>::Output,
1414            &'a <C as Deref>::Target,
1415        ) -> Result<<P as Yokeable<'a>>::Output, E>,
1416        <C as Deref>::Target: 'static,
1417    {
1418        let p = f(self.get(), self.cart.deref())?;
1419        Ok(Yoke {
1420            yokeable: KindaSortaDangling::new(
1421                // Safety: the resulting `yokeable` is dropped before the `cart` because
1422                // of the Yoke invariant. See the safety docs below for the justification of why
1423                // yokeable could only borrow from the Cart.
1424                unsafe { P::make(p) },
1425            ),
1426            cart: self.cart.clone(),
1427        })
1428    }
1429}
1430
1431#[cfg(feature = "alloc")]
1432impl<Y: for<'a> Yokeable<'a>, C: 'static + Sized> Yoke<Y, Rc<C>> {
1433    /// Allows type-erasing the cart in a `Yoke<Y, Rc<C>>`.
1434    ///
1435    /// The yoke only carries around a cart type `C` for its destructor,
1436    /// since it needs to be able to guarantee that its internal references
1437    /// are valid for the lifetime of the Yoke. As such, the actual type of the
1438    /// Cart is not very useful unless you wish to extract data out of it
1439    /// via [`Yoke::backing_cart()`]. Erasing the cart allows for one to mix
1440    /// [`Yoke`]s obtained from different sources.
1441    ///
1442    /// In case the cart type `C` is not already an `Rc<T>`, you can use
1443    /// [`Yoke::wrap_cart_in_rc()`] to wrap it.
1444    ///
1445    /// ✨ *Enabled with the `alloc` Cargo feature.*
1446    ///
1447    /// # Example
1448    ///
1449    /// ```rust
1450    /// use std::rc::Rc;
1451    /// use yoke::erased::ErasedRcCart;
1452    /// use yoke::Yoke;
1453    ///
1454    /// let buffer1: Rc<String> = Rc::new("   foo bar baz  ".into());
1455    /// let buffer2: Box<String> = Box::new("  baz quux  ".into());
1456    ///
1457    /// let yoke1 =
1458    ///     Yoke::<&'static str, _>::attach_to_cart(buffer1, |rc| rc.trim());
1459    /// let yoke2 = Yoke::<&'static str, _>::attach_to_cart(buffer2, |b| b.trim());
1460    ///
1461    /// let erased1: Yoke<_, ErasedRcCart> = yoke1.erase_rc_cart();
1462    /// // Wrap the Box in an Rc to make it compatible
1463    /// let erased2: Yoke<_, ErasedRcCart> =
1464    ///     yoke2.wrap_cart_in_rc().erase_rc_cart();
1465    ///
1466    /// // Now erased1 and erased2 have the same type!
1467    /// ```
1468    pub fn erase_rc_cart(self) -> Yoke<Y, ErasedRcCart> {
1469        // Safety: safe because the cart is preserved, as it is just type-erased
1470        unsafe { self.replace_cart(|c| c as ErasedRcCart) }
1471    }
1472}
1473
1474#[cfg(feature = "alloc")]
1475impl<Y: for<'a> Yokeable<'a>, C: 'static + Sized + Send + Sync> Yoke<Y, Arc<C>> {
1476    /// Allows type-erasing the cart in a `Yoke<Y, Arc<C>>`.
1477    ///
1478    /// The yoke only carries around a cart type `C` for its destructor,
1479    /// since it needs to be able to guarantee that its internal references
1480    /// are valid for the lifetime of the Yoke. As such, the actual type of the
1481    /// Cart is not very useful unless you wish to extract data out of it
1482    /// via [`Yoke::backing_cart()`]. Erasing the cart allows for one to mix
1483    /// [`Yoke`]s obtained from different sources.
1484    ///
1485    /// In case the cart type `C` is not already an `Arc<T>`, you can use
1486    /// [`Yoke::wrap_cart_in_arc()`] to wrap it.
1487    ///
1488    /// ✨ *Enabled with the `alloc` Cargo feature.*
1489    ///
1490    /// # Example
1491    ///
1492    /// ```rust
1493    /// use std::sync::Arc;
1494    /// use yoke::erased::ErasedArcCart;
1495    /// use yoke::Yoke;
1496    ///
1497    /// let buffer1: Arc<String> = Arc::new("   foo bar baz  ".into());
1498    /// let buffer2: Box<String> = Box::new("  baz quux  ".into());
1499    ///
1500    /// let yoke1 =
1501    ///     Yoke::<&'static str, _>::attach_to_cart(buffer1, |arc| arc.trim());
1502    /// let yoke2 = Yoke::<&'static str, _>::attach_to_cart(buffer2, |b| b.trim());
1503    ///
1504    /// let erased1: Yoke<_, ErasedArcCart> = yoke1.erase_arc_cart();
1505    /// // Wrap the Box in an Rc to make it compatible
1506    /// let erased2: Yoke<_, ErasedArcCart> =
1507    ///     yoke2.wrap_cart_in_arc().erase_arc_cart();
1508    ///
1509    /// // Now erased1 and erased2 have the same type!
1510    /// ```
1511    pub fn erase_arc_cart(self) -> Yoke<Y, ErasedArcCart> {
1512        // Safety: safe because the cart is preserved, as it is just type-erased
1513        unsafe { self.replace_cart(|c| c as ErasedArcCart) }
1514    }
1515}
1516
1517#[cfg(feature = "alloc")]
1518impl<Y: for<'a> Yokeable<'a>, C: 'static + Sized> Yoke<Y, Box<C>> {
1519    /// Allows type-erasing the cart in a `Yoke<Y, Box<C>>`.
1520    ///
1521    /// The yoke only carries around a cart type `C` for its destructor,
1522    /// since it needs to be able to guarantee that its internal references
1523    /// are valid for the lifetime of the Yoke. As such, the actual type of the
1524    /// Cart is not very useful unless you wish to extract data out of it
1525    /// via [`Yoke::backing_cart()`]. Erasing the cart allows for one to mix
1526    /// [`Yoke`]s obtained from different sources.
1527    ///
1528    /// In case the cart type `C` is not already `Box<T>`, you can use
1529    /// [`Yoke::wrap_cart_in_box()`] to wrap it.
1530    ///
1531    /// ✨ *Enabled with the `alloc` Cargo feature.*
1532    ///
1533    /// # Example
1534    ///
1535    /// ```rust
1536    /// use std::rc::Rc;
1537    /// use yoke::erased::ErasedBoxCart;
1538    /// use yoke::Yoke;
1539    ///
1540    /// let buffer1: Rc<String> = Rc::new("   foo bar baz  ".into());
1541    /// let buffer2: Box<String> = Box::new("  baz quux  ".into());
1542    ///
1543    /// let yoke1 =
1544    ///     Yoke::<&'static str, _>::attach_to_cart(buffer1, |rc| rc.trim());
1545    /// let yoke2 = Yoke::<&'static str, _>::attach_to_cart(buffer2, |b| b.trim());
1546    ///
1547    /// // Wrap the Rc in an Box to make it compatible
1548    /// let erased1: Yoke<_, ErasedBoxCart> =
1549    ///     yoke1.wrap_cart_in_box().erase_box_cart();
1550    /// let erased2: Yoke<_, ErasedBoxCart> = yoke2.erase_box_cart();
1551    ///
1552    /// // Now erased1 and erased2 have the same type!
1553    /// ```
1554    pub fn erase_box_cart(self) -> Yoke<Y, ErasedBoxCart> {
1555        // Safety: safe because the cart is preserved, as it is just type-erased
1556        unsafe { self.replace_cart(|c| c as ErasedBoxCart) }
1557    }
1558}
1559
1560#[cfg(feature = "alloc")]
1561impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
1562    /// Helper function allowing one to wrap the cart type `C` in a `Box<T>`.
1563    /// Can be paired with [`Yoke::erase_box_cart()`]
1564    ///
1565    /// ✨ *Enabled with the `alloc` Cargo feature.*
1566    #[inline]
1567    pub fn wrap_cart_in_box(self) -> Yoke<Y, Box<C>> {
1568        // Safety: safe because the cart is preserved, as it is just wrapped.
1569        // `replace_cart()` explicitly allows panics.
1570        unsafe { self.replace_cart(Box::new) }
1571    }
1572    /// Helper function allowing one to wrap the cart type `C` in an `Rc<T>`.
1573    /// Can be paired with [`Yoke::erase_rc_cart()`], or generally used
1574    /// to make the [`Yoke`] cloneable.
1575    ///
1576    /// ✨ *Enabled with the `alloc` Cargo feature.*
1577    #[inline]
1578    pub fn wrap_cart_in_rc(self) -> Yoke<Y, Rc<C>> {
1579        // Safety: safe because the cart is preserved, as it is just wrapped.
1580        // `replace_cart()` explicitly allows panics.
1581        unsafe { self.replace_cart(Rc::new) }
1582    }
1583    /// Helper function allowing one to wrap the cart type `C` in an `Arc<T>`.
1584    /// Can be paired with [`Yoke::erase_arc_cart()`], or generally used
1585    /// to make the [`Yoke`] cloneable.
1586    ///
1587    /// ✨ *Enabled with the `alloc` Cargo feature.*
1588    #[inline]
1589    pub fn wrap_cart_in_arc(self) -> Yoke<Y, Arc<C>> {
1590        // Safety: safe because the cart is preserved, as it is just wrapped.
1591        // `replace_cart()` explicitly allows panics.
1592        unsafe { self.replace_cart(Arc::new) }
1593    }
1594}
1595
1596impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
1597    /// Helper function allowing one to wrap the cart type `C` in an [`EitherCart`].
1598    ///
1599    /// This function wraps the cart into the `A` variant. To wrap it into the
1600    /// `B` variant, use [`Self::wrap_cart_in_either_b()`].
1601    ///
1602    /// For an example, see [`EitherCart`].
1603    #[inline]
1604    pub fn wrap_cart_in_either_a<B>(self) -> Yoke<Y, EitherCart<C, B>> {
1605        // Safety: safe because the cart is preserved, as it is just wrapped.
1606        unsafe { self.replace_cart(EitherCart::A) }
1607    }
1608    /// Helper function allowing one to wrap the cart type `C` in an [`EitherCart`].
1609    ///
1610    /// This function wraps the cart into the `B` variant. To wrap it into the
1611    /// `A` variant, use [`Self::wrap_cart_in_either_a()`].
1612    ///
1613    /// For an example, see [`EitherCart`].
1614    #[inline]
1615    pub fn wrap_cart_in_either_b<A>(self) -> Yoke<Y, EitherCart<A, C>> {
1616        // Safety: safe because the cart is preserved, as it is just wrapped.
1617        unsafe { self.replace_cart(EitherCart::B) }
1618    }
1619}
1620
1621/// # Safety docs for `*map_project*()`
1622///
1623/// (Docs are on a private const to allow the use of `compile_fail` doctests)
1624///
1625/// This is safe to perform because of the choice of lifetimes on `f`, that is,
1626/// `for<a> fn(<Y as Yokeable<'a>>::Output, &'a ()) -> <P as Yokeable<'a>>::Output`.
1627///
1628/// Note that correctness arguments are similar if you replace `fn` with `FnOnce`.
1629///
1630/// What we want this function to do is take a Yokeable (`Y`) that is borrowing from the cart, and
1631/// produce another Yokeable (`P`) that also borrows from the same cart. There are a couple potential
1632/// hazards here:
1633///
1634/// - `P` ends up borrowing data from `Y` (or elsewhere) that did _not_ come from the cart,
1635///   for example `P` could borrow owned data from a `Cow`. This would make the `Yoke<P>` dependent
1636///   on data owned only by the `Yoke<Y>`.
1637/// - Borrowed data from `Y` escapes with the wrong lifetime
1638///
1639/// Let's walk through these and see how they're prevented.
1640///
1641/// ```rust,compile_fail,E0271
1642/// # use std::rc::Rc;
1643/// # use yoke::Yoke;
1644/// # use std::borrow::Cow;
1645/// fn borrow_potentially_owned(y: &Yoke<Cow<'static, str>, Rc<[u8]>>) -> Yoke<&'static str, Rc<[u8]>> {
1646///    y.map_project_cloned(|cow, _| &*cow)
1647/// }
1648/// ```
1649///
1650/// In this case, the lifetime of `&*cow` is `&'this str`, however the function needs to be able to return
1651/// `&'a str` _for all `'a`_, which isn't possible.
1652///
1653///
1654/// ```rust,compile_fail,E0515
1655/// # use std::rc::Rc;
1656/// # use yoke::Yoke;
1657/// # use std::borrow::Cow;
1658/// fn borrow_potentially_owned(y: Yoke<Cow<'static, str>, Rc<[u8]>>) -> Yoke<&'static str, Rc<[u8]>> {
1659///    y.map_project(|cow, _| &*cow)
1660/// }
1661/// ```
1662///
1663/// This has the same issue, `&*cow` is borrowing for a local lifetime.
1664///
1665/// Similarly, trying to project an owned field of a struct will produce similar errors:
1666///
1667/// ```rust,compile_fail
1668/// # use std::borrow::Cow;
1669/// # use yoke::{Yoke, Yokeable};
1670/// # use std::mem;
1671/// # use std::rc::Rc;
1672/// #
1673/// // also safely implements Yokeable<'a>
1674/// struct Bar<'a> {
1675///     owned: String,
1676///     string_2: &'a str,
1677/// }
1678///
1679/// fn map_project_owned(bar: &Yoke<Bar<'static>, Rc<[u8]>>) -> Yoke<&'static str, Rc<[u8]>> {
1680///     // ERROR (but works if you replace owned with string_2)
1681///     bar.map_project_cloned(|bar, _| &*bar.owned)
1682/// }
1683///
1684/// #
1685/// # unsafe impl<'a> Yokeable<'a> for Bar<'static> {
1686/// #     type Output = Bar<'a>;
1687/// #     fn transform(&'a self) -> &'a Bar<'a> {
1688/// #         self
1689/// #     }
1690/// #
1691/// #     fn transform_owned(self) -> Bar<'a> {
1692/// #         // covariant lifetime cast, can be done safely
1693/// #         self
1694/// #     }
1695/// #
1696/// #     unsafe fn make(from: Bar<'a>) -> Self {
1697/// #         let ret = mem::transmute_copy(&from);
1698/// #         mem::forget(from);
1699/// #         ret
1700/// #     }
1701/// #
1702/// #     fn transform_mut<F>(&'a mut self, f: F)
1703/// #     where
1704/// #         F: 'static + FnOnce(&'a mut Self::Output),
1705/// #     {
1706/// #         unsafe { f(mem::transmute(self)) }
1707/// #     }
1708/// # }
1709/// ```
1710///
1711/// Borrowed data from `Y` similarly cannot escape with the wrong lifetime because of the `for<'a>`, since
1712/// it will never be valid for the borrowed data to escape for all lifetimes of 'a. Internally, `.map_project()`
1713/// uses `.get()`, however the signature forces the callers to be able to handle every lifetime.
1714///
1715///  `'a` is the only lifetime that matters here; `Yokeable`s must be `'static` and since
1716/// `Output` is an associated type it can only have one lifetime, `'a` (there's nowhere for it to get another from).
1717/// `Yoke`s can get additional lifetimes via the cart, and indeed, `map_project()` can operate on `Yoke<_, &'b [u8]>`,
1718/// however this lifetime is inaccessible to the closure, and even if it were accessible the `for<'a>` would force
1719/// it out of the output. All external lifetimes (from other found outside the yoke/closures
1720/// are similarly constrained here.
1721///
1722/// Essentially, safety is achieved by using `for<'a> fn(...)` with `'a` used in both `Yokeable`s to ensure that
1723/// the output yokeable can _only_ have borrowed data flow in to it from the input. All paths of unsoundness require the
1724/// unification of an existential and universal lifetime, which isn't possible.
1725const _: () = ();
1726
1727/// # Safety docs for `attach_to_cart()`'s signature
1728///
1729/// The `attach_to_cart()` family of methods get by by using the following bound:
1730///
1731/// ```rust,ignore
1732/// F: for<'de> FnOnce(&'de <C as Deref>::Target) -> <Y as Yokeable<'de>>::Output,
1733/// C::Target: 'static
1734/// ```
1735///
1736/// to enforce that the yoking closure produces a yokeable that is *only* allowed to borrow from the cart.
1737/// A way to be sure of this is as follows: imagine if `F` *did* borrow data of lifetime `'a` and stuff it in
1738/// its output. Then that lifetime `'a` would have to live at least as long as `'de` *for all `'de`*.
1739/// The only lifetime that satisfies that is `'static` (since at least one of the potential `'de`s is `'static`),
1740/// and we're fine with that.
1741///
1742/// ## Implied bounds and variance
1743///
1744/// The `C::Target: 'static` bound is tricky, however. Let's imagine a situation where we *didn't* have that bound.
1745///
1746/// One thing to remember is that we are okay with the cart itself borrowing from places,
1747/// e.g. `&[u8]` is a valid cart, as is `Box<&[u8]>`. `C` is not `'static`.
1748///
1749/// (I'm going to use `CT` in prose to refer to `C::Target` here, since almost everything here has to do
1750/// with `C::Target` and not C itself.)
1751///
1752/// Unfortunately, there's a sneaky additional bound inside `F`. The signature of `F` is *actually*
1753///
1754/// ```rust,ignore
1755/// F: for<'de> where<C::Target: 'de> FnOnce(&'de C::Target) -> <Y as Yokeable<'de>>::Output
1756/// ```
1757///
1758/// using made-up "where clause inside HRTB" syntax to represent a type that can be represented inside the compiler
1759/// and type system but not in Rust code. The `CT: 'de` bond comes from the `&'de C::Target`: any time you
1760/// write `&'a T`, an implied bound of `T: 'a` materializes and is stored alongside it, since references cannot refer
1761/// to data that itself refers to data of shorter lifetimes. If a reference is valid, its referent must be valid for
1762/// the duration of the reference's lifetime, so every reference *inside* its referent must also be valid, giving us `T: 'a`.
1763/// This kind of constraint is often called a "well formedness" constraint: `&'a T` is not "well formed" without that
1764/// bound, and rustc is being helpful by giving it to us for free.
1765///
1766/// Unfortunately, this messes with our universal quantification. The `for<'de>` is no longer "For all lifetimes `'de`",
1767/// it is "for all lifetimes `'de` *where `CT: 'de`*". And if `CT` borrows from somewhere (with lifetime `'ct`), then we get a
1768/// `'ct: 'de` bound, and `'de` candidates that live longer than `'ct` won't actually be considered.
1769/// The neat little logic at the beginning stops working.
1770///
1771/// `attach_to_cart()` will instead enforce that the produced yokeable *either* borrows from the cart (fine), or from
1772/// data that has a lifetime that is at least `'ct`. Which means that `attach_to_cart()` will allow us to borrow locals
1773/// provided they live at least as long as `'ct`.
1774///
1775/// Is this a problem?
1776///
1777/// This is totally fine if CT's lifetime is covariant: if C is something like `Box<&'ct [u8]>`, even if our
1778/// yoked object borrows from locals outliving `'ct`, our Yoke can't outlive that
1779/// lifetime `'ct` anyway (since it's a part of the cart type), so we're fine.
1780///
1781/// However it's completely broken for contravariant carts (e.g. `Box<fn(&'ct u8)>`). In that case
1782/// we still get `'ct: 'de`, and we still end up being able to
1783/// borrow from locals that outlive `'ct`. However, our Yoke _can_ outlive
1784/// that lifetime, because Yoke shares its variance over `'ct`
1785/// with the cart type, and the cart type is contravariant over `'ct`.
1786/// So the Yoke can be upcast to having a longer lifetime than `'ct`, and *that* Yoke
1787/// can outlive `'ct`.
1788///
1789/// We fix this by forcing `C::Target: 'static` in `attach_to_cart()`, which would make it work
1790/// for fewer types, but would also allow Yoke to continue to be covariant over cart lifetimes if necessary.
1791///
1792/// An alternate fix would be to not allowing yoke to ever be upcast over lifetimes contained in the cart
1793/// by forcing them to be invariant. This is a bit more restrictive and affects *all* `Yoke` users, not just
1794/// those using `attach_to_cart()`.
1795///
1796/// See <https://github.com/unicode-org/icu4x/issues/2926>
1797/// See also <https://github.com/rust-lang/rust/issues/106431> for potentially fixing this upstream by
1798/// changing how the bound works.
1799///
1800/// # Tests
1801///
1802/// Here's a broken `attach_to_cart()` that attempts to borrow from a local:
1803///
1804/// ```rust,compile_fail,E0597
1805/// use yoke::Yoke;
1806///
1807/// let cart = vec![1, 2, 3, 4].into_boxed_slice();
1808/// let local = vec![4, 5, 6, 7];
1809/// let yoke: Yoke<&[u8], Box<[u8]>> = Yoke::attach_to_cart(cart, |_| &*local);
1810/// ```
1811///
1812/// Fails as expected.
1813///
1814/// And here's a working one with a local borrowed cart that does not do any sneaky borrows whilst attaching.
1815///
1816/// ```rust
1817/// use yoke::Yoke;
1818///
1819/// let cart = vec![1, 2, 3, 4].into_boxed_slice();
1820/// let yoke: Yoke<&[u8], &[u8]> = Yoke::attach_to_cart(&cart, |c| c);
1821/// ```
1822///
1823/// Here's an `attach_to_cart()` that attempts to borrow from a longer-lived local due to
1824/// the cart being covariant. It fails, but would not if the alternate fix of forcing Yoke to be invariant
1825/// were implemented. It is technically a safe operation:
1826///
1827/// ```rust,compile_fail,E0597
1828/// use yoke::Yoke;
1829/// // longer lived
1830/// let local = vec![4, 5, 6, 7];
1831///
1832/// let backing = vec![1, 2, 3, 4];
1833/// let cart = Box::new(&*backing);
1834///
1835/// let yoke: Yoke<&[u8], Box<&[u8]>> = Yoke::attach_to_cart(cart, |_| &*local);
1836/// println!("{:?}", yoke.get());
1837/// ```
1838///
1839/// Finally, here's an `attach_to_cart()` that attempts to borrow from a longer lived local
1840/// in the case of a contravariant lifetime. It does not compile, but in and of itself is not dangerous:
1841///
1842/// ```rust,compile_fail,E0597
1843/// use yoke::Yoke;
1844///
1845/// type Contra<'a> = fn(&'a ());
1846///
1847/// let local = String::from("Hello World!");
1848/// let yoke: Yoke<&'static str, Box<Contra<'_>>> = Yoke::attach_to_cart(Box::new((|_| {}) as _), |_| &local[..]);
1849/// println!("{:?}", yoke.get());
1850/// ```
1851///
1852/// It is dangerous if allowed to transform (testcase from #2926)
1853///
1854/// ```rust,compile_fail,E0597
1855/// use yoke::Yoke;
1856///
1857/// type Contra<'a> = fn(&'a ());
1858///
1859///
1860/// let local = String::from("Hello World!");
1861/// let yoke: Yoke<&'static str, Box<Contra<'_>>> = Yoke::attach_to_cart(Box::new((|_| {}) as _), |_| &local[..]);
1862/// println!("{:?}", yoke.get());
1863/// let yoke_longer: Yoke<&'static str, Box<Contra<'static>>> = yoke;
1864/// let leaked: &'static Yoke<&'static str, Box<Contra<'static>>> = Box::leak(Box::new(yoke_longer));
1865/// let reference: &'static str = leaked.get();
1866///
1867/// println!("pre-drop: {reference}");
1868/// drop(local);
1869/// println!("post-drop: {reference}");
1870/// ```
1871const _: () = ();
1872
1873/// # Safety docs for `*map_with_cart*()`
1874///
1875/// [`Yoke::map_with_cart`] has both the problems of [`Yoke::map_project`] (with a
1876/// potentially-pathological callback) and [`Yoke::attach_to_cart`] (with a potentially
1877/// pathological cart, capable of permitting a bad callback).
1878///
1879/// [`map_project`] forces the callback to be well-behaved with the bounds:
1880/// ```rust,ignore
1881/// F: for<'a> FnOnce(
1882///     <Y as Yokeable<'a>>::Output,
1883///     PhantomData<&'a ()>,
1884/// ) -> <P as Yokeable<'a>>::Output,
1885/// ```
1886///
1887/// The `for<'a>` constraint prevents `F` from inserting additional borrows that did not come
1888/// from the input; `<P as Yokeable<'a>>::Output` can be `'static` or only `'a`, but that
1889/// `'a` could potentially be `'static` as well. Therefore, `F` has to be capable of returning
1890/// `'static` data (under certain constraints), and cannot insert additional borrows. Nor can a
1891/// reference leak out, as for a sufficiently short `'a`, the data would not live long enough.
1892/// The `PhantomData<&'a ()>` is just to make sure that the lifetime `'a` is constrained
1893/// to fix <https://github.com/rust-lang/rust/issues/86702>.
1894///
1895/// Next, [`Yoke::attach_to_cart`] follows mostly the same approach, but needs to ensure that
1896/// the `for<'a>` bound remains a fully universal quantifier.
1897/// It uses the bounds:
1898/// ```rust,ignore
1899/// F: for<'de> FnOnce(&'de <C as Deref>::Target) -> <Y as Yokeable<'de>>::Output,
1900/// <C as Deref>::Target: 'static,
1901/// ```
1902///
1903/// The problem is that the `for<'de>` quantifier is bounded by whatever the lifetime of
1904/// `<C as Deref>::Target` is, so for it to cover all lifetimes, `<C as Deref>::Target` must
1905/// be `'static`.
1906///
1907///
1908/// [`Yoke::map_with_cart`] combines the relevant bounds into one:
1909/// ```rust,ignore
1910/// F: for<'a> FnOnce(
1911///     <Y as Yokeable<'a>>::Output,
1912///     &'a <C as Deref>::Target,
1913/// ) -> <P as Yokeable<'a>>::Output,
1914/// <C as Deref>::Target: 'static,
1915/// ```
1916///
1917/// The techniques ensure that, for any lifetime `'a`, the callback must be capable of taking in
1918/// data from the old `Yokeable` and from the cart which is known only to outlive `'a`, and return
1919/// data that outlives `'a`. `F` is incapable of inserting external data which is not `'static`,
1920/// and is otherwise constrained to using the data in the cart and old `Yokeable` to produce
1921/// a new `Yokeable`.
1922/// A `PhantomData` is not needed, since the lifetime `'a` is constrained by
1923/// `&'a <C as Deref>::Target`.
1924///
1925/// # Fail tests
1926///
1927/// We can confirm that problematic cases analogous to those in [`Yoke::map_project`] and
1928/// [`Yoke::attach_to_cart`] still fail here. They're copied and adapted slightly.
1929///
1930/// ### From `map_project`'s safety docs
1931///
1932/// ```rust,compile_fail
1933/// # use std::rc::Rc;
1934/// # use yoke::Yoke;
1935/// # use std::borrow::Cow;
1936/// fn borrow_potentially_owned(y: &Yoke<Cow<'static, str>, Rc<[u8]>>) -> Yoke<&'static str, Rc<[u8]>> {
1937///    y.map_with_cart_cloned(|cow, _cart| &**cow)
1938/// }
1939/// ```
1940///
1941/// ```rust,compile_fail,E0515
1942/// # use std::rc::Rc;
1943/// # use yoke::Yoke;
1944/// # use std::borrow::Cow;
1945/// fn borrow_potentially_owned(y: Yoke<Cow<'static, str>, Rc<[u8]>>) -> Yoke<&'static str, Rc<[u8]>> {
1946///    y.map_with_cart(|cow: Cow<'_, _>, _cart| &*cow)
1947/// }
1948/// ```
1949///
1950/// ```rust,compile_fail
1951/// # use std::borrow::Cow;
1952/// # use yoke::{Yoke, Yokeable};
1953/// # use std::mem;
1954/// # use std::rc::Rc;
1955/// #
1956/// // also safely implements Yokeable<'a>
1957/// struct Bar<'a> {
1958///     owned: String,
1959///     string_2: &'a str,
1960/// }
1961///
1962/// fn map_with_cart_owned(bar: &Yoke<Bar<'static>, Rc<[u8]>>) -> Yoke<&'static str, Rc<[u8]>> {
1963///     // ERROR (but works if you replace owned with string_2)
1964///     bar.map_with_cart_cloned(|bar, _cart| &*bar.owned)
1965/// }
1966///
1967/// #
1968/// # unsafe impl<'a> Yokeable<'a> for Bar<'static> {
1969/// #     type Output = Bar<'a>;
1970/// #     fn transform(&'a self) -> &'a Bar<'a> {
1971/// #         self
1972/// #     }
1973/// #
1974/// #     fn transform_owned(self) -> Bar<'a> {
1975/// #         // covariant lifetime cast, can be done safely
1976/// #         self
1977/// #     }
1978/// #
1979/// #     unsafe fn make(from: Bar<'a>) -> Self {
1980/// #         let ret = mem::transmute_copy(&from);
1981/// #         mem::forget(from);
1982/// #         ret
1983/// #     }
1984/// #
1985/// #     fn transform_mut<F>(&'a mut self, f: F)
1986/// #     where
1987/// #         F: 'static + FnOnce(&'a mut Self::Output),
1988/// #     {
1989/// #         unsafe { f(mem::transmute(self)) }
1990/// #     }
1991/// # }
1992/// ```
1993///
1994/// ### From `attach_to_cart`'s safety docs
1995///
1996/// Being slightly paranoid, confirm that the expected line is the one causing the error.
1997/// ```rust
1998/// use std::rc::Rc;
1999/// use yoke::Yoke;
2000///
2001/// let cart: Vec<u8> = vec![1, 2, 3, 4];
2002/// let cart: Rc<[u8]> = Rc::from(&*cart);
2003///
2004/// let local = vec![4, 5, 6, 7];
2005/// let local: Rc<[u8]> = Rc::from(&*local);
2006///
2007/// let yoke: Yoke<&[u8], Rc<[u8]>> = Yoke::attach_to_cart(cart, |cart| cart);
2008/// let yoke: Yoke<&[u8], Rc<[u8]>> = yoke.map_with_cart(|_, cart| cart);
2009/// ```
2010///
2011/// ```rust,compile_fail,E0597
2012/// use std::rc::Rc;
2013/// use yoke::Yoke;
2014///
2015/// let cart: Vec<u8> = vec![1, 2, 3, 4];
2016/// let cart: Rc<[u8]> = Rc::from(&*cart);
2017///
2018/// let local = vec![4, 5, 6, 7];
2019/// let local: Rc<[u8]> = Rc::from(&*local);
2020///
2021/// let yoke: Yoke<&[u8], Rc<[u8]>> = Yoke::attach_to_cart(cart, |cart| &*cart);
2022/// let yoke: Yoke<&[u8], Rc<[u8]>> = yoke.map_with_cart(|_, _| &*local);
2023/// ```
2024///
2025///
2026/// ```rust
2027/// use std::rc::Rc;
2028/// use yoke::Yoke;
2029///
2030/// // longer lived
2031/// let local = vec![4_u8, 5, 6, 7];
2032/// let local: Rc<[u8]> = Rc::from(&*local);
2033///
2034/// let backing = vec![1_u8, 2, 3, 4];
2035/// let cart: Rc<[u8]> = Rc::from(&*backing);
2036///
2037/// let yoke: Yoke<&[u8], Rc<[u8]>> = Yoke::attach_to_cart(cart, |cart| cart);
2038/// let yoke: Yoke<&[u8], Rc<[u8]>> = yoke.map_with_cart(|_, cart: &[u8]| cart);
2039/// println!("{:?}", yoke.get());
2040/// ```
2041///
2042/// ```rust,compile_fail,E0425
2043/// use std::rc::Rc;
2044/// use yoke::Yoke;
2045///
2046/// // longer lived
2047/// let local: Rc<[u8]> = Rc::from(&*local);
2048///
2049/// let backing = vec![1_u8, 2, 3, 4];
2050/// let cart: Rc<[u8]> = Rc::from(&*backing);
2051///
2052/// let yoke: Yoke<&[u8], Rc<[u8]>> = Yoke::attach_to_cart(cart, |cart| &*cart);
2053/// let yoke: Yoke<&[u8], Rc<[u8]>> = yoke.map_with_cart(|_, cart: &[u8]| &*local);
2054/// println!("{:?}", yoke.get());
2055/// ```
2056///
2057///
2058/// I don't see a way to closely adapt `attach_to_cart`'s last two test cases on contravariant
2059/// carts, since the problematic `Cart` type is stopped at the stage of construction. We can use
2060/// one of `Yoke`'s other constructors instead, and try mapping it.
2061///
2062/// ```rust
2063/// use std::rc::Rc;
2064/// use yoke::Yoke;
2065///
2066/// type Contra<'a> = fn(&'a ());
2067///
2068/// let local = String::from("Hello World!");
2069/// let yoke: Yoke<&'static str, Option<Rc<Contra<'_>>>> =
2070///     Yoke::new_owned("hi");
2071/// println!("{:?}", yoke.get());
2072/// ```
2073///
2074/// This case might actually be fine to allow, since `attach_to_cart` could not possibly succeed
2075/// with this cart type and thus the `Yokeable` must always be owned. But whether it's safe to
2076/// permit *any* contravariant cart in `map_with_cart` is not immediately clear to me. Therefore,
2077/// compile fail.
2078/// ```rust,compile_fail
2079/// use std::rc::Rc;
2080/// use yoke::Yoke;
2081///
2082/// type Contra<'a> = fn(&'a ());
2083///
2084/// fn scope<'b>() {
2085///     let local = String::from("Hello World!");
2086///     let yoke: Yoke<&'static str, Option<Rc<Contra<'b>>>> = Yoke::new_owned("hi");
2087///     let yoke: Yoke<&'static str, Rc<Option<Rc<Contra<'b>>>>> = yoke.wrap_cart_in_rc);
2088///     let yoke: Yoke<&'static str, Rc<Option<Rc<Contra<'b>>>>> = yoke.map_with_cart(|yoke, _| yoke);
2089///     println!("{:?}", yoke.get());
2090/// }
2091/// ```
2092///
2093/// This version succeeds, though.
2094/// ```rust
2095/// use std::rc::Rc;
2096/// use yoke::Yoke;
2097///
2098/// type Contra<'a> = fn(&'a ());
2099///
2100/// fn scope<'b>() {
2101///     let local = String::from("Hello World!");
2102///     let yoke: Yoke<&'static str, Option<Rc<Contra<'b>>>> =
2103///         Yoke::new_owned("hi");
2104///     let yoke: Yoke<&'static str, Rc<Option<Rc<Contra<'b>>>>> =
2105///         yoke.wrap_cart_in_rc();
2106///     let yoke: Yoke<&'static str, Rc<Option<Rc<Contra<'static>>>>> = yoke;
2107///     let yoke: Yoke<&'static str, Rc<Option<Rc<Contra<'static>>>>> =
2108///         yoke.map_with_cart(|yoke, _| yoke);
2109///     println!("{:?}", yoke.get());
2110/// }
2111/// ```
2112///
2113/// # Test running the function
2114///
2115/// The above verifies the method signature. We can also check that the implementation is correct,
2116/// by running Miri on the following test (analogous to [`Yoke::map_with_cart`]'s doctest):
2117/// ```
2118/// use std::rc::Rc;
2119/// use yoke::Yoke;
2120///
2121/// type Foo<'a> = Option<&'a str>;
2122/// type Bar<'a> = (Option<&'a str>, Option<&'a str>);
2123///
2124/// fn foo_to_bar(
2125///     foo: Yoke<Foo<'static>, Rc<str>>,
2126/// ) -> Yoke<Bar<'static>, Rc<str>> {
2127///     foo.map_with_cart(|foo, cart| (foo, cart.lines().next_back()))
2128/// }
2129///
2130/// fn foo_to_bar_cloned(
2131///     foo: &Yoke<Foo<'static>, Rc<str>>,
2132/// ) -> Yoke<Bar<'static>, Rc<str>> {
2133///     foo.map_with_cart_cloned(|foo, cart| (*foo, cart.lines().next_back()))
2134/// }
2135///
2136/// fn bar_to_foo(
2137///     bar: Yoke<Bar<'static>, Rc<str>>,
2138/// ) -> Yoke<Foo<'static>, Rc<str>> {
2139///     bar.map_project(|bar, _| (bar.0))
2140/// }
2141///
2142/// fn main() {
2143///     fn assert_hello_world(bar: &Yoke<Bar<'static>, Rc<str>>) {
2144///         assert_eq!(bar.get().0, Some("hello"));
2145///         assert_eq!(bar.get().1, Some("world"));
2146///     }
2147///
2148///     let foo = Yoke::<Foo<'static>, Rc<str>>::attach_to_cart(
2149///         Rc::from("hello\nworld"),
2150///         |cart| cart.lines().next(),
2151///     );
2152///
2153///     assert_eq!(*foo.get(), Some("hello"));
2154///
2155///     let bar = foo_to_bar(foo);
2156///     assert_hello_world(&bar);
2157///
2158///     let foo = bar_to_foo(bar);
2159///
2160///     let bar_one = foo_to_bar_cloned(&foo);
2161///     let bar_two = foo_to_bar_cloned(&foo);
2162///
2163///     assert_hello_world(&bar_one);
2164///     assert_hello_world(&bar_two);
2165/// }
2166/// ```
2167const _: () = ();