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::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    /// If the callback needs to return `'static` data, then [`Yoke::with_mut_return`] can be
396    /// used until the next breaking release of `yoke`, at which time the callback to this
397    /// function will be able to return any `'static` data.
398    ///
399    /// See [`Yokeable::transform_mut()`] for why this operation is safe.
400    ///
401    /// # Example
402    ///
403    /// This can be used to partially mutate the stored data, provided
404    /// no _new_ borrowed data is introduced.
405    ///
406    /// ```rust
407    /// # use yoke::{Yoke, Yokeable};
408    /// # use std::rc::Rc;
409    /// # use std::borrow::Cow;
410    /// # use std::mem;
411    /// # fn load_from_cache(_filename: &str) -> Rc<[u8]> {
412    /// #     // dummy implementation
413    /// #     Rc::new([0x5, 0, 0, 0, 0, 0, 0, 0, 0x68, 0x65, 0x6c, 0x6c, 0x6f])
414    /// # }
415    /// #
416    /// # fn load_object(filename: &str) -> Yoke<Bar<'static>, Rc<[u8]>> {
417    /// #     let rc: Rc<[u8]> = load_from_cache(filename);
418    /// #     Yoke::<Bar<'static>, Rc<[u8]>>::attach_to_cart(rc, |data: &[u8]| {
419    /// #         // A real implementation would properly deserialize `Bar` as a whole
420    /// #         Bar {
421    /// #             numbers: Cow::Borrowed(bincode::deserialize(data).unwrap()),
422    /// #             string: Cow::Borrowed(bincode::deserialize(data).unwrap()),
423    /// #             owned: Vec::new(),
424    /// #         }
425    /// #     })
426    /// # }
427    ///
428    /// #[derive(Yokeable)]
429    /// struct Bar<'a> {
430    ///     numbers: Cow<'a, [u8]>,
431    ///     string: Cow<'a, str>,
432    ///     owned: Vec<u8>,
433    /// }
434    ///
435    /// // `load_object()` deserializes an object from a file
436    /// let mut bar: Yoke<Bar, _> = load_object("filename.bincode");
437    /// assert_eq!(bar.get().string, "hello");
438    /// assert!(matches!(bar.get().string, Cow::Borrowed(_)));
439    /// assert_eq!(&*bar.get().numbers, &[0x68, 0x65, 0x6c, 0x6c, 0x6f]);
440    /// assert!(matches!(bar.get().numbers, Cow::Borrowed(_)));
441    /// assert_eq!(&*bar.get().owned, &[]);
442    ///
443    /// bar.with_mut(|bar| {
444    ///     bar.string.to_mut().push_str(" world");
445    ///     bar.owned.extend_from_slice(&[1, 4, 1, 5, 9]);
446    /// });
447    ///
448    /// assert_eq!(bar.get().string, "hello world");
449    /// assert!(matches!(bar.get().string, Cow::Owned(_)));
450    /// assert_eq!(&*bar.get().owned, &[1, 4, 1, 5, 9]);
451    /// // Unchanged and still Cow::Borrowed
452    /// assert_eq!(&*bar.get().numbers, &[0x68, 0x65, 0x6c, 0x6c, 0x6f]);
453    /// assert!(matches!(bar.get().numbers, Cow::Borrowed(_)));
454    /// ```
455    pub fn with_mut<'a, F>(&'a mut self, f: F)
456    where
457        F: 'static + for<'b> FnOnce(&'b mut <Y as Yokeable<'a>>::Output),
458    {
459        self.yokeable.transform_mut(f);
460    }
461
462    /// Mutate the stored [`Yokeable`] data, and return `'static` data (possibly just `()`).
463    ///
464    /// See [`Yokeable::transform_mut()`] for why this operation is safe, noting that no
465    /// `'static`.
466    ///
467    /// ### Will be removed
468    /// This method will be removed on the next breaking release of `yoke`, when the callback of
469    /// [`Yoke::with_mut`] will gain the ability to return any `R: 'static` and supersede this
470    /// method.
471    pub fn with_mut_return<'a, F, R>(&'a mut self, f: F) -> R
472    where
473        F: 'static + for<'b> FnOnce(&'b mut <Y as Yokeable<'a>>::Output) -> R,
474        R: 'static,
475    {
476        utils::transform_mut_yokeable(&mut *self.yokeable, f)
477    }
478
479    /// Helper function allowing one to wrap the cart type `C` in an `Option<T>`.
480    #[inline]
481    pub fn wrap_cart_in_option(self) -> Yoke<Y, Option<C>> {
482        // Safety: the cart is preserved (since it is just wrapped into a Some),
483        // so any data it owns is too.
484        unsafe { self.replace_cart(Some) }
485    }
486}
487
488impl<Y: for<'a> Yokeable<'a>> Yoke<Y, ()> {
489    /// Construct a new [`Yoke`] from static data. There will be no
490    /// references to `cart` here since [`Yokeable`]s are `'static`,
491    /// this is good for e.g. constructing fully owned
492    /// [`Yoke`]s with no internal borrowing.
493    ///
494    /// This is similar to [`Yoke::new_owned()`] but it does not allow you to
495    /// mix the [`Yoke`] with borrowed data. This is primarily useful
496    /// for using [`Yoke`] in generic scenarios.
497    ///
498    /// # Example
499    ///
500    /// ```rust
501    /// # use yoke::Yoke;
502    /// # use std::borrow::Cow;
503    ///
504    /// let owned: Cow<str> = "hello".to_owned().into();
505    /// // this yoke can be intermingled with actually-borrowed Yokes
506    /// let yoke: Yoke<Cow<str>, ()> = Yoke::new_always_owned(owned);
507    ///
508    /// assert_eq!(yoke.get(), "hello");
509    /// ```
510    pub fn new_always_owned(yokeable: Y) -> Self {
511        Self {
512            // Safety note: this `yokeable` certainly does not reference data owned by (), so we do
513            // not have to worry about when the `yokeable` is dropped.
514            yokeable: KindaSortaDangling::new(yokeable),
515            cart: (),
516        }
517    }
518
519    /// Obtain the yokeable out of a `Yoke<Y, ()>`
520    ///
521    /// For most `Yoke` types this would be unsafe but it's
522    /// fine for `Yoke<Y, ()>` since there are no actual internal
523    /// references
524    pub fn into_yokeable(self) -> Y {
525        // Safety note: since `yokeable` cannot reference data owned by `()`, this is certainly
526        // safe.
527        self.yokeable.into_inner()
528    }
529}
530
531// C does not need to be StableDeref here, if the yoke was constructed it's valid,
532// and new_owned() doesn't construct a yokeable that uses references,
533impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, Option<C>> {
534    /// Construct a new [`Yoke`] from static data. There will be no
535    /// references to `cart` here since [`Yokeable`]s are `'static`,
536    /// this is good for e.g. constructing fully owned
537    /// [`Yoke`]s with no internal borrowing.
538    ///
539    /// This can be paired with [`Yoke:: wrap_cart_in_option()`] to mix owned
540    /// and borrowed data.
541    ///
542    /// If you do not wish to pair this with borrowed data, [`Yoke::new_always_owned()`] can
543    /// be used to get a [`Yoke`] API on always-owned data.
544    ///
545    /// # Example
546    ///
547    /// ```rust
548    /// # use yoke::Yoke;
549    /// # use std::borrow::Cow;
550    /// # use std::rc::Rc;
551    ///
552    /// let owned: Cow<str> = "hello".to_owned().into();
553    /// // this yoke can be intermingled with actually-borrowed Yokes
554    /// let yoke: Yoke<Cow<str>, Option<Rc<[u8]>>> = Yoke::new_owned(owned);
555    ///
556    /// assert_eq!(yoke.get(), "hello");
557    /// ```
558    pub const fn new_owned(yokeable: Y) -> Self {
559        Self {
560            // Safety note: this `yokeable` is known not to borrow from the cart.
561            yokeable: KindaSortaDangling::new(yokeable),
562            cart: None,
563        }
564    }
565
566    /// Obtain the yokeable out of a `Yoke<Y, Option<C>>` if possible.
567    ///
568    /// If the cart is `None`, this returns `Ok`, but if the cart is `Some`,
569    /// this returns `self` as an error.
570    pub fn try_into_yokeable(self) -> Result<Y, Self> {
571        // Safety: if the cart is None there is no way for the yokeable to
572        // have references into it because of the cart invariant.
573        match self.cart {
574            Some(_) => Err(self),
575            None => Ok(self.yokeable.into_inner()),
576        }
577    }
578}
579
580impl<Y: for<'a> Yokeable<'a>, C: CartablePointerLike> Yoke<Y, Option<C>> {
581    /// Converts a `Yoke<Y, Option<C>>` to `Yoke<Y, CartableOptionPointer<C>>`
582    /// for better niche optimization when stored as a field.
583    ///
584    /// # Examples
585    ///
586    /// ```
587    /// use std::borrow::Cow;
588    /// use yoke::Yoke;
589    ///
590    /// let yoke: Yoke<Cow<[u8]>, Box<Vec<u8>>> =
591    ///     Yoke::attach_to_cart(vec![10, 20, 30].into(), |c| c.into());
592    ///
593    /// let yoke_option = yoke.wrap_cart_in_option();
594    /// let yoke_option_pointer = yoke_option.convert_cart_into_option_pointer();
595    /// ```
596    ///
597    /// The niche improves stack sizes:
598    ///
599    /// ```
600    /// use yoke::Yoke;
601    /// use yoke::cartable_ptr::CartableOptionPointer;
602    /// use std::mem::size_of;
603    /// use std::rc::Rc;
604    ///
605    /// // The data struct is 6 words:
606    /// # #[derive(yoke::Yokeable)]
607    /// # struct MyDataStruct<'a> {
608    /// #     _s: (usize, usize, usize, usize),
609    /// #     _p: &'a str,
610    /// # }
611    /// const W: usize = core::mem::size_of::<usize>();
612    /// assert_eq!(W * 6, size_of::<MyDataStruct>());
613    ///
614    /// // An enum containing the data struct with an `Option<Rc>` cart is 8 words:
615    /// enum StaticOrYoke1 {
616    ///     Static(&'static MyDataStruct<'static>),
617    ///     Yoke(Yoke<MyDataStruct<'static>, Option<Rc<String>>>),
618    /// }
619    /// assert_eq!(W * 8, size_of::<StaticOrYoke1>());
620    ///
621    /// // When using `CartableOptionPointer``, we need only 7 words for the same behavior:
622    /// enum StaticOrYoke2 {
623    ///     Static(&'static MyDataStruct<'static>),
624    ///     Yoke(Yoke<MyDataStruct<'static>, CartableOptionPointer<Rc<String>>>),
625    /// }
626    /// assert_eq!(W * 7, size_of::<StaticOrYoke2>());
627    /// ```
628    #[inline]
629    pub fn convert_cart_into_option_pointer(self) -> Yoke<Y, CartableOptionPointer<C>> {
630        match self.cart {
631            Some(cart) => Yoke {
632                // Safety note: CartableOptionPointer::from_cartable only wraps the `cart`,
633                // so the data referenced by the yokeable is still live.
634                yokeable: self.yokeable,
635                cart: CartableOptionPointer::from_cartable(cart),
636            },
637            None => Yoke {
638                // Safety note: this Yokeable cannot refer to any data since self.cart is None.
639                yokeable: self.yokeable,
640                cart: CartableOptionPointer::none(),
641            },
642        }
643    }
644}
645
646impl<Y: for<'a> Yokeable<'a>, C: CartablePointerLike> Yoke<Y, CartableOptionPointer<C>> {
647    /// Obtain the yokeable out of a `Yoke<Y, CartableOptionPointer<C>>` if possible.
648    ///
649    /// If the cart is `None`, this returns `Ok`, but if the cart is `Some`,
650    /// this returns `self` as an error.
651    #[inline]
652    pub fn try_into_yokeable(self) -> Result<Y, Self> {
653        if self.cart.is_none() {
654            Ok(self.yokeable.into_inner())
655        } else {
656            Err(self)
657        }
658    }
659}
660
661/// This trait marks cart types that do not change source on cloning
662///
663/// This is conceptually similar to [`stable_deref_trait::CloneStableDeref`],
664/// however [`stable_deref_trait::CloneStableDeref`] is not (and should not) be
665/// implemented on [`Option`] (since it's not [`Deref`]). [`CloneableCart`] essentially is
666/// "if there _is_ data to borrow from here, cloning the cart gives you an additional
667/// handle to the same data".
668///
669/// # Safety
670/// This trait is safe to implement on `StableDeref` types which, once `Clone`d, point to the same underlying data and retain ownership.
671///
672/// This trait can also be implemented on aggregates of such types like `Option<T: CloneableCart>` and `(T: CloneableCart, U: CloneableCart)`.
673///
674/// Essentially, all data that could be referenced by a Yokeable (i.e. data that is referenced via a StableDeref) must retain the same
675/// pointer and ownership semantics once cloned.
676pub unsafe trait CloneableCart: Clone {}
677
678#[cfg(feature = "alloc")]
679// Safety: Rc<T> implements CloneStableDeref.
680unsafe impl<T: ?Sized> CloneableCart for Rc<T> {}
681#[cfg(feature = "alloc")]
682// Safety: Arc<T> implements CloneStableDeref.
683unsafe impl<T: ?Sized> CloneableCart for Arc<T> {}
684// Safety: Option<T> cannot deref to anything that T doesn't already deref to.
685unsafe impl<T: CloneableCart> CloneableCart for Option<T> {}
686// Safety: &'a T is indeed StableDeref, and cloning it refers to the same data.
687// &'a T does not own in the first place, so ownership is preserved.
688unsafe impl<'a, T: ?Sized> CloneableCart for &'a T {}
689// Safety: () cannot deref to anything.
690unsafe impl CloneableCart for () {}
691
692/// Clone requires that the cart type `C` derefs to the same address after it is cloned. This works for
693/// Rc, Arc, and &'a T.
694///
695/// For other cart types, clone `.backing_cart()` and re-use `.attach_to_cart()`; however, doing
696/// so may lose mutations performed via `.with_mut()`.
697///
698/// Cloning a `Yoke` is often a cheap operation requiring no heap allocations, in much the same
699/// way that cloning an `Rc` is a cheap operation. However, if the `yokeable` contains owned data
700/// (e.g., from `.with_mut()`), that data will need to be cloned.
701impl<Y: for<'a> Yokeable<'a>, C: CloneableCart> Clone for Yoke<Y, C>
702where
703    for<'a> <Y as Yokeable<'a>>::Output: Clone,
704{
705    fn clone(&self) -> Self {
706        // We have an &T not a T, and we can clone T
707        let this = self.get().clone();
708        Yoke {
709            yokeable: KindaSortaDangling::new(
710                // Safety: C being a CloneableCart guarantees that the data referenced by the
711                // `yokeable` is kept alive by the clone of the cart.
712                unsafe { Y::make(this) },
713            ),
714            cart: self.cart.clone(),
715        }
716    }
717}
718
719#[test]
720fn test_clone() {
721    let local_data = "foo".to_owned();
722    let y1 = Yoke::<alloc::borrow::Cow<'static, str>, Rc<String>>::attach_to_zero_copy_cart(
723        Rc::new(local_data),
724    );
725
726    // Test basic clone
727    let y2 = y1.clone();
728    assert_eq!(y1.get(), "foo");
729    assert_eq!(y2.get(), "foo");
730
731    // Test clone with mutation on target
732    let mut y3 = y1.clone();
733    y3.with_mut(|y| {
734        y.to_mut().push_str("bar");
735    });
736    assert_eq!(y1.get(), "foo");
737    assert_eq!(y2.get(), "foo");
738    assert_eq!(y3.get(), "foobar");
739
740    // Test that mutations on source do not affect target
741    let y4 = y3.clone();
742    y3.with_mut(|y| {
743        y.to_mut().push_str("baz");
744    });
745    assert_eq!(y1.get(), "foo");
746    assert_eq!(y2.get(), "foo");
747    assert_eq!(y3.get(), "foobarbaz");
748    assert_eq!(y4.get(), "foobar");
749}
750
751impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
752    /// Allows one to "project" a yoke to perform a transformation on the data, potentially
753    /// looking at a subfield, and producing a new yoke. This will move cart, and the provided
754    /// transformation is only allowed to use data known to be borrowed from the cart.
755    ///
756    /// If producing the new [`Yokeable`] `P` requires access to the cart in addition to the old
757    /// `Y`, then [`Yoke::map_with_cart`] can be used if the cart satisfies additional constraints.
758    ///
759    /// The callback takes an additional `PhantomData<&()>` parameter to anchor lifetimes
760    /// (see [#86702](https://github.com/rust-lang/rust/issues/86702)) This parameter
761    /// should just be ignored in the callback.
762    ///
763    /// This can be used, for example, to transform data from one format to another:
764    ///
765    /// ```
766    /// # use std::rc::Rc;
767    /// # use yoke::Yoke;
768    /// #
769    /// fn slice(y: Yoke<&'static str, Rc<[u8]>>) -> Yoke<&'static [u8], Rc<[u8]>> {
770    ///     y.map_project(move |yk, _| yk.as_bytes())
771    /// }
772    /// ```
773    ///
774    /// This can also be used to create a yoke for a subfield
775    ///
776    /// ```
777    /// # use yoke::{Yoke, Yokeable};
778    /// # use std::mem;
779    /// # use std::rc::Rc;
780    /// #
781    /// // also safely implements Yokeable<'a>
782    /// struct Bar<'a> {
783    ///     string_1: &'a str,
784    ///     string_2: &'a str,
785    /// }
786    ///
787    /// fn map_project_string_1(
788    ///     bar: Yoke<Bar<'static>, Rc<[u8]>>,
789    /// ) -> Yoke<&'static str, Rc<[u8]>> {
790    ///     bar.map_project(|bar, _| bar.string_1)
791    /// }
792    ///
793    /// #
794    /// # unsafe impl<'a> Yokeable<'a> for Bar<'static> {
795    /// #     type Output = Bar<'a>;
796    /// #     fn transform(&'a self) -> &'a Bar<'a> {
797    /// #         self
798    /// #     }
799    /// #
800    /// #     fn transform_owned(self) -> Bar<'a> {
801    /// #         // covariant lifetime cast, can be done safely
802    /// #         self
803    /// #     }
804    /// #
805    /// #     unsafe fn make(from: Bar<'a>) -> Self {
806    /// #         unsafe { mem::transmute(from) }
807    /// #     }
808    /// #
809    /// #     fn transform_mut<F>(&'a mut self, f: F)
810    /// #     where
811    /// #         F: 'static + FnOnce(&'a mut Self::Output),
812    /// #     {
813    /// #         unsafe { f(mem::transmute(self)) }
814    /// #     }
815    /// # }
816    /// ```
817    //
818    // Safety docs can be found at the end of the file.
819    pub fn map_project<P, F>(self, f: F) -> Yoke<P, C>
820    where
821        P: for<'a> Yokeable<'a>,
822        F: for<'a> FnOnce(
823            <Y as Yokeable<'a>>::Output,
824            PhantomData<&'a ()>,
825        ) -> <P as Yokeable<'a>>::Output,
826    {
827        let p = f(self.yokeable.into_inner().transform_owned(), PhantomData);
828        Yoke {
829            yokeable: KindaSortaDangling::new(
830                // Safety: the resulting `yokeable` is dropped before the `cart` because
831                // of the Yoke invariant. See the safety docs below for the justification of why
832                // yokeable could only borrow from the Cart.
833                unsafe { P::make(p) },
834            ),
835            cart: self.cart,
836        }
837    }
838
839    /// This is similar to [`Yoke::map_project`], however it does not move
840    /// [`Self`] and instead clones the cart (only if the cart is a [`CloneableCart`])
841    ///
842    /// This is a bit more efficient than cloning the [`Yoke`] and then calling [`Yoke::map_project`]
843    /// because then it will not clone fields that are going to be discarded.
844    pub fn map_project_cloned<'this, P, F>(&'this self, f: F) -> Yoke<P, C>
845    where
846        P: for<'a> Yokeable<'a>,
847        C: CloneableCart,
848        F: for<'a> FnOnce(
849            &'this <Y as Yokeable<'a>>::Output,
850            PhantomData<&'a ()>,
851        ) -> <P as Yokeable<'a>>::Output,
852    {
853        let p = f(self.get(), PhantomData);
854        Yoke {
855            yokeable: KindaSortaDangling::new(
856                // Safety: the resulting `yokeable` is dropped before the `cart` because
857                // of the Yoke invariant. See the safety docs below for the justification of why
858                // yokeable could only borrow from the Cart.
859                unsafe { P::make(p) },
860            ),
861            cart: self.cart.clone(),
862        }
863    }
864
865    /// This is similar to [`Yoke::map_project`], however it can also bubble up an error
866    /// from the callback.
867    ///
868    /// ```
869    /// # use std::rc::Rc;
870    /// # use yoke::Yoke;
871    /// # use std::str::{self, Utf8Error};
872    /// #
873    /// fn slice(
874    ///     y: Yoke<&'static [u8], Rc<[u8]>>,
875    /// ) -> Result<Yoke<&'static str, Rc<[u8]>>, Utf8Error> {
876    ///     y.try_map_project(move |bytes, _| str::from_utf8(bytes))
877    /// }
878    /// ```
879    ///
880    /// This can also be used to create a yoke for a subfield
881    ///
882    /// ```
883    /// # use yoke::{Yoke, Yokeable};
884    /// # use std::mem;
885    /// # use std::rc::Rc;
886    /// # use std::str::{self, Utf8Error};
887    /// #
888    /// // also safely implements Yokeable<'a>
889    /// struct Bar<'a> {
890    ///     bytes_1: &'a [u8],
891    ///     string_2: &'a str,
892    /// }
893    ///
894    /// fn map_project_string_1(
895    ///     bar: Yoke<Bar<'static>, Rc<[u8]>>,
896    /// ) -> Result<Yoke<&'static str, Rc<[u8]>>, Utf8Error> {
897    ///     bar.try_map_project(|bar, _| str::from_utf8(bar.bytes_1))
898    /// }
899    ///
900    /// #
901    /// # unsafe impl<'a> Yokeable<'a> for Bar<'static> {
902    /// #     type Output = Bar<'a>;
903    /// #     fn transform(&'a self) -> &'a Bar<'a> {
904    /// #         self
905    /// #     }
906    /// #
907    /// #     fn transform_owned(self) -> Bar<'a> {
908    /// #         // covariant lifetime cast, can be done safely
909    /// #         self
910    /// #     }
911    /// #
912    /// #     unsafe fn make(from: Bar<'a>) -> Self {
913    /// #         unsafe { mem::transmute(from) }
914    /// #     }
915    /// #
916    /// #     fn transform_mut<F>(&'a mut self, f: F)
917    /// #     where
918    /// #         F: 'static + FnOnce(&'a mut Self::Output),
919    /// #     {
920    /// #         unsafe { f(mem::transmute(self)) }
921    /// #     }
922    /// # }
923    /// ```
924    pub fn try_map_project<P, F, E>(self, f: F) -> Result<Yoke<P, C>, E>
925    where
926        P: for<'a> Yokeable<'a>,
927        F: for<'a> FnOnce(
928            <Y as Yokeable<'a>>::Output,
929            PhantomData<&'a ()>,
930        ) -> Result<<P as Yokeable<'a>>::Output, E>,
931    {
932        let p = f(self.yokeable.into_inner().transform_owned(), PhantomData)?;
933        Ok(Yoke {
934            yokeable: KindaSortaDangling::new(
935                // Safety: the resulting `yokeable` is dropped before the `cart` because
936                // of the Yoke invariant. See the safety docs below for the justification of why
937                // yokeable could only borrow from the Cart.
938                unsafe { P::make(p) },
939            ),
940            cart: self.cart,
941        })
942    }
943
944    /// This is similar to [`Yoke::try_map_project`], however it does not move
945    /// [`Self`] and instead clones the cart (only if the cart is a [`CloneableCart`])
946    ///
947    /// This is a bit more efficient than cloning the [`Yoke`] and then calling [`Yoke::map_project`]
948    /// because then it will not clone fields that are going to be discarded.
949    pub fn try_map_project_cloned<'this, P, F, E>(&'this self, f: F) -> Result<Yoke<P, C>, E>
950    where
951        P: for<'a> Yokeable<'a>,
952        C: CloneableCart,
953        F: for<'a> FnOnce(
954            &'this <Y as Yokeable<'a>>::Output,
955            PhantomData<&'a ()>,
956        ) -> Result<<P as Yokeable<'a>>::Output, E>,
957    {
958        let p = f(self.get(), PhantomData)?;
959        Ok(Yoke {
960            yokeable: KindaSortaDangling::new(
961                // Safety: the resulting `yokeable` is dropped before the `cart` because
962                // of the Yoke invariant. See the safety docs below for the justification of why
963                // yokeable could only borrow from the Cart.
964                unsafe { P::make(p) },
965            ),
966            cart: self.cart.clone(),
967        })
968    }
969    /// This is similar to [`Yoke::map_project`], but it works around older versions
970    /// of Rust not being able to use `FnOnce` by using an explicit capture input.
971    /// See [#1061](https://github.com/unicode-org/icu4x/issues/1061).
972    ///
973    /// See the docs of [`Yoke::map_project`] for how this works.
974    pub fn map_project_with_explicit_capture<P, T>(
975        self,
976        capture: T,
977        f: for<'a> fn(
978            <Y as Yokeable<'a>>::Output,
979            capture: T,
980            PhantomData<&'a ()>,
981        ) -> <P as Yokeable<'a>>::Output,
982    ) -> Yoke<P, C>
983    where
984        P: for<'a> Yokeable<'a>,
985    {
986        let p = f(
987            self.yokeable.into_inner().transform_owned(),
988            capture,
989            PhantomData,
990        );
991        Yoke {
992            yokeable: KindaSortaDangling::new(
993                // Safety: the resulting `yokeable` is dropped before the `cart` because
994                // of the Yoke invariant. See the safety docs below for the justification of why
995                // yokeable could only borrow from the Cart.
996                unsafe { P::make(p) },
997            ),
998            cart: self.cart,
999        }
1000    }
1001
1002    /// This is similar to [`Yoke::map_project_cloned`], but it works around older versions
1003    /// of Rust not being able to use `FnOnce` by using an explicit capture input.
1004    /// See [#1061](https://github.com/unicode-org/icu4x/issues/1061).
1005    ///
1006    /// See the docs of [`Yoke::map_project_cloned`] for how this works.
1007    pub fn map_project_cloned_with_explicit_capture<'this, P, T>(
1008        &'this self,
1009        capture: T,
1010        f: for<'a> fn(
1011            &'this <Y as Yokeable<'a>>::Output,
1012            capture: T,
1013            PhantomData<&'a ()>,
1014        ) -> <P as Yokeable<'a>>::Output,
1015    ) -> Yoke<P, C>
1016    where
1017        P: for<'a> Yokeable<'a>,
1018        C: CloneableCart,
1019    {
1020        let p = f(self.get(), capture, PhantomData);
1021        Yoke {
1022            yokeable: KindaSortaDangling::new(
1023                // Safety: the resulting `yokeable` is dropped before the `cart` because
1024                // of the Yoke invariant. See the safety docs below for the justification of why
1025                // yokeable could only borrow from the Cart.
1026                unsafe { P::make(p) },
1027            ),
1028            cart: self.cart.clone(),
1029        }
1030    }
1031
1032    /// This is similar to [`Yoke::try_map_project`], but it works around older versions
1033    /// of Rust not being able to use `FnOnce` by using an explicit capture input.
1034    /// See [#1061](https://github.com/unicode-org/icu4x/issues/1061).
1035    ///
1036    /// See the docs of [`Yoke::try_map_project`] for how this works.
1037    #[expect(clippy::type_complexity)]
1038    pub fn try_map_project_with_explicit_capture<P, T, E>(
1039        self,
1040        capture: T,
1041        f: for<'a> fn(
1042            <Y as Yokeable<'a>>::Output,
1043            capture: T,
1044            PhantomData<&'a ()>,
1045        ) -> Result<<P as Yokeable<'a>>::Output, E>,
1046    ) -> Result<Yoke<P, C>, E>
1047    where
1048        P: for<'a> Yokeable<'a>,
1049    {
1050        let p = f(
1051            self.yokeable.into_inner().transform_owned(),
1052            capture,
1053            PhantomData,
1054        )?;
1055        Ok(Yoke {
1056            yokeable: KindaSortaDangling::new(
1057                // Safety: the resulting `yokeable` is dropped before the `cart` because
1058                // of the Yoke invariant. See the safety docs below for the justification of why
1059                // yokeable could only borrow from the Cart.
1060                unsafe { P::make(p) },
1061            ),
1062            cart: self.cart,
1063        })
1064    }
1065
1066    /// This is similar to [`Yoke::try_map_project_cloned`], but it works around older versions
1067    /// of Rust not being able to use `FnOnce` by using an explicit capture input.
1068    /// See [#1061](https://github.com/unicode-org/icu4x/issues/1061).
1069    ///
1070    /// See the docs of [`Yoke::try_map_project_cloned`] for how this works.
1071    #[expect(clippy::type_complexity)]
1072    pub fn try_map_project_cloned_with_explicit_capture<'this, P, T, E>(
1073        &'this self,
1074        capture: T,
1075        f: for<'a> fn(
1076            &'this <Y as Yokeable<'a>>::Output,
1077            capture: T,
1078            PhantomData<&'a ()>,
1079        ) -> Result<<P as Yokeable<'a>>::Output, E>,
1080    ) -> Result<Yoke<P, C>, E>
1081    where
1082        P: for<'a> Yokeable<'a>,
1083        C: CloneableCart,
1084    {
1085        let p = f(self.get(), capture, PhantomData)?;
1086        Ok(Yoke {
1087            yokeable: KindaSortaDangling::new(
1088                // Safety: the resulting `yokeable` is dropped before the `cart` because
1089                // of the Yoke invariant. See the safety docs below for the justification of why
1090                // yokeable could only borrow from the Cart.
1091                unsafe { P::make(p) },
1092            ),
1093            cart: self.cart.clone(),
1094        })
1095    }
1096}
1097
1098impl<Y: for<'a> Yokeable<'a>, C: StableDeref> Yoke<Y, C>
1099where
1100    <C as Deref>::Target: 'static,
1101{
1102    /// Allows one to produce a new yoke from both the cart and the old yoke. This will move the
1103    /// cart, and the provided transformation is only allowed to use data known to be borrowed from
1104    /// the cart.
1105    ///
1106    /// If access to the old [`Yokeable`] `Y` is sufficient to produce the new [`Yokeable`] `P`,
1107    /// then [`Yoke::map_project`] should be preferred, as `map_with_cart` places additional
1108    /// constraints on the cart.
1109    ///
1110    /// This can be used, for example, to transform data between two formats, one of which contains
1111    /// more data:
1112    ///
1113    /// ```
1114    /// # use yoke::{Yoke, Yokeable};
1115    /// # use std::mem;
1116    /// # use std::rc::Rc;
1117    /// #
1118    /// // Both structs have `first_line`, which won't need to be recomputed in `map_with_cart`.
1119    /// // They also safely implement `Yokeable<'a>`
1120    /// struct Foo<'a> {
1121    ///     first_line: Option<&'a str>,
1122    /// }
1123    /// struct Bar<'a> {
1124    ///     first_line: Option<&'a str>,
1125    ///     last_line: Option<&'a str>,
1126    /// }
1127    ///
1128    /// fn foo_to_bar(
1129    ///     foo: Yoke<Foo<'static>, Rc<str>>,
1130    /// ) -> Yoke<Bar<'static>, Rc<str>> {
1131    ///     foo.map_with_cart(|foo, cart| {
1132    ///         Bar {
1133    ///             first_line: foo.first_line,
1134    ///             last_line: cart.lines().next_back(),
1135    ///         }
1136    ///     })
1137    /// }
1138    ///
1139    /// fn bar_to_foo(
1140    ///     bar: Yoke<Bar<'static>, Rc<str>>,
1141    /// ) -> Yoke<Foo<'static>, Rc<str>> {
1142    ///     bar.map_project(|bar, _| {
1143    ///         Foo {
1144    ///             first_line: bar.first_line,
1145    ///         }
1146    ///     })
1147    /// }
1148    ///
1149    /// #
1150    /// # unsafe impl<'a> Yokeable<'a> for Foo<'static> {
1151    /// #     type Output = Foo<'a>;
1152    /// #     fn transform(&'a self) -> &'a Foo<'a> {
1153    /// #         self
1154    /// #     }
1155    /// #
1156    /// #     fn transform_owned(self) -> Foo<'a> {
1157    /// #         // covariant lifetime cast, can be done safely
1158    /// #         self
1159    /// #     }
1160    /// #
1161    /// #     unsafe fn make(from: Foo<'a>) -> Self {
1162    /// #         unsafe { mem::transmute(from) }
1163    /// #     }
1164    /// #
1165    /// #     fn transform_mut<F>(&'a mut self, f: F)
1166    /// #     where
1167    /// #         F: 'static + FnOnce(&'a mut Self::Output),
1168    /// #     {
1169    /// #         unsafe { f(mem::transmute(self)) }
1170    /// #     }
1171    /// # }
1172    /// #
1173    /// # unsafe impl<'a> Yokeable<'a> for Bar<'static> {
1174    /// #     type Output = Bar<'a>;
1175    /// #     fn transform(&'a self) -> &'a Bar<'a> {
1176    /// #         self
1177    /// #     }
1178    /// #
1179    /// #     fn transform_owned(self) -> Bar<'a> {
1180    /// #         // covariant lifetime cast, can be done safely
1181    /// #         self
1182    /// #     }
1183    /// #
1184    /// #     unsafe fn make(from: Bar<'a>) -> Self {
1185    /// #         unsafe { mem::transmute(from) }
1186    /// #     }
1187    /// #
1188    /// #     fn transform_mut<F>(&'a mut self, f: F)
1189    /// #     where
1190    /// #         F: 'static + FnOnce(&'a mut Self::Output),
1191    /// #     {
1192    /// #         unsafe { f(mem::transmute(self)) }
1193    /// #     }
1194    /// # }
1195    /// ```
1196    //
1197    // Safety docs can be found at the end of the file.
1198    pub fn map_with_cart<P, F>(self, f: F) -> Yoke<P, C>
1199    where
1200        P: for<'a> Yokeable<'a>,
1201        F: for<'a> FnOnce(
1202            <Y as Yokeable<'a>>::Output,
1203            &'a <C as Deref>::Target,
1204        ) -> <P as Yokeable<'a>>::Output,
1205        <C as Deref>::Target: 'static,
1206    {
1207        let p = f(
1208            self.yokeable.into_inner().transform_owned(),
1209            self.cart.deref(),
1210        );
1211        Yoke {
1212            yokeable: KindaSortaDangling::new(
1213                // Safety: the resulting `yokeable` is dropped before the `cart` because
1214                // of the Yoke invariant. See the safety docs below for the justification of why
1215                // yokeable could only borrow from the Cart.
1216                unsafe { P::make(p) },
1217            ),
1218            cart: self.cart,
1219        }
1220    }
1221
1222    /// This is similar to [`Yoke::map_with_cart`], but it does not move [`Self`] and instead
1223    /// clones the cart (only if the cart is a [`CloneableCart`]).
1224    ///
1225    /// This is a bit more efficient than cloning the [`Yoke`] and then calling
1226    /// [`Yoke::map_with_cart`] because it will not clone fields that are going to be discarded.
1227    ///
1228    /// If access to the old [`Yokeable`] `Y` is sufficient to produce the new [`Yokeable`] `P`,
1229    /// then [`Yoke::map_project_cloned`] should be preferred, as `map_with_cart_cloned` places
1230    /// additional constraints on the cart.
1231    pub fn map_with_cart_cloned<'this, P, F>(&'this self, f: F) -> Yoke<P, C>
1232    where
1233        P: for<'a> Yokeable<'a>,
1234        F: for<'a> FnOnce(
1235            &'this <Y as Yokeable<'a>>::Output,
1236            &'a <C as Deref>::Target,
1237        ) -> <P as Yokeable<'a>>::Output,
1238        C: CloneableCart,
1239        <C as Deref>::Target: 'static,
1240    {
1241        let p = f(self.get(), self.cart.deref());
1242        Yoke {
1243            yokeable: KindaSortaDangling::new(
1244                // Safety: the resulting `yokeable` is dropped before the `cart` because
1245                // of the Yoke invariant. See the safety docs below for the justification of why
1246                // yokeable could only borrow from the Cart.
1247                unsafe { P::make(p) },
1248            ),
1249            cart: self.cart.clone(),
1250        }
1251    }
1252
1253    /// This is similar to [`Yoke::map_with_cart`], but it can also bubble up an error
1254    /// from the callback.
1255    ///
1256    /// If access to the old [`Yokeable`] `Y` is sufficient to produce the new [`Yokeable`] `P`,
1257    /// then [`Yoke::try_map_project`] should be preferred, as `try_map_with_cart` places
1258    /// additional constraints on the cart.
1259    ///
1260    /// ```
1261    /// # use std::rc::Rc;
1262    /// # use yoke::Yoke;
1263    /// # use std::str::{self, Utf8Error};
1264    /// #
1265    /// // Implements `Yokeable`
1266    /// type P<'a> = (&'a str, Option<&'a u8>);
1267    ///
1268    /// fn slice(
1269    ///     y: Yoke<&'static [u8], Rc<[u8]>>,
1270    /// ) -> Result<Yoke<P<'static>, Rc<[u8]>>, Utf8Error> {
1271    ///     y.try_map_with_cart(move |bytes, cart| {
1272    ///         Ok((str::from_utf8(bytes)?, bytes.first()))
1273    ///     })
1274    /// }
1275    /// ```
1276    pub fn try_map_with_cart<P, F, E>(self, f: F) -> Result<Yoke<P, C>, E>
1277    where
1278        P: for<'a> Yokeable<'a>,
1279        F: for<'a> FnOnce(
1280            <Y as Yokeable<'a>>::Output,
1281            &'a <C as Deref>::Target,
1282        ) -> Result<<P as Yokeable<'a>>::Output, E>,
1283        <C as Deref>::Target: 'static,
1284    {
1285        let p = f(
1286            self.yokeable.into_inner().transform_owned(),
1287            self.cart.deref(),
1288        )?;
1289        Ok(Yoke {
1290            yokeable: KindaSortaDangling::new(
1291                // Safety: the resulting `yokeable` is dropped before the `cart` because
1292                // of the Yoke invariant. See the safety docs below for the justification of why
1293                // yokeable could only borrow from the Cart.
1294                unsafe { P::make(p) },
1295            ),
1296            cart: self.cart,
1297        })
1298    }
1299
1300    /// This is similar to [`Yoke::try_map_with_cart`], but it does not move [`Self`] and instead
1301    /// clones the cart (only if the cart is a [`CloneableCart`]).
1302    ///
1303    /// This is a bit more efficient than cloning the [`Yoke`] and then calling
1304    /// [`Yoke::try_map_with_cart`] because it will not clone fields that are going to be discarded.
1305    ///
1306    /// If access to the old [`Yokeable`] `Y` is sufficient to producethe new [`Yokeable`] `P`,
1307    /// then [`Yoke::try_map_project_cloned`] should be preferred, as `try_map_with_cart_cloned`
1308    /// places additional constraints on the cart.
1309    pub fn try_map_with_cart_cloned<'this, P, F, E>(&'this self, f: F) -> Result<Yoke<P, C>, E>
1310    where
1311        P: for<'a> Yokeable<'a>,
1312        C: CloneableCart,
1313        F: for<'a> FnOnce(
1314            &'this <Y as Yokeable<'a>>::Output,
1315            &'a <C as Deref>::Target,
1316        ) -> Result<<P as Yokeable<'a>>::Output, E>,
1317        <C as Deref>::Target: 'static,
1318    {
1319        let p = f(self.get(), self.cart.deref())?;
1320        Ok(Yoke {
1321            yokeable: KindaSortaDangling::new(
1322                // Safety: the resulting `yokeable` is dropped before the `cart` because
1323                // of the Yoke invariant. See the safety docs below for the justification of why
1324                // yokeable could only borrow from the Cart.
1325                unsafe { P::make(p) },
1326            ),
1327            cart: self.cart.clone(),
1328        })
1329    }
1330}
1331
1332#[cfg(feature = "alloc")]
1333impl<Y: for<'a> Yokeable<'a>, C: 'static + Sized> Yoke<Y, Rc<C>> {
1334    /// Allows type-erasing the cart in a `Yoke<Y, Rc<C>>`.
1335    ///
1336    /// The yoke only carries around a cart type `C` for its destructor,
1337    /// since it needs to be able to guarantee that its internal references
1338    /// are valid for the lifetime of the Yoke. As such, the actual type of the
1339    /// Cart is not very useful unless you wish to extract data out of it
1340    /// via [`Yoke::backing_cart()`]. Erasing the cart allows for one to mix
1341    /// [`Yoke`]s obtained from different sources.
1342    ///
1343    /// In case the cart type `C` is not already an `Rc<T>`, you can use
1344    /// [`Yoke::wrap_cart_in_rc()`] to wrap it.
1345    ///
1346    /// ✨ *Enabled with the `alloc` Cargo feature.*
1347    ///
1348    /// # Example
1349    ///
1350    /// ```rust
1351    /// use std::rc::Rc;
1352    /// use yoke::erased::ErasedRcCart;
1353    /// use yoke::Yoke;
1354    ///
1355    /// let buffer1: Rc<String> = Rc::new("   foo bar baz  ".into());
1356    /// let buffer2: Box<String> = Box::new("  baz quux  ".into());
1357    ///
1358    /// let yoke1 =
1359    ///     Yoke::<&'static str, _>::attach_to_cart(buffer1, |rc| rc.trim());
1360    /// let yoke2 = Yoke::<&'static str, _>::attach_to_cart(buffer2, |b| b.trim());
1361    ///
1362    /// let erased1: Yoke<_, ErasedRcCart> = yoke1.erase_rc_cart();
1363    /// // Wrap the Box in an Rc to make it compatible
1364    /// let erased2: Yoke<_, ErasedRcCart> =
1365    ///     yoke2.wrap_cart_in_rc().erase_rc_cart();
1366    ///
1367    /// // Now erased1 and erased2 have the same type!
1368    /// ```
1369    pub fn erase_rc_cart(self) -> Yoke<Y, ErasedRcCart> {
1370        // Safety: safe because the cart is preserved, as it is just type-erased
1371        unsafe { self.replace_cart(|c| c as ErasedRcCart) }
1372    }
1373}
1374
1375#[cfg(feature = "alloc")]
1376impl<Y: for<'a> Yokeable<'a>, C: 'static + Sized + Send + Sync> Yoke<Y, Arc<C>> {
1377    /// Allows type-erasing the cart in a `Yoke<Y, Arc<C>>`.
1378    ///
1379    /// The yoke only carries around a cart type `C` for its destructor,
1380    /// since it needs to be able to guarantee that its internal references
1381    /// are valid for the lifetime of the Yoke. As such, the actual type of the
1382    /// Cart is not very useful unless you wish to extract data out of it
1383    /// via [`Yoke::backing_cart()`]. Erasing the cart allows for one to mix
1384    /// [`Yoke`]s obtained from different sources.
1385    ///
1386    /// In case the cart type `C` is not already an `Arc<T>`, you can use
1387    /// [`Yoke::wrap_cart_in_arc()`] to wrap it.
1388    ///
1389    /// ✨ *Enabled with the `alloc` Cargo feature.*
1390    ///
1391    /// # Example
1392    ///
1393    /// ```rust
1394    /// use std::sync::Arc;
1395    /// use yoke::erased::ErasedArcCart;
1396    /// use yoke::Yoke;
1397    ///
1398    /// let buffer1: Arc<String> = Arc::new("   foo bar baz  ".into());
1399    /// let buffer2: Box<String> = Box::new("  baz quux  ".into());
1400    ///
1401    /// let yoke1 =
1402    ///     Yoke::<&'static str, _>::attach_to_cart(buffer1, |arc| arc.trim());
1403    /// let yoke2 = Yoke::<&'static str, _>::attach_to_cart(buffer2, |b| b.trim());
1404    ///
1405    /// let erased1: Yoke<_, ErasedArcCart> = yoke1.erase_arc_cart();
1406    /// // Wrap the Box in an Rc to make it compatible
1407    /// let erased2: Yoke<_, ErasedArcCart> =
1408    ///     yoke2.wrap_cart_in_arc().erase_arc_cart();
1409    ///
1410    /// // Now erased1 and erased2 have the same type!
1411    /// ```
1412    pub fn erase_arc_cart(self) -> Yoke<Y, ErasedArcCart> {
1413        // Safety: safe because the cart is preserved, as it is just type-erased
1414        unsafe { self.replace_cart(|c| c as ErasedArcCart) }
1415    }
1416}
1417
1418#[cfg(feature = "alloc")]
1419impl<Y: for<'a> Yokeable<'a>, C: 'static + Sized> Yoke<Y, Box<C>> {
1420    /// Allows type-erasing the cart in a `Yoke<Y, Box<C>>`.
1421    ///
1422    /// The yoke only carries around a cart type `C` for its destructor,
1423    /// since it needs to be able to guarantee that its internal references
1424    /// are valid for the lifetime of the Yoke. As such, the actual type of the
1425    /// Cart is not very useful unless you wish to extract data out of it
1426    /// via [`Yoke::backing_cart()`]. Erasing the cart allows for one to mix
1427    /// [`Yoke`]s obtained from different sources.
1428    ///
1429    /// In case the cart type `C` is not already `Box<T>`, you can use
1430    /// [`Yoke::wrap_cart_in_box()`] to wrap it.
1431    ///
1432    /// ✨ *Enabled with the `alloc` Cargo feature.*
1433    ///
1434    /// # Example
1435    ///
1436    /// ```rust
1437    /// use std::rc::Rc;
1438    /// use yoke::erased::ErasedBoxCart;
1439    /// use yoke::Yoke;
1440    ///
1441    /// let buffer1: Rc<String> = Rc::new("   foo bar baz  ".into());
1442    /// let buffer2: Box<String> = Box::new("  baz quux  ".into());
1443    ///
1444    /// let yoke1 =
1445    ///     Yoke::<&'static str, _>::attach_to_cart(buffer1, |rc| rc.trim());
1446    /// let yoke2 = Yoke::<&'static str, _>::attach_to_cart(buffer2, |b| b.trim());
1447    ///
1448    /// // Wrap the Rc in an Box to make it compatible
1449    /// let erased1: Yoke<_, ErasedBoxCart> =
1450    ///     yoke1.wrap_cart_in_box().erase_box_cart();
1451    /// let erased2: Yoke<_, ErasedBoxCart> = yoke2.erase_box_cart();
1452    ///
1453    /// // Now erased1 and erased2 have the same type!
1454    /// ```
1455    pub fn erase_box_cart(self) -> Yoke<Y, ErasedBoxCart> {
1456        // Safety: safe because the cart is preserved, as it is just type-erased
1457        unsafe { self.replace_cart(|c| c as ErasedBoxCart) }
1458    }
1459}
1460
1461#[cfg(feature = "alloc")]
1462impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
1463    /// Helper function allowing one to wrap the cart type `C` in a `Box<T>`.
1464    /// Can be paired with [`Yoke::erase_box_cart()`]
1465    ///
1466    /// ✨ *Enabled with the `alloc` Cargo feature.*
1467    #[inline]
1468    pub fn wrap_cart_in_box(self) -> Yoke<Y, Box<C>> {
1469        // Safety: safe because the cart is preserved, as it is just wrapped.
1470        unsafe { self.replace_cart(Box::new) }
1471    }
1472    /// Helper function allowing one to wrap the cart type `C` in an `Rc<T>`.
1473    /// Can be paired with [`Yoke::erase_rc_cart()`], or generally used
1474    /// to make the [`Yoke`] cloneable.
1475    ///
1476    /// ✨ *Enabled with the `alloc` Cargo feature.*
1477    #[inline]
1478    pub fn wrap_cart_in_rc(self) -> Yoke<Y, Rc<C>> {
1479        // Safety: safe because the cart is preserved, as it is just wrapped
1480        unsafe { self.replace_cart(Rc::new) }
1481    }
1482    /// Helper function allowing one to wrap the cart type `C` in an `Arc<T>`.
1483    /// Can be paired with [`Yoke::erase_arc_cart()`], or generally used
1484    /// to make the [`Yoke`] cloneable.
1485    ///
1486    /// ✨ *Enabled with the `alloc` Cargo feature.*
1487    #[inline]
1488    pub fn wrap_cart_in_arc(self) -> Yoke<Y, Arc<C>> {
1489        // Safety: safe because the cart is preserved, as it is just wrapped
1490        unsafe { self.replace_cart(Arc::new) }
1491    }
1492}
1493
1494impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
1495    /// Helper function allowing one to wrap the cart type `C` in an [`EitherCart`].
1496    ///
1497    /// This function wraps the cart into the `A` variant. To wrap it into the
1498    /// `B` variant, use [`Self::wrap_cart_in_either_b()`].
1499    ///
1500    /// For an example, see [`EitherCart`].
1501    #[inline]
1502    pub fn wrap_cart_in_either_a<B>(self) -> Yoke<Y, EitherCart<C, B>> {
1503        // Safety: safe because the cart is preserved, as it is just wrapped.
1504        unsafe { self.replace_cart(EitherCart::A) }
1505    }
1506    /// Helper function allowing one to wrap the cart type `C` in an [`EitherCart`].
1507    ///
1508    /// This function wraps the cart into the `B` variant. To wrap it into the
1509    /// `A` variant, use [`Self::wrap_cart_in_either_a()`].
1510    ///
1511    /// For an example, see [`EitherCart`].
1512    #[inline]
1513    pub fn wrap_cart_in_either_b<A>(self) -> Yoke<Y, EitherCart<A, C>> {
1514        // Safety: safe because the cart is preserved, as it is just wrapped.
1515        unsafe { self.replace_cart(EitherCart::B) }
1516    }
1517}
1518
1519/// # Safety docs for *map_project*()
1520///
1521/// (Docs are on a private const to allow the use of compile_fail doctests)
1522///
1523/// This is safe to perform because of the choice of lifetimes on `f`, that is,
1524/// `for<a> fn(<Y as Yokeable<'a>>::Output, &'a ()) -> <P as Yokeable<'a>>::Output`.
1525///
1526/// Note that correctness arguments are similar if you replace `fn` with `FnOnce`.
1527///
1528/// What we want this function to do is take a Yokeable (`Y`) that is borrowing from the cart, and
1529/// produce another Yokeable (`P`) that also borrows from the same cart. There are a couple potential
1530/// hazards here:
1531///
1532/// - `P` ends up borrowing data from `Y` (or elsewhere) that did _not_ come from the cart,
1533///   for example `P` could borrow owned data from a `Cow`. This would make the `Yoke<P>` dependent
1534///   on data owned only by the `Yoke<Y>`.
1535/// - Borrowed data from `Y` escapes with the wrong lifetime
1536///
1537/// Let's walk through these and see how they're prevented.
1538///
1539/// ```rust, compile_fail
1540/// # use std::rc::Rc;
1541/// # use yoke::Yoke;
1542/// # use std::borrow::Cow;
1543/// fn borrow_potentially_owned(y: &Yoke<Cow<'static, str>, Rc<[u8]>>) -> Yoke<&'static str, Rc<[u8]>> {
1544///    y.map_project_cloned(|cow, _| &*cow)
1545/// }
1546/// ```
1547///
1548/// In this case, the lifetime of `&*cow` is `&'this str`, however the function needs to be able to return
1549/// `&'a str` _for all `'a`_, which isn't possible.
1550///
1551///
1552/// ```rust, compile_fail
1553/// # use std::rc::Rc;
1554/// # use yoke::Yoke;
1555/// # use std::borrow::Cow;
1556/// fn borrow_potentially_owned(y: Yoke<Cow<'static, str>, Rc<[u8]>>) -> Yoke<&'static str, Rc<[u8]>> {
1557///    y.map_project(|cow, _| &*cow)
1558/// }
1559/// ```
1560///
1561/// This has the same issue, `&*cow` is borrowing for a local lifetime.
1562///
1563/// Similarly, trying to project an owned field of a struct will produce similar errors:
1564///
1565/// ```rust,compile_fail
1566/// # use std::borrow::Cow;
1567/// # use yoke::{Yoke, Yokeable};
1568/// # use std::mem;
1569/// # use std::rc::Rc;
1570/// #
1571/// // also safely implements Yokeable<'a>
1572/// struct Bar<'a> {
1573///     owned: String,
1574///     string_2: &'a str,
1575/// }
1576///
1577/// fn map_project_owned(bar: &Yoke<Bar<'static>, Rc<[u8]>>) -> Yoke<&'static str, Rc<[u8]>> {
1578///     // ERROR (but works if you replace owned with string_2)
1579///     bar.map_project_cloned(|bar, _| &*bar.owned)
1580/// }
1581///
1582/// #
1583/// # unsafe impl<'a> Yokeable<'a> for Bar<'static> {
1584/// #     type Output = Bar<'a>;
1585/// #     fn transform(&'a self) -> &'a Bar<'a> {
1586/// #         self
1587/// #     }
1588/// #
1589/// #     fn transform_owned(self) -> Bar<'a> {
1590/// #         // covariant lifetime cast, can be done safely
1591/// #         self
1592/// #     }
1593/// #
1594/// #     unsafe fn make(from: Bar<'a>) -> Self {
1595/// #         let ret = mem::transmute_copy(&from);
1596/// #         mem::forget(from);
1597/// #         ret
1598/// #     }
1599/// #
1600/// #     fn transform_mut<F>(&'a mut self, f: F)
1601/// #     where
1602/// #         F: 'static + FnOnce(&'a mut Self::Output),
1603/// #     {
1604/// #         unsafe { f(mem::transmute(self)) }
1605/// #     }
1606/// # }
1607/// ```
1608///
1609/// Borrowed data from `Y` similarly cannot escape with the wrong lifetime because of the `for<'a>`, since
1610/// it will never be valid for the borrowed data to escape for all lifetimes of 'a. Internally, `.map_project()`
1611/// uses `.get()`, however the signature forces the callers to be able to handle every lifetime.
1612///
1613///  `'a` is the only lifetime that matters here; `Yokeable`s must be `'static` and since
1614/// `Output` is an associated type it can only have one lifetime, `'a` (there's nowhere for it to get another from).
1615/// `Yoke`s can get additional lifetimes via the cart, and indeed, `map_project()` can operate on `Yoke<_, &'b [u8]>`,
1616/// however this lifetime is inaccessible to the closure, and even if it were accessible the `for<'a>` would force
1617/// it out of the output. All external lifetimes (from other found outside the yoke/closures
1618/// are similarly constrained here.
1619///
1620/// Essentially, safety is achieved by using `for<'a> fn(...)` with `'a` used in both `Yokeable`s to ensure that
1621/// the output yokeable can _only_ have borrowed data flow in to it from the input. All paths of unsoundness require the
1622/// unification of an existential and universal lifetime, which isn't possible.
1623const _: () = ();
1624
1625/// # Safety docs for attach_to_cart()'s signature
1626///
1627/// The `attach_to_cart()` family of methods get by by using the following bound:
1628///
1629/// ```rust,ignore
1630/// F: for<'de> FnOnce(&'de <C as Deref>::Target) -> <Y as Yokeable<'de>>::Output,
1631/// C::Target: 'static
1632/// ```
1633///
1634/// to enforce that the yoking closure produces a yokeable that is *only* allowed to borrow from the cart.
1635/// A way to be sure of this is as follows: imagine if `F` *did* borrow data of lifetime `'a` and stuff it in
1636/// its output. Then that lifetime `'a` would have to live at least as long as `'de` *for all `'de`*.
1637/// The only lifetime that satisfies that is `'static` (since at least one of the potential `'de`s is `'static`),
1638/// and we're fine with that.
1639///
1640/// ## Implied bounds and variance
1641///
1642/// The `C::Target: 'static` bound is tricky, however. Let's imagine a situation where we *didn't* have that bound.
1643///
1644/// One thing to remember is that we are okay with the cart itself borrowing from places,
1645/// e.g. `&[u8]` is a valid cart, as is `Box<&[u8]>`. `C` is not `'static`.
1646///
1647/// (I'm going to use `CT` in prose to refer to `C::Target` here, since almost everything here has to do
1648/// with C::Target and not C itself.)
1649///
1650/// Unfortunately, there's a sneaky additional bound inside `F`. The signature of `F` is *actually*
1651///
1652/// ```rust,ignore
1653/// F: for<'de> where<C::Target: 'de> FnOnce(&'de C::Target) -> <Y as Yokeable<'de>>::Output
1654/// ```
1655///
1656/// using made-up "where clause inside HRTB" syntax to represent a type that can be represented inside the compiler
1657/// and type system but not in Rust code. The `CT: 'de` bond comes from the `&'de C::Target`: any time you
1658/// write `&'a T`, an implied bound of `T: 'a` materializes and is stored alongside it, since references cannot refer
1659/// to data that itself refers to data of shorter lifetimes. If a reference is valid, its referent must be valid for
1660/// the duration of the reference's lifetime, so every reference *inside* its referent must also be valid, giving us `T: 'a`.
1661/// This kind of constraint is often called a "well formedness" constraint: `&'a T` is not "well formed" without that
1662/// bound, and rustc is being helpful by giving it to us for free.
1663///
1664/// Unfortunately, this messes with our universal quantification. The `for<'de>` is no longer "For all lifetimes `'de`",
1665/// it is "for all lifetimes `'de` *where `CT: 'de`*". And if `CT` borrows from somewhere (with lifetime `'ct`), then we get a
1666/// `'ct: 'de` bound, and `'de` candidates that live longer than `'ct` won't actually be considered.
1667/// The neat little logic at the beginning stops working.
1668///
1669/// `attach_to_cart()` will instead enforce that the produced yokeable *either* borrows from the cart (fine), or from
1670/// data that has a lifetime that is at least `'ct`. Which means that `attach_to_cart()` will allow us to borrow locals
1671/// provided they live at least as long as `'ct`.
1672///
1673/// Is this a problem?
1674///
1675/// This is totally fine if CT's lifetime is covariant: if C is something like `Box<&'ct [u8]>`, even if our
1676/// yoked object borrows from locals outliving `'ct`, our Yoke can't outlive that
1677/// lifetime `'ct` anyway (since it's a part of the cart type), so we're fine.
1678///
1679/// However it's completely broken for contravariant carts (e.g. `Box<fn(&'ct u8)>`). In that case
1680/// we still get `'ct: 'de`, and we still end up being able to
1681/// borrow from locals that outlive `'ct`. However, our Yoke _can_ outlive
1682/// that lifetime, because Yoke shares its variance over `'ct`
1683/// with the cart type, and the cart type is contravariant over `'ct`.
1684/// So the Yoke can be upcast to having a longer lifetime than `'ct`, and *that* Yoke
1685/// can outlive `'ct`.
1686///
1687/// We fix this by forcing `C::Target: 'static` in `attach_to_cart()`, which would make it work
1688/// for fewer types, but would also allow Yoke to continue to be covariant over cart lifetimes if necessary.
1689///
1690/// An alternate fix would be to not allowing yoke to ever be upcast over lifetimes contained in the cart
1691/// by forcing them to be invariant. This is a bit more restrictive and affects *all* `Yoke` users, not just
1692/// those using `attach_to_cart()`.
1693///
1694/// See https://github.com/unicode-org/icu4x/issues/2926
1695/// See also https://github.com/rust-lang/rust/issues/106431 for potentially fixing this upstream by
1696/// changing how the bound works.
1697///
1698/// # Tests
1699///
1700/// Here's a broken `attach_to_cart()` that attempts to borrow from a local:
1701///
1702/// ```rust,compile_fail
1703/// use yoke::Yoke;
1704///
1705/// let cart = vec![1, 2, 3, 4].into_boxed_slice();
1706/// let local = vec![4, 5, 6, 7];
1707/// let yoke: Yoke<&[u8], Box<[u8]>> = Yoke::attach_to_cart(cart, |_| &*local);
1708/// ```
1709///
1710/// Fails as expected.
1711///
1712/// And here's a working one with a local borrowed cart that does not do any sneaky borrows whilst attaching.
1713///
1714/// ```rust
1715/// use yoke::Yoke;
1716///
1717/// let cart = vec![1, 2, 3, 4].into_boxed_slice();
1718/// let yoke: Yoke<&[u8], &[u8]> = Yoke::attach_to_cart(&cart, |c| c);
1719/// ```
1720///
1721/// Here's an `attach_to_cart()` that attempts to borrow from a longer-lived local due to
1722/// the cart being covariant. It fails, but would not if the alternate fix of forcing Yoke to be invariant
1723/// were implemented. It is technically a safe operation:
1724///
1725/// ```rust,compile_fail
1726/// use yoke::Yoke;
1727/// // longer lived
1728/// let local = vec![4, 5, 6, 7];
1729///
1730/// let backing = vec![1, 2, 3, 4];
1731/// let cart = Box::new(&*backing);
1732///
1733/// let yoke: Yoke<&[u8], Box<&[u8]>> = Yoke::attach_to_cart(cart, |_| &*local);
1734/// println!("{:?}", yoke.get());
1735/// ```
1736///
1737/// Finally, here's an `attach_to_cart()` that attempts to borrow from a longer lived local
1738/// in the case of a contravariant lifetime. It does not compile, but in and of itself is not dangerous:
1739///
1740/// ```rust,compile_fail
1741/// use yoke::Yoke;
1742///
1743/// type Contra<'a> = fn(&'a ());
1744///
1745/// let local = String::from("Hello World!");
1746/// let yoke: Yoke<&'static str, Box<Contra<'_>>> = Yoke::attach_to_cart(Box::new((|_| {}) as _), |_| &local[..]);
1747/// println!("{:?}", yoke.get());
1748/// ```
1749///
1750/// It is dangerous if allowed to transform (testcase from #2926)
1751///
1752/// ```rust,compile_fail
1753/// use yoke::Yoke;
1754///
1755/// type Contra<'a> = fn(&'a ());
1756///
1757///
1758/// let local = String::from("Hello World!");
1759/// let yoke: Yoke<&'static str, Box<Contra<'_>>> = Yoke::attach_to_cart(Box::new((|_| {}) as _), |_| &local[..]);
1760/// println!("{:?}", yoke.get());
1761/// let yoke_longer: Yoke<&'static str, Box<Contra<'static>>> = yoke;
1762/// let leaked: &'static Yoke<&'static str, Box<Contra<'static>>> = Box::leak(Box::new(yoke_longer));
1763/// let reference: &'static str = leaked.get();
1764///
1765/// println!("pre-drop: {reference}");
1766/// drop(local);
1767/// println!("post-drop: {reference}");
1768/// ```
1769const _: () = ();
1770
1771/// # Safety docs for *map_with_cart*()
1772///
1773/// [`Yoke::map_with_cart`] has both the problems of [`Yoke::map_project`] (with a
1774/// potentially-pathological callback) and [`Yoke::attach_to_cart`] (with a potentially
1775/// pathological cart, capable of permitting a bad callback).
1776///
1777/// [`map_project`] forces the callback to be well-behaved with the bounds:
1778/// ```rust,ignore
1779/// F: for<'a> FnOnce(
1780///     <Y as Yokeable<'a>>::Output,
1781///     PhantomData<&'a ()>,
1782/// ) -> <P as Yokeable<'a>>::Output,
1783/// ```
1784///
1785/// The `for<'a>` constraint prevents `F` from inserting additional borrows that did not come
1786/// from the input; `<P as Yokeable<'a>>::Output` can be `'static` or only `'a`, but that
1787/// `'a` could potentially be `'static` as well. Therefore, `F` has to be capable of returning
1788/// `'static` data (under certain constraints), and cannot insert additional borrows. Nor can a
1789/// reference leak out, as for a sufficiently short `'a`, the data would not live long enough.
1790/// The `PhantomData<&'a ()>` is just to make sure that the lifetime `'a` is constrained
1791/// to fix <https://github.com/rust-lang/rust/issues/86702>.
1792///
1793/// Next, [`Yoke::attach_to_cart`] follows mostly the same approach, but needs to ensure that
1794/// the `for<'a>` bound remains a fully universal quantifier.
1795/// It uses the bounds:
1796/// ```rust,ignore
1797/// F: for<'de> FnOnce(&'de <C as Deref>::Target) -> <Y as Yokeable<'de>>::Output,
1798/// <C as Deref>::Target: 'static,
1799/// ```
1800///
1801/// The problem is that the `for<'de>` quantifier is bounded by whatever the lifetime of
1802/// `<C as Deref>::Target` is, so for it to cover all lifetimes, `<C as Deref>::Target` must
1803/// be `'static`.
1804///
1805///
1806/// [`Yoke::map_with_cart`] combines the relevant bounds into one:
1807/// ```rust,ignore
1808/// F: for<'a> FnOnce(
1809///     <Y as Yokeable<'a>>::Output,
1810///     &'a <C as Deref>::Target,
1811/// ) -> <P as Yokeable<'a>>::Output,
1812/// <C as Deref>::Target: 'static,
1813/// ```
1814///
1815/// The techniques ensure that, for any lifetime `'a`, the callback must be capable of taking in
1816/// data from the old `Yokeable` and from the cart which is known only to outlive `'a`, and return
1817/// data that outlives `'a`. `F` is incapable of inserting external data which is not `'static`,
1818/// and is otherwise constrained to using the data in the cart and old `Yokeable` to produce
1819/// a new `Yokeable`.
1820/// A `PhantomData` is not needed, since the lifetime `'a` is constrained by
1821/// `&'a <C as Deref>::Target`.
1822///
1823/// # Fail tests
1824///
1825/// We can confirm that problematic cases analogous to those in [`Yoke::map_project`] and
1826/// [`Yoke::attach_to_cart`] still fail here. They're copied and adapted slightly.
1827///
1828/// ### From `map_project`'s safety docs
1829///
1830/// ```rust, compile_fail
1831/// # use std::rc::Rc;
1832/// # use yoke::Yoke;
1833/// # use std::borrow::Cow;
1834/// fn borrow_potentially_owned(y: &Yoke<Cow<'static, str>, Rc<[u8]>>) -> Yoke<&'static str, Rc<[u8]>> {
1835///    y.map_with_cart_cloned(|cow, _cart| &**cow)
1836/// }
1837/// ```
1838///
1839/// ```rust, compile_fail
1840/// # use std::rc::Rc;
1841/// # use yoke::Yoke;
1842/// # use std::borrow::Cow;
1843/// fn borrow_potentially_owned(y: Yoke<Cow<'static, str>, Rc<[u8]>>) -> Yoke<&'static str, Rc<[u8]>> {
1844///    y.map_with_cart(|cow: Cow<'_, _>, _cart| &*cow)
1845/// }
1846/// ```
1847///
1848/// ```rust,compile_fail
1849/// # use std::borrow::Cow;
1850/// # use yoke::{Yoke, Yokeable};
1851/// # use std::mem;
1852/// # use std::rc::Rc;
1853/// #
1854/// // also safely implements Yokeable<'a>
1855/// struct Bar<'a> {
1856///     owned: String,
1857///     string_2: &'a str,
1858/// }
1859///
1860/// fn map_with_cart_owned(bar: &Yoke<Bar<'static>, Rc<[u8]>>) -> Yoke<&'static str, Rc<[u8]>> {
1861///     // ERROR (but works if you replace owned with string_2)
1862///     bar.map_with_cart_cloned(|bar, _cart| &*bar.owned)
1863/// }
1864///
1865/// #
1866/// # unsafe impl<'a> Yokeable<'a> for Bar<'static> {
1867/// #     type Output = Bar<'a>;
1868/// #     fn transform(&'a self) -> &'a Bar<'a> {
1869/// #         self
1870/// #     }
1871/// #
1872/// #     fn transform_owned(self) -> Bar<'a> {
1873/// #         // covariant lifetime cast, can be done safely
1874/// #         self
1875/// #     }
1876/// #
1877/// #     unsafe fn make(from: Bar<'a>) -> Self {
1878/// #         let ret = mem::transmute_copy(&from);
1879/// #         mem::forget(from);
1880/// #         ret
1881/// #     }
1882/// #
1883/// #     fn transform_mut<F>(&'a mut self, f: F)
1884/// #     where
1885/// #         F: 'static + FnOnce(&'a mut Self::Output),
1886/// #     {
1887/// #         unsafe { f(mem::transmute(self)) }
1888/// #     }
1889/// # }
1890/// ```
1891///
1892/// ### From `attach_to_cart`'s safety docs
1893///
1894/// Being slightly paranoid, confirm that the expected line is the one causing the error.
1895/// ```rust
1896/// use std::rc::Rc;
1897/// use yoke::Yoke;
1898///
1899/// let cart: Vec<u8> = vec![1, 2, 3, 4];
1900/// let cart: Rc<[u8]> = Rc::from(&*cart);
1901///
1902/// let local = vec![4, 5, 6, 7];
1903/// let local: Rc<[u8]> = Rc::from(&*local);
1904///
1905/// let yoke: Yoke<&[u8], Rc<[u8]>> = Yoke::attach_to_cart(cart, |cart| cart);
1906/// let yoke: Yoke<&[u8], Rc<[u8]>> = yoke.map_with_cart(|_, cart| cart);
1907/// ```
1908///
1909/// ```rust,compile_fail
1910/// use std::rc::Rc;
1911/// use yoke::Yoke;
1912///
1913/// let cart: Vec<u8> = vec![1, 2, 3, 4];
1914/// let cart: Rc<[u8]> = Rc::from(&*cart);
1915///
1916/// let local = vec![4, 5, 6, 7];
1917/// let local: Rc<[u8]> = Rc::from(&*local);
1918///
1919/// let yoke: Yoke<&[u8], Rc<[u8]>> = Yoke::attach_to_cart(cart, |cart| &*cart);
1920/// let yoke: Yoke<&[u8], Rc<[u8]>> = yoke.map_with_cart(|_, _| &*local);
1921/// ```
1922///
1923///
1924/// ```rust
1925/// use std::rc::Rc;
1926/// use yoke::Yoke;
1927///
1928/// // longer lived
1929/// let local = vec![4_u8, 5, 6, 7];
1930/// let local: Rc<[u8]> = Rc::from(&*local);
1931///
1932/// let backing = vec![1_u8, 2, 3, 4];
1933/// let cart: Rc<[u8]> = Rc::from(&*backing);
1934///
1935/// let yoke: Yoke<&[u8], Rc<[u8]>> = Yoke::attach_to_cart(cart, |cart| cart);
1936/// let yoke: Yoke<&[u8], Rc<[u8]>> = yoke.map_with_cart(|_, cart: &[u8]| cart);
1937/// println!("{:?}", yoke.get());
1938/// ```
1939///
1940/// ```rust,compile_fail
1941/// use std::rc::Rc;
1942/// use yoke::Yoke;
1943///
1944/// // longer lived
1945/// let local: Rc<[u8]> = Rc::from(&*local);
1946///
1947/// let backing = vec![1_u8, 2, 3, 4];
1948/// let cart: Rc<[u8]> = Rc::from(&*backing);
1949///
1950/// let yoke: Yoke<&[u8], Rc<[u8]>> = Yoke::attach_to_cart(cart, |cart| &*cart);
1951/// let yoke: Yoke<&[u8], Rc<[u8]>> = yoke.map_with_cart(|_, cart: &[u8]| &*local);
1952/// println!("{:?}", yoke.get());
1953/// ```
1954///
1955///
1956/// I don't see a way to closely adapt `attach_to_cart`'s last two test cases on contravariant
1957/// carts, since the problematic `Cart` type is stopped at the stage of construction. We can use
1958/// one of `Yoke`'s other constructors instead, and try mapping it.
1959///
1960/// ```rust
1961/// use std::rc::Rc;
1962/// use yoke::Yoke;
1963///
1964/// type Contra<'a> = fn(&'a ());
1965///
1966/// let local = String::from("Hello World!");
1967/// let yoke: Yoke<&'static str, Option<Rc<Contra<'_>>>> =
1968///     Yoke::new_owned("hi");
1969/// println!("{:?}", yoke.get());
1970/// ```
1971///
1972/// This case might actually be fine to allow, since `attach_to_cart` could not possibly succeed
1973/// with this cart type and thus the `Yokeable` must always be owned. But whether it's safe to
1974/// permit *any* contravariant cart in `map_with_cart` is not immediately clear to me. Therefore,
1975/// compile fail.
1976/// ```rust,compile_fail
1977/// use std::rc::Rc;
1978/// use yoke::Yoke;
1979///
1980/// type Contra<'a> = fn(&'a ());
1981///
1982/// fn scope<'b>() {
1983///     let local = String::from("Hello World!");
1984///     let yoke: Yoke<&'static str, Option<Rc<Contra<'b>>>> = Yoke::new_owned("hi");
1985///     let yoke: Yoke<&'static str, Rc<Option<Rc<Contra<'b>>>>> = yoke.wrap_cart_in_rc);
1986///     let yoke: Yoke<&'static str, Rc<Option<Rc<Contra<'b>>>>> = yoke.map_with_cart(|yoke, _| yoke);
1987///     println!("{:?}", yoke.get());
1988/// }
1989/// ```
1990///
1991/// This version succeeds, though.
1992/// ```rust
1993/// use std::rc::Rc;
1994/// use yoke::Yoke;
1995///
1996/// type Contra<'a> = fn(&'a ());
1997///
1998/// fn scope<'b>() {
1999///     let local = String::from("Hello World!");
2000///     let yoke: Yoke<&'static str, Option<Rc<Contra<'b>>>> =
2001///         Yoke::new_owned("hi");
2002///     let yoke: Yoke<&'static str, Rc<Option<Rc<Contra<'b>>>>> =
2003///         yoke.wrap_cart_in_rc();
2004///     let yoke: Yoke<&'static str, Rc<Option<Rc<Contra<'static>>>>> = yoke;
2005///     let yoke: Yoke<&'static str, Rc<Option<Rc<Contra<'static>>>>> =
2006///         yoke.map_with_cart(|yoke, _| yoke);
2007///     println!("{:?}", yoke.get());
2008/// }
2009/// ```
2010///
2011/// # Test running the function
2012///
2013/// The above verifies the method signature. We can also check that the implementation is correct,
2014/// by running Miri on the following test (analogous to [`Yoke::map_with_cart`]'s doctest):
2015/// ```
2016/// use std::rc::Rc;
2017/// use yoke::Yoke;
2018///
2019/// type Foo<'a> = Option<&'a str>;
2020/// type Bar<'a> = (Option<&'a str>, Option<&'a str>);
2021///
2022/// fn foo_to_bar(
2023///     foo: Yoke<Foo<'static>, Rc<str>>,
2024/// ) -> Yoke<Bar<'static>, Rc<str>> {
2025///     foo.map_with_cart(|foo, cart| (foo, cart.lines().next_back()))
2026/// }
2027///
2028/// fn foo_to_bar_cloned(
2029///     foo: &Yoke<Foo<'static>, Rc<str>>,
2030/// ) -> Yoke<Bar<'static>, Rc<str>> {
2031///     foo.map_with_cart_cloned(|foo, cart| (*foo, cart.lines().next_back()))
2032/// }
2033///
2034/// fn bar_to_foo(
2035///     bar: Yoke<Bar<'static>, Rc<str>>,
2036/// ) -> Yoke<Foo<'static>, Rc<str>> {
2037///     bar.map_project(|bar, _| (bar.0))
2038/// }
2039///
2040/// fn main() {
2041///     fn assert_hello_world(bar: &Yoke<Bar<'static>, Rc<str>>) {
2042///         assert_eq!(bar.get().0, Some("hello"));
2043///         assert_eq!(bar.get().1, Some("world"));
2044///     }
2045///
2046///     let foo = Yoke::<Foo<'static>, Rc<str>>::attach_to_cart(
2047///         Rc::from("hello\nworld"),
2048///         |cart| cart.lines().next(),
2049///     );
2050///
2051///     assert_eq!(*foo.get(), Some("hello"));
2052///
2053///     let bar = foo_to_bar(foo);
2054///     assert_hello_world(&bar);
2055///
2056///     let foo = bar_to_foo(bar);
2057///
2058///     let bar_one = foo_to_bar_cloned(&foo);
2059///     let bar_two = foo_to_bar_cloned(&foo);
2060///
2061///     assert_hello_world(&bar_one);
2062///     assert_hello_world(&bar_two);
2063/// }
2064/// ```
2065const _: () = ();