Coverage Report

Created: 2026-09-01 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/yoke-0.8.3/src/yoke.rs
Line
Count
Source
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
5
use crate::cartable_ptr::{CartableOptionPointer, CartablePointerLike};
6
use crate::either::EitherCart;
7
#[cfg(feature = "alloc")]
8
use crate::erased::{ErasedArcCart, ErasedBoxCart, ErasedRcCart};
9
use crate::kinda_sorta_dangling::KindaSortaDangling;
10
use crate::utils;
11
use crate::Yokeable;
12
use core::marker::PhantomData;
13
use core::mem::ManuallyDrop;
14
use core::ops::Deref;
15
use stable_deref_trait::StableDeref;
16
17
#[cfg(feature = "alloc")]
18
use alloc::boxed::Box;
19
#[cfg(feature = "alloc")]
20
use alloc::rc::Rc;
21
#[cfg(feature = "alloc")]
22
use 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
/// ```
80
pub 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
98
impl<Y: for<'a> Yokeable<'a>, C: core::fmt::Debug> core::fmt::Debug for Yoke<Y, C>
99
where
100
    for<'a> <Y as Yokeable<'a>>::Output: core::fmt::Debug,
101
{
102
0
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
103
0
        f.debug_struct("Yoke")
104
0
            .field("yokeable", self.get())
105
0
            .field("cart", self.backing_cart())
106
0
            .finish()
107
0
    }
108
}
109
110
impl<Y, C> core::fmt::Display for Yoke<Y, C>
111
where
112
    Y: for<'a> Yokeable<'a>,
113
    for<'a> <Y as Yokeable<'a>>::Output: core::fmt::Display,
114
{
115
0
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
116
0
        core::fmt::Display::fmt(self.get(), f)
117
0
    }
118
}
119
120
impl<Y, C> PartialEq for Yoke<Y, C>
121
where
122
    Y: for<'a> Yokeable<'a>,
123
    for<'a> <Y as Yokeable<'a>>::Output: PartialEq,
124
{
125
0
    fn eq(&self, other: &Self) -> bool {
126
0
        self.get() == other.get()
127
0
    }
128
}
129
130
impl<Y, C> Eq for Yoke<Y, C>
131
where
132
    Y: for<'a> Yokeable<'a>,
133
    for<'a> <Y as Yokeable<'a>>::Output: Eq,
134
{
135
}
136
137
impl<Y, C> PartialOrd for Yoke<Y, C>
138
where
139
    Y: for<'a> Yokeable<'a>,
140
    for<'a> <Y as Yokeable<'a>>::Output: PartialOrd,
141
{
142
0
    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
143
0
        self.get().partial_cmp(other.get())
144
0
    }
145
}
146
147
impl<Y, C> Ord for Yoke<Y, C>
148
where
149
    Y: for<'a> Yokeable<'a>,
150
    for<'a> <Y as Yokeable<'a>>::Output: Ord,
151
{
152
0
    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
153
0
        self.get().cmp(other.get())
154
0
    }
155
}
156
157
#[test]
158
fn 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]
170
fn 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]
179
fn 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]
190
fn 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]
204
fn 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
215
impl<Y: for<'a> Yokeable<'a>, C: StableDeref> Yoke<Y, C>
216
where
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
0
    pub fn attach_to_cart<F>(cart: C, f: F) -> Self
288
0
    where
289
0
        // safety note: This works by enforcing that the *only* place the return value of F
290
0
        // can borrow from is the cart, since `F` must be valid for all lifetimes `'de`
291
0
        //
292
0
        // The <C as Deref>::Target: 'static on the impl is crucial for safety as well
293
0
        //
294
0
        // See safety docs at the bottom of this file for more information
295
0
        F: for<'de> FnOnce(&'de <C as Deref>::Target) -> <Y as Yokeable<'de>>::Output,
296
0
        <C as Deref>::Target: 'static,
