Coverage Report

Created: 2025-06-16 06:50

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