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