297
    {
298
0
        let deserialized = f(cart.deref());
299
0
        Self {
300
0
            yokeable: KindaSortaDangling::new(
301
0
                // Safety: the resulting `yokeable` is dropped before the `cart` because
302
0
                // of the Yoke invariant. See the safety docs at the bottom of this file
303
0
                // for the justification of why yokeable could only borrow from the Cart.
304
0
                unsafe { Y::make(deserialized) },
305
0
            ),
306
0
            cart,
307
0
        }
308
0
    }
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
0
    pub fn try_attach_to_cart<E, F>(cart: C, f: F) -> Result<Self, E>
316
0
    where
317
0
        F: for<'de> FnOnce(&'de <C as Deref>::Target) -> Result<<Y as Yokeable<'de>>::Output, E>,
318
0
        <C as Deref>::Target: 'static,
319
    {
320
0
        let deserialized = f(cart.deref())?;
321
0
        Ok(Self {
322
0
            yokeable: KindaSortaDangling::new(
323
0
                // Safety: the resulting `yokeable` is dropped before the `cart` because
324
0
                // of the Yoke invariant. See the safety docs at the bottom of this file
325
0
                // for the justification of why yokeable could only borrow from the Cart.
326
0
                unsafe { Y::make(deserialized) },
327
0
            ),
328
0
            cart,
329
0
        })
330
0
    }
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
0
    pub fn attach_to_cart_badly(
337
0
        cart: C,
338
0
        f: for<'de> fn(&'de <C as Deref>::Target) -> <Y as Yokeable<'de>>::Output,
339
0
    ) -> Self {
340
0
        Self::attach_to_cart(cart, f)
341
0
    }
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
0
    pub fn try_attach_to_cart_badly<E>(
348
0
        cart: C,
349
0
        f: for<'de> fn(&'de <C as Deref>::Target) -> Result<<Y as Yokeable<'de>>::Output, E>,
350
0
    ) -> Result<Self, E> {
351
0
        Self::try_attach_to_cart(cart, f)
352
0
    }
353
}
354
355
impl<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
0
    pub fn get<'a>(&'a self) -> &'a <Y as Yokeable<'a>>::Output {
387
0
        self.yokeable.transform()
388
0
    }
Unexecuted instantiation: <yoke::yoke::Yoke<icu_properties::provider::PropertyUnicodeSet, yoke::cartable_ptr::CartableOptionPointer<&()>>>::get
Unexecuted instantiation: <yoke::yoke::Yoke<icu_properties::provider::PropertyCodePointSet, yoke::cartable_ptr::CartableOptionPointer<&()>>>::get
Unexecuted instantiation: <yoke::yoke::Yoke<icu_normalizer::provider::DecompositionData, yoke::cartable_ptr::CartableOptionPointer<&()>>>::get
Unexecuted instantiation: <yoke::yoke::Yoke<icu_normalizer::provider::DecompositionTables, yoke::cartable_ptr::CartableOptionPointer<&()>>>::get
Unexecuted instantiation: <yoke::yoke::Yoke<icu_normalizer::provider::CanonicalCompositions, yoke::cartable_ptr::CartableOptionPointer<&()>>>::get
Unexecuted instantiation: <yoke::yoke::Yoke<icu_normalizer::provider::NonRecursiveDecompositionSupplement, yoke::cartable_ptr::CartableOptionPointer<&()>>>::get
Unexecuted instantiation: <yoke::yoke::Yoke<_, _>>::get
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
0
    pub fn backing_cart(&self) -> &C {
395
0
        &self.cart
396
0
    }
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
0
    pub fn into_backing_cart(self) -> C {
448
0
        self.cart
449
0
    }
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
0
    pub unsafe fn replace_cart<C2>(self, f: impl FnOnce(C) -> C2) -> Yoke<Y, C2> {
479
0
        let yokeable = ManuallyDrop::new(self.yokeable);
480
0
        let cart = f(self.cart);
481
0
        Yoke {
482
0
            // Safety note: the safety invariant of this function guarantees that
483
0
            // the data that the yokeable references has its ownership (if any)
484
0
            // transferred to the new cart before self.cart is dropped, unless
485
0
            // `f` panics, in which case the above `ManuallyDrop` ensures that
486
0
            // the yokeable is leaked (preventing any UB from dropping the
487
0
            // yokeable after its cart).
488
0
            yokeable: ManuallyDrop::into_inner(yokeable),
489
0
            cart,
490
0
        }
491
0
    }
Unexecuted instantiation: <yoke::yoke::Yoke<&[u8], core::option::Option<icu_provider::response::Cart>>>::replace_cart::<core::option::Option<&()>, <icu_provider::response::Cart>::unwrap_cart<&[u8]>::{closure#0}>
Unexecuted instantiation: <yoke::yoke::Yoke<_, _>>::replace_cart::<_, _>
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
0
    pub fn with_mut<'a, F>(&'a mut self, f: F)
556
0
    where
557
0
        F: 'static + for<'b> FnOnce(&'b mut <Y as Yokeable<'a>>::Output),
558
    {
559
0
        self.yokeable.transform_mut(f);
560
0
    }
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
0
    pub fn with_mut_return<'a, F, R>(&'a mut self, f: F) -> R
572
0
    where
573
0
        F: 'static + for<'b> FnOnce(&'b mut <Y as Yokeable<'a>>::Output) -> R,
574
0
        R: 'static,
575
    {
576
0
        utils::transform_mut_yokeable(&mut *self.yokeable, f)
577
0
    }
578
579
    /// Helper function allowing one to wrap the cart type `C` in an `Option<T>`.
580
    #[inline]
581
0
    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
0
        unsafe { self.replace_cart(Some) }
585
0
    }
586
}
587
588
impl<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
0
    pub fn new_always_owned(yokeable: Y) -> Self {
611
0
        Self {
612
0
            // Safety note: this `yokeable` certainly does not reference data owned by (), so we do
613
0
            // not have to worry about when the `yokeable` is dropped.
614
0
            yokeable: KindaSortaDangling::new(yokeable),
615
0
            cart: (),
616
0
        }
617
0
    }
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
0
    pub fn into_yokeable(self) -> Y {
625
        // Safety note: since `yokeable` cannot reference data owned by `()`, this is certainly
626
        // safe.
627
0
        self.yokeable.into_inner()
628
0
    }
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,
633
impl<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
0
    pub const fn new_owned(yokeable: Y) -> Self {
659
0
        Self {
660
0
            // Safety note: this `yokeable` is known not to borrow from the cart.
661
0
            yokeable: KindaSortaDangling::new(yokeable),
662
0
            cart: None,
663
0
        }
664
0
    }
Unexecuted instantiation: <yoke::yoke::Yoke<icu_properties::provider::PropertyUnicodeSet, core::option::Option<&()>>>::new_owned
Unexecuted instantiation: <yoke::yoke::Yoke<icu_properties::provider::PropertyCodePointSet, core::option::Option<&()>>>::new_owned
Unexecuted instantiation: <yoke::yoke::Yoke<&[u8], core::option::Option<&()>>>::new_owned
Unexecuted instantiation: <yoke::yoke::Yoke<_, core::option::Option<_>>>::new_owned
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
0
    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
0
        match self.cart {
674
0
            Some(_) => Err(self),
675
0
            None => Ok(self.yokeable.into_inner()),
676
        }
677
0
    }
678
}
679
680
impl<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
0
    pub fn convert_cart_into_option_pointer(self) -> Yoke<Y, CartableOptionPointer<C>> {
729
0
        match self.cart {
730
0
            Some(cart) => Yoke {
731
0
                // Safety note: CartableOptionPointer::from_cartable only wraps the `cart`,
732
0
                // so the data referenced by the yokeable is still live.
733
0
                yokeable: self.yokeable,
734
0
                cart: CartableOptionPointer::from_cartable(cart),
735
0
            },
736
0
            None => Yoke {
737
0
                // Safety note: this Yokeable cannot refer to any data since self.cart is None.
738
0
                yokeable: self.yokeable,
739
0
                cart: CartableOptionPointer::none(),
740
0
            },
741
        }
742
0
    }
Unexecuted instantiation: <yoke::yoke::Yoke<icu_properties::provider::PropertyUnicodeSet, core::option::Option<&()>>>::convert_cart_into_option_pointer
Unexecuted instantiation: <yoke::yoke::Yoke<icu_properties::provider::PropertyCodePointSet, core::option::Option<&()>>>::convert_cart_into_option_pointer
Unexecuted instantiation: <yoke::yoke::Yoke<&[u8], core::option::Option<&()>>>::convert_cart_into_option_pointer
Unexecuted instantiation: <yoke::yoke::Yoke<_, core::option::Option<_>>>::convert_cart_into_option_pointer
743
}
744
745
impl<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
0
    pub fn try_into_yokeable(self) -> Result<Y, Self> {
752
0
        if self.cart.is_none() {
753
0
            Ok(self.yokeable.into_inner())
754
        } else {
755
0
            Err(self)
756
        }
757
0
    }
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.
775
pub unsafe trait CloneableCart: Clone {}
776
777
#[cfg(feature = "alloc")]
778
// Safety: Rc<T> implements CloneStableDeref.
779
unsafe impl<T: ?Sized> CloneableCart for Rc<T> {}
780
#[cfg(feature = "alloc")]
781
// Safety: Arc<T> implements CloneStableDeref.
782
unsafe impl<T: ?Sized> CloneableCart for Arc<T> {}
783
// Safety: Option<T> cannot deref to anything that T doesn't already deref to.
784
unsafe 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.
787
unsafe impl<'a, T: ?Sized> CloneableCart for &'a T {}
788
// Safety: () cannot deref to anything.
789
unsafe 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.
800
impl<Y: for<'a> Yokeable<'a>, C: CloneableCart> Clone for Yoke<Y, C>
801
where
802
    for<'a> <Y as Yokeable<'a>>::Output: Clone,
803
{
804
0
    fn clone(&self) -> Self {
805
        // We have an &T not a T, and we can clone T
806
0
        let this = self.get().clone();
807
0
        Yoke {
808
0
            yokeable: KindaSortaDangling::new(
809
0
                // Safety: C being a CloneableCart guarantees that the data referenced by the
810
0
                // `yokeable` is kept alive by the clone of the cart.
811
0
                unsafe { Y::make(this) },
812
0
            ),
813
0
            cart: self.cart.clone(),
814
0
        }
815
0
    }
816
}
817
818
#[test]
819
fn 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
850
impl<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
0
    pub fn map_project<P, F>(self, f: F) -> Yoke<P, C>
919
0
    where
920
0
        P: for<'a> Yokeable<'a>,
921
0
        F: for<'a> FnOnce(
922
0
            <Y as Yokeable<'a>>::Output,
923
0
            PhantomData<&'a ()>,
924
0
        ) -> <P as Yokeable<'a>>::Output,
925
    {
926
0
        let p = f(self.yokeable.into_inner().transform_owned(), PhantomData);
927
0
        Yoke {
928
0
            yokeable: KindaSortaDangling::new(
929
0
                // Safety: the resulting `yokeable` is dropped before the `cart` because
930
0
                // of the Yoke invariant. See the safety docs below for the justification of why
931
0
                // yokeable could only borrow from the Cart.
932
0
                unsafe { P::make(p) },
933
0
            ),
934
0
            cart: self.cart,
935
0
        }
936
0
    }
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
0
    pub fn map_project_cloned<'this, P, F>(&'this self, f: F) -> Yoke<P, C>
944
0
    where
945
0
        P: for<'a> Yokeable<'a>,
946
0
        C: CloneableCart,
947
0
        F: for<'a> FnOnce(
948
0
            &'this <Y as Yokeable<'a>>::Output,
949
0
            PhantomData<&'a ()>,
950
0
        ) -> <P as Yokeable<'a>>::Output,
951
    {
952
0
        let p = f(self.get(), PhantomData);
953
0
        Yoke {
954
0
            yokeable: KindaSortaDangling::new(
955
0
                // Safety: the resulting `yokeable` is dropped before the `cart` because
956
0
                // of the Yoke invariant. See the safety docs below for the justification of why
957
0
                // yokeable could only borrow from the Cart.
958
0
                unsafe { P::make(p) },
959
0
            ),
960
0
            cart: self.cart.clone(),
961
0
        }
962
0
    }
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
0
    pub fn try_map_project<P, F, E>(self, f: F) -> Result<Yoke<P, C>, E>
1024
0
    where
1025
0
        P: for<'a> Yokeable<'a>,
1026
0
        F: for<'a> FnOnce(
1027
0
            <Y as Yokeable<'a>>::Output,
1028
0
            PhantomData<&'a ()>,
1029
0
        ) -> Result<<P as Yokeable<'a>>::Output, E>,
1030
    {
1031
0
        let p = f(self.yokeable.into_inner().transform_owned(), PhantomData)?;
1032
0
        Ok(Yoke {
1033
0
            yokeable: KindaSortaDangling::new(
1034
0
                // Safety: the resulting `yokeable` is dropped before the `cart` because
1035
0
                // of the Yoke invariant. See the safety docs below for the justification of why
1036
0
                // yokeable could only borrow from the Cart.
1037
0
                unsafe { P::make(p) },
1038
0
            ),
1039
0
            cart: self.cart,
1040
0
        })
1041
0
    }
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
0
    pub fn try_map_project_cloned<'this, P, F, E>(&'this self, f: F) -> Result<Yoke<P, C>, E>
1049
0
    where
1050
0
        P: for<'a> Yokeable<'a>,
1051
0
        C: CloneableCart,
1052
0
        F: for<'a> FnOnce(
1053
0
            &'this <Y as Yokeable<'a>>::Output,
1054
0
            PhantomData<&'a ()>,
1055
0
        ) -> Result<<P as Yokeable<'a>>::Output, E>,
1056
    {
1057
0
        let p = f(self.get(), PhantomData)?;
1058
0
        Ok(Yoke {
1059
0
            yokeable: KindaSortaDangling::new(
1060
0
                // Safety: the resulting `yokeable` is dropped before the `cart` because
1061
0
                // of the Yoke invariant. See the safety docs below for the justification of why
1062
0
                // yokeable could only borrow from the Cart.
1063
0
                unsafe { P::make(p) },
1064
0
            ),
1065
0
            cart: self.cart.clone(),
1066
0
        })
1067
0
    }
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
0
    pub fn map_project_with_explicit_capture<P, T>(
1074
0
        self,
1075
0
        capture: T,
1076
0
        f: for<'a> fn(
1077
0
            <Y as Yokeable<'a>>::Output,
1078
0
            capture: T,
1079
0
            PhantomData<&'a ()>,
1080
0
        ) -> <P as Yokeable<'a>>::Output,
1081
0
    ) -> Yoke<P, C>
1082
0
    where
1083
0
        P: for<'a> Yokeable<'a>,
1084
    {
1085
0
        let p = f(
1086
0
            self.yokeable.into_inner().transform_owned(),
1087
0
            capture,
1088
0
            PhantomData,
1089
0
        );
1090
0
        Yoke {
1091
0
            yokeable: KindaSortaDangling::new(
1092
0
                // Safety: the resulting `yokeable` is dropped before the `cart` because
1093
0
                // of the Yoke invariant. See the safety docs below for the justification of why
1094
0
                // yokeable could only borrow from the Cart.
1095
0
                unsafe { P::make(p) },
1096
0
            ),
1097
0
            cart: self.cart,
1098
0
        }
1099
0
    }
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
0
    pub fn map_project_cloned_with_explicit_capture<'this, P, T>(
1107
0
        &'this self,
1108
0
        capture: T,
1109
0
        f: for<'a> fn(
1110
0
            &'this <Y as Yokeable<'a>>::Output,
1111
0
            capture: T,
1112
0
            PhantomData<&'a ()>,
1113
0
        ) -> <P as Yokeable<'a>>::Output,
1114
0
    ) -> Yoke<P, C>
1115
0
    where
1116
0
        P: for<'a> Yokeable<'a>,
1117
0
        C: CloneableCart,
1118
    {
1119
0
        let p = f(self.get(), capture, PhantomData);
1120
0
        Yoke {
1121
0
            yokeable: KindaSortaDangling::new(
1122
0
                // Safety: the resulting `yokeable` is dropped before the `cart` because
1123
0
                // of the Yoke invariant. See the safety docs below for the justification of why
1124
0
                // yokeable could only borrow from the Cart.
1125
0
                unsafe { P::make(p) },
1126
0
            ),
1127
0
            cart: self.cart.clone(),
1128
0
        }
1129
0
    }
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
0
    pub fn try_map_project_with_explicit_capture<P, T, E>(
1138
0
        self,
1139
0
        capture: T,
1140
0
        f: for<'a> fn(
1141
0
            <Y as Yokeable<'a>>::Output,
1142
0
            capture: T,
1143
0
            PhantomData<&'a ()>,
1144
0
        ) -> Result<<P as Yokeable<'a>>::Output, E>,
1145
0
    ) -> Result<Yoke<P, C>, E>
1146
0
    where
1147
0
        P: for<'a> Yokeable<'a>,
1148
    {
1149
0
        let p = f(
1150
0
            self.yokeable.into_inner().transform_owned(),
1151
0
            capture,
1152
0
            PhantomData,
1153
0
        )?;
1154
0
        Ok(Yoke {
1155
0
            yokeable: KindaSortaDangling::new(
1156
0
                // Safety: the resulting `yokeable` is dropped before the `cart` because
1157
0
                // of the Yoke invariant. See the safety docs below for the justification of why
1158
0
                // yokeable could only borrow from the Cart.
1159
0
                unsafe { P::make(p) },
1160
0
            ),
1161
0
            cart: self.cart,
1162
0
        })
1163
0
    }
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
0
    pub fn try_map_project_cloned_with_explicit_capture<'this, P, T, E>(
1172
0
        &'this self,
1173
0
        capture: T,
1174
0
        f: for<'a> fn(
1175
0
            &'this <Y as Yokeable<'a>>::Output,
1176
0
            capture: T,
1177
0
            PhantomData<&'a ()>,
1178
0
        ) -> Result<<P as Yokeable<'a>>::Output, E>,
1179
0
    ) -> Result<Yoke<P, C>, E>
1180
0
    where
1181
0
        P: for<'a> Yokeable<'a>,
1182
0
        C: CloneableCart,
1183
    {
1184
0
        let p = f(self.get(), capture, PhantomData)?;
1185
0
        Ok(Yoke {
1186
0
            yokeable: KindaSortaDangling::new(
1187
0
                // Safety: the resulting `yokeable` is dropped before the `cart` because
1188
0
                // of the Yoke invariant. See the safety docs below for the justification of why
1189
0
                // yokeable could only borrow from the Cart.
1190
0
                unsafe { P::make(p) },
1191
0
            ),
1192
0
            cart: self.cart.clone(),
1193
0
        })
1194
0
    }
1195
}
1196
1197
impl<Y: for<'a> Yokeable<'a>, C: StableDeref> Yoke<Y, C>
1198
where
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
0
    pub fn map_with_cart<P, F>(self, f: F) -> Yoke<P, C>
1298
0
    where
1299
0
        P: for<'a> Yokeable<'a>,
1300
0
        F: for<'a> FnOnce(
1301
0
            <Y as Yokeable<'a>>::Output,
1302
0
            &'a <C as Deref>::Target,
1303
0
        ) -> <P as Yokeable<'a>>::Output,
1304
0
        <C as Deref>::Target: 'static,
1305
    {
1306
0
        let p = f(
1307
0
            self.yokeable.into_inner().transform_owned(),
1308
0
            self.cart.deref(),
1309
0
        );
1310
0
        Yoke {
1311
0
            yokeable: KindaSortaDangling::new(
1312
0
                // Safety: the resulting `yokeable` is dropped before the `cart` because
1313
0
                // of the Yoke invariant. See the safety docs below for the justification of why
1314
0
                // yokeable could only borrow from the Cart.
1315
0
                unsafe { P::make(p) },
1316
0
            ),
1317
0
            cart: self.cart,
1318
0
        }
1319
0
    }
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
0
    pub fn map_with_cart_cloned<'this, P, F>(&'this self, f: F) -> Yoke<P, C>
1331
0
    where
1332
0
        P: for<'a> Yokeable<'a>,
1333
0
        F: for<'a> FnOnce(
1334
0
            &'this <Y as Yokeable<'a>>::Output,
1335
0
            &'a <C as Deref>::Target,
1336
0
        ) -> <P as Yokeable<'a>>::Output,
1337
0
        C: CloneableCart,
1338
0
        <C as Deref>::Target: 'static,
1339
    {
1340
0
        let p = f(self.get(), self.cart.deref());
1341
0
        Yoke {
1342
0
            yokeable: KindaSortaDangling::new(
1343
0
                // Safety: the resulting `yokeable` is dropped before the `cart` because
1344
0
                // of the Yoke invariant. See the safety docs below for the justification of why
1345
0
                // yokeable could only borrow from the Cart.
1346
0
                unsafe { P::make(p) },
1347
0
            ),
1348
0
            cart: self.cart.clone(),
1349
0
        }
1350
0
    }
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
0
    pub fn try_map_with_cart<P, F, E>(self, f: F) -> Result<Yoke<P, C>, E>
1376
0
    where
1377
0
        P: for<'a> Yokeable<'a>,
1378
0
        F: for<'a> FnOnce(
1379
0
            <Y as Yokeable<'a>>::Output,
1380
0
            &'a <C as Deref>::Target,
1381
0
        ) -> Result<<P as Yokeable<'a>>::Output, E>,
1382
0
        <C as Deref>::Target: 'static,
1383
    {
1384
0
        let p = f(
1385
0
            self.yokeable.into_inner().transform_owned(),
1386
0
            self.cart.deref(),
1387
0
        )?;
1388
0
        Ok(Yoke {
1389
0
            yokeable: KindaSortaDangling::new(
1390
0
                // Safety: the resulting `yokeable` is dropped before the `cart` because
1391
0
                // of the Yoke invariant. See the safety docs below for the justification of why
1392
0
                // yokeable could only borrow from the Cart.
1393
0
                unsafe { P::make(p) },
1394
0
            ),
1395
0
            cart: self.cart,
1396
0
        })
1397
0
    }
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
0
    pub fn try_map_with_cart_cloned<'this, P, F, E>(&'this self, f: F) -> Result<Yoke<P, C>, E>
1409
0
    where
1410
0
        P: for<'a> Yokeable<'a>,
1411
0
        C: CloneableCart,
1412
0
        F: for<'a> FnOnce(
1413
0
            &'this <Y as Yokeable<'a>>::Output,
1414
0
            &'a <C as Deref>::Target,
1415
0
        ) -> Result<<P as Yokeable<'a>>::Output, E>,
1416
0
        <C as Deref>::Target: 'static,
1417
    {
1418
0
        let p = f(self.get(), self.cart.deref())?;
1419
0
        Ok(Yoke {
1420
0
            yokeable: KindaSortaDangling::new(
1421
0
                // Safety: the resulting `yokeable` is dropped before the `cart` because
1422
0
                // of the Yoke invariant. See the safety docs below for the justification of why
1423
0
                // yokeable could only borrow from the Cart.
1424
0
                unsafe { P::make(p) },
1425
0
            ),
1426
0
            cart: self.cart.clone(),
1427
0
        })
1428
0
    }
1429
}
1430
1431
#[cfg(feature = "alloc")]
1432
impl<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")]
1475
impl<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")]
1518
impl<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")]
1561
impl<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
1596
impl<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
0
    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
0
        unsafe { self.replace_cart(EitherCart::A) }
1607
0
    }
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
0
    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
0
        unsafe { self.replace_cart(EitherCart::B) }
1618
0
    }
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.
1725
const _: () = ();
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
/// ```
1871
const _: () = ();
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
/// ```
2167
const _: () = ();