| { | ||
| "git": { | ||
| "sha1": "55cd12ebb25c6261492e1e3dfa2e6453c54dde31" | ||
| "sha1": "6bd4893cc44c2ca2718de47a119a31cc40045fe5" | ||
| }, | ||
| "path_in_vcs": "utils/yoke" | ||
| } |
+20
-3
@@ -14,6 +14,7 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO | ||
| edition = "2021" | ||
| rust-version = "1.67" | ||
| rust-version = "1.71.1" | ||
| name = "yoke" | ||
| version = "0.7.4" | ||
| version = "0.7.5" | ||
| authors = ["Manish Goregaokar <manishsmail@gmail.com>"] | ||
| build = false | ||
| include = [ | ||
@@ -29,2 +30,6 @@ "data/**/*", | ||
| ] | ||
| autobins = false | ||
| autoexamples = false | ||
| autotests = false | ||
| autobenches = false | ||
| description = "Abstraction allowing borrowed data to be carried along with the backing data it borrows from" | ||
@@ -57,2 +62,14 @@ readme = "README.md" | ||
| [lib] | ||
| name = "yoke" | ||
| path = "src/lib.rs" | ||
| [[test]] | ||
| name = "bincode" | ||
| path = "tests/bincode.rs" | ||
| [[test]] | ||
| name = "miri" | ||
| path = "tests/miri.rs" | ||
| [dependencies.serde] | ||
@@ -68,3 +85,3 @@ version = "1.0.110" | ||
| [dependencies.yoke-derive] | ||
| version = "0.7.4" | ||
| version = "0.7.5" | ||
| optional = true | ||
@@ -71,0 +88,0 @@ default-features = false |
+38
-16
@@ -33,5 +33,13 @@ // This file is part of ICU4X. For terms of use, please see the file | ||
| // Safety note: this method MUST return the same value for the same T, even if i.e. the method gets | ||
| // instantiated in different crates. This can be untrue in surprising ways! For example, just | ||
| // returning a const-ref-to-const would not guarantee that. | ||
| // The current implementation always returns the same address for any T, see | ||
| // [the reference](https://doc.rust-lang.org/reference/items/static-items.html#statics--generics): | ||
| // there is exactly one `SENTINEL` item for any T. | ||
| #[inline] | ||
| fn sentinel_for<T>() -> NonNull<T> { | ||
| static SENTINEL: &u8 = &0x1a; // SUB | ||
| // Safety: SENTINEL is indeed not a null pointer, even after the casts. | ||
| unsafe { NonNull::new_unchecked(SENTINEL as *const u8 as *mut T) } | ||
@@ -60,4 +68,6 @@ } | ||
| /// 2. `drop_raw` returns ownership back to the impl, if there is ownership to transfer | ||
| /// 3. `into_raw` must not return the sentinel pointer | ||
| /// | ||
| /// Note: if `into_raw` returns the sentinel pointer, memory leaks may occur, but this will not | ||
| /// lead to undefined behaviour. | ||
| /// | ||
| /// Note: the pointer `NonNull<Self::Raw>` may or may not be aligned and it should never | ||
@@ -114,3 +124,2 @@ /// be dereferenced. Rust allows unaligned pointers; see [`std::ptr::read_unaligned`]. | ||
| // 2. There is no ownership to transfer | ||
| // 3. External clients do not have the sentinel address so it won't be used in this reference. | ||
| unsafe impl<'a, T> CartablePointerLike for &'a T { | ||
@@ -142,2 +151,3 @@ type Raw = T; | ||
| #[cfg(feature = "alloc")] | ||
| // Safety: | ||
@@ -148,4 +158,2 @@ // 1. `Box::into_raw` says: "After calling this function, the caller is responsible for the | ||
| // resulting Box." | ||
| // 3. The pointer comes from the Box so it won't be the sentinel pointer. | ||
| #[cfg(feature = "alloc")] | ||
| unsafe impl<T> CartablePointerLike for Box<T> { | ||
@@ -161,3 +169,6 @@ type Raw = T; | ||
| unsafe fn drop_raw(pointer: NonNull<T>) { | ||
| let _box = Box::from_raw(pointer.as_ptr()); | ||
| // Safety: per the method's precondition, `pointer` is dereferenceable and was returned by | ||
| // `Self::into_raw`, i.e. by `Box::into_raw`. In this circumstances, calling | ||
| // `Box::from_raw` is safe. | ||
| let _box = unsafe { Box::from_raw(pointer.as_ptr()) }; | ||
@@ -173,2 +184,3 @@ // Boxes are always dropped | ||
| #[cfg(feature = "alloc")] | ||
| // Safety: | ||
@@ -178,4 +190,2 @@ // 1. `Rc::into_raw` says: "Consumes the Rc, returning the wrapped pointer. To avoid a memory | ||
| // 2. See 1. | ||
| // 3. The pointer comes from the Rc so it won't be the sentinel pointer. | ||
| #[cfg(feature = "alloc")] | ||
| unsafe impl<T> CartablePointerLike for Rc<T> { | ||
@@ -189,5 +199,9 @@ type Raw = T; | ||
| } | ||
| #[inline] | ||
| unsafe fn drop_raw(pointer: NonNull<T>) { | ||
| let _rc = Rc::from_raw(pointer.as_ptr()); | ||
| // Safety: per the method's precondition, `pointer` is dereferenceable and was returned by | ||
| // `Self::into_raw`, i.e. by `Rc::into_raw`. In this circumstances, calling | ||
| // `Rc::from_raw` is safe. | ||
| let _rc = unsafe { Rc::from_raw(pointer.as_ptr()) }; | ||
@@ -202,6 +216,6 @@ // Rc is dropped if refcount is 1 | ||
| #[cfg(feature = "alloc")] | ||
| // Safety: | ||
| // 1. The impl increases the refcount such that `Drop` will decrease it. | ||
| // 2. The impl increases refcount without changing the address of data. | ||
| #[cfg(feature = "alloc")] | ||
| unsafe impl<T> CloneableCartablePointerLike for Rc<T> { | ||
@@ -214,3 +228,5 @@ #[inline] | ||
| // Further, this impl is not defined for anything but the global allocator. | ||
| Rc::increment_strong_count(pointer.as_ptr()); | ||
| unsafe { | ||
| Rc::increment_strong_count(pointer.as_ptr()); | ||
| } | ||
| } | ||
@@ -222,2 +238,3 @@ } | ||
| #[cfg(feature = "alloc")] | ||
| // Safety: | ||
@@ -227,4 +244,2 @@ // 1. `Rc::into_raw` says: "Consumes the Arc, returning the wrapped pointer. To avoid a memory | ||
| // 2. See 1. | ||
| // 3. The pointer comes from the Arc so it won't be the sentinel pointer. | ||
| #[cfg(feature = "alloc")] | ||
| unsafe impl<T> CartablePointerLike for Arc<T> { | ||
@@ -240,3 +255,6 @@ type Raw = T; | ||
| unsafe fn drop_raw(pointer: NonNull<T>) { | ||
| let _arc = Arc::from_raw(pointer.as_ptr()); | ||
| // Safety: per the method's precondition, `pointer` is dereferenceable and was returned by | ||
| // `Self::into_raw`, i.e. by `Rc::into_raw`. In this circumstances, calling | ||
| // `Rc::from_raw` is safe. | ||
| let _arc = unsafe { Arc::from_raw(pointer.as_ptr()) }; | ||
@@ -251,6 +269,6 @@ // Arc is dropped if refcount is 1 | ||
| #[cfg(feature = "alloc")] | ||
| // Safety: | ||
| // 1. The impl increases the refcount such that `Drop` will decrease it. | ||
| // 2. The impl increases refcount without changing the address of data. | ||
| #[cfg(feature = "alloc")] | ||
| unsafe impl<T> CloneableCartablePointerLike for Arc<T> { | ||
@@ -263,3 +281,5 @@ #[inline] | ||
| // Further, this impl is not defined for anything but the global allocator. | ||
| Arc::increment_strong_count(pointer.as_ptr()); | ||
| unsafe { | ||
| Arc::increment_strong_count(pointer.as_ptr()); | ||
| } | ||
| } | ||
@@ -305,4 +325,6 @@ } | ||
| pub(crate) fn from_cartable(cartable: C) -> Self { | ||
| let inner = cartable.into_raw(); | ||
| debug_assert_ne!(inner, sentinel_for::<C::Raw>()); | ||
| Self { | ||
| inner: cartable.into_raw(), | ||
| inner, | ||
| _cartable: PhantomData, | ||
@@ -309,0 +331,0 @@ } |
+2
-2
@@ -70,3 +70,3 @@ // This file is part of ICU4X. For terms of use, please see the file | ||
| // Safe because both sub-types implement the trait. | ||
| // Safety: Safe because both sub-types implement the trait. | ||
| unsafe impl<C0, C1, T> StableDeref for EitherCart<C0, C1> | ||
@@ -81,3 +81,3 @@ where | ||
| // Safe because both sub-types implement the trait. | ||
| // Safety: Safe because both sub-types implement the trait. | ||
| unsafe impl<C0, C1> CloneableCart for EitherCart<C0, C1> | ||
@@ -84,0 +84,0 @@ where |
@@ -14,3 +14,4 @@ // This file is part of ICU4X. For terms of use, please see the file | ||
| /// | ||
| /// See [#3696] for a testcase where `Yoke` fails this under miri's field-retagging mode. | ||
| /// See [#3696] for a testcase where `Yoke` fails under miri's field-retagging mode if not using | ||
| /// KindaSortaDangling. | ||
| /// | ||
@@ -63,4 +64,4 @@ /// This has `T: 'static` since we don't need anything | ||
| fn deref(&self) -> &T { | ||
| // Safety: Safe due to the safety invariant on `dangle`; | ||
| // we can always assume initialized | ||
| // Safety: Due to the safety invariant on `dangle`, it is guaranteed to be always | ||
| // initialized as deref is never called during drop. | ||
| unsafe { self.dangle.assume_init_ref() } | ||
@@ -73,4 +74,4 @@ } | ||
| fn deref_mut(&mut self) -> &mut T { | ||
| // Safety: Safe due to the safety invariant on `dangle`; | ||
| // we can always assume initialized | ||
| // Safety: Due to the safety invariant on `dangle`, it is guaranteed to be always | ||
| // initialized as deref_mut is never called during drop. | ||
| unsafe { self.dangle.assume_init_mut() } | ||
@@ -83,13 +84,13 @@ } | ||
| fn drop(&mut self) { | ||
| // Safety: We are reading and dropping a valid initialized T. | ||
| // | ||
| // As `drop_in_place()` is a `read()`-like duplication operation we must be careful that the original value isn't | ||
| // used afterwards. It won't be because this is drop and the only | ||
| // code that will run after this is `self`'s drop glue, and that drop glue is empty | ||
| // because MaybeUninit has no drop. | ||
| // | ||
| // We use `drop_in_place()` instead of `let _ = ... .assume_init_read()` to avoid creating a move | ||
| // of the inner `T` (without `KindaSortaDangling` protection!) type into a local -- we don't want to | ||
| // assert any of `T`'s memory-related validity properties here. | ||
| unsafe { | ||
| // Safety: We are reading and dropping a valid initialized T. | ||
| // | ||
| // As `drop_in_place()` is a `read()`-like duplication operation we must be careful that the original value isn't | ||
| // used afterwards. It won't be because this is drop and the only | ||
| // code that will run after this is `self`'s drop glue, and that drop glue is empty | ||
| // because MaybeUninit has no drop. | ||
| // | ||
| // We use `drop_in_place()` instead of `let _ = ... .assume_init_read()` to avoid creating a move | ||
| // of the inner `T` (without `KindaSortaDangling` protection!) type into a local -- we don't want to | ||
| // assert any of `T`'s memory-related validity properties here. | ||
| self.dangle.as_mut_ptr().drop_in_place(); | ||
@@ -96,0 +97,0 @@ } |
+26
-6
@@ -10,3 +10,6 @@ // This file is part of ICU4X. For terms of use, please see the file | ||
| use crate::Yokeable; | ||
| use core::{mem, ptr}; | ||
| use core::{ | ||
| mem::{self, ManuallyDrop}, | ||
| ptr, | ||
| }; | ||
@@ -37,3 +40,5 @@ macro_rules! copy_yoke_impl { | ||
| macro_rules! impl_copy_type { | ||
| ($ty:ident) => { | ||
| ($ty:ty) => { | ||
| // Safety: all the types that this macro is used to generate impls of Yokeable for do not | ||
| // borrow any memory. | ||
| unsafe impl<'a> Yokeable<'a> for $ty { | ||
@@ -46,2 +51,3 @@ type Output = Self; | ||
| impl_copy_type!(()); | ||
| impl_copy_type!(u8); | ||
@@ -64,5 +70,8 @@ impl_copy_type!(u16); | ||
| // obvious to the compiler that the lifetime is covariant | ||
| // | ||
| // Safety: the caller of this macro must ensure that `Self` is indeed covariant in 'a. | ||
| macro_rules! unsafe_complex_yoke_impl { | ||
| () => { | ||
| fn transform(&'a self) -> &'a Self::Output { | ||
| // Safety: equivalent to casting the lifetime. Macro caller ensures covariance. | ||
| unsafe { mem::transmute(self) } | ||
@@ -73,5 +82,6 @@ } | ||
| debug_assert!(mem::size_of::<Self::Output>() == mem::size_of::<Self>()); | ||
| // Safety: equivalent to casting the lifetime. Macro caller ensures covariance. | ||
| unsafe { | ||
| let ptr: *const Self::Output = (&self as *const Self).cast(); | ||
| mem::forget(self); | ||
| let _ = ManuallyDrop::new(self); | ||
| ptr::read(ptr) | ||
@@ -84,4 +94,6 @@ } | ||
| let ptr: *const Self = (&from as *const Self::Output).cast(); | ||
| mem::forget(from); | ||
| ptr::read(ptr) | ||
| let _ = ManuallyDrop::new(from); | ||
| // Safety: `ptr` is certainly valid, aligned and points to a properly initialized value, as | ||
| // it comes from a value that was moved into a ManuallyDrop. | ||
| unsafe { ptr::read(ptr) } | ||
| } | ||
@@ -94,2 +106,4 @@ | ||
| // Cast away the lifetime of Self | ||
| // Safety: this is equivalent to f(transmute(self)), and the documentation of the trait | ||
| // method explains why doing so is sound. | ||
| unsafe { f(mem::transmute::<&'a mut Self, &'a mut Self::Output>(self)) } | ||
@@ -100,2 +114,4 @@ } | ||
| // Safety: since T implements Yokeable<'a>, Option<T<'b>> must be covariant on 'b or the Yokeable | ||
| // implementation on T would be unsound. | ||
| unsafe impl<'a, T: 'static + for<'b> Yokeable<'b>> Yokeable<'a> for Option<T> { | ||
@@ -106,2 +122,4 @@ type Output = Option<<T as Yokeable<'a>>::Output>; | ||
| // Safety: since T1, T2 implement Yokeable<'a>, (T1<'b>, T2<'b>) must be covariant on 'b or the Yokeable | ||
| // implementation on T would be unsound. | ||
| unsafe impl<'a, T1: 'static + for<'b> Yokeable<'b>, T2: 'static + for<'b> Yokeable<'b>> Yokeable<'a> | ||
@@ -114,5 +132,7 @@ for (T1, T2) | ||
| unsafe impl<'a, T: Yokeable<'a>, const N: usize> Yokeable<'a> for [T; N] { | ||
| // Safety: since T implements Yokeable<'a>, [T<'b>; N] must be covariant on 'b or the Yokeable | ||
| // implementation on T would be unsound. | ||
| unsafe impl<'a, T: 'static + for<'b> Yokeable<'b>, const N: usize> Yokeable<'a> for [T; N] { | ||
| type Output = [<T as Yokeable<'a>>::Output; N]; | ||
| unsafe_complex_yoke_impl!(); | ||
| } |
@@ -108,3 +108,3 @@ // This file is part of ICU4X. For terms of use, please see the file | ||
| //! impl MiniDataMarker for SimpleStruct { | ||
| //! type Yokeable = SimpleStruct; | ||
| //! type DataStruct = SimpleStruct; | ||
| //! } | ||
@@ -301,3 +301,3 @@ //! | ||
| pub fn into_ref(self) -> &'a YokeTraitHack<T> { | ||
| // YokeTraitHack is repr(transparent) so it's always safe | ||
| // Safety: YokeTraitHack is repr(transparent) so it's always safe | ||
| // to transmute YTH<&T> to &YTH<T> | ||
@@ -304,0 +304,0 @@ unsafe { mem::transmute::<YokeTraitHack<&T>, &YokeTraitHack<T>>(self) } |
+113
-55
@@ -84,6 +84,10 @@ // This file is part of ICU4X. For terms of use, please see the file | ||
| // Safety invariant: this type can be anything, but `yokeable` may only contain references to | ||
| // StableDeref parts of this cart, and those references must be valid for the lifetime of | ||
| // this cart (it must own or borrow them). It's ok for this cart to contain stack data as long as it | ||
| // is not referenced by `yokeable` during construction. `attach_to_cart`, the typical constructor | ||
| // of this type, upholds this invariant, but other constructors like `replace_cart` need to uphold it. | ||
| // StableDeref parts of this cart, and the targets of those references must be valid for the | ||
| // lifetime of this cart (it must own or borrow them). It's ok for this cart to contain stack | ||
| // data as long as it is not referenced by `yokeable` during construction. `attach_to_cart`, | ||
| // the typical constructor of this type, upholds this invariant, but other constructors like | ||
| // `replace_cart` need to uphold it. | ||
| // The implementation guarantees that there are no live `yokeable`s that reference data | ||
| // in a `cart` when the `cart` is dropped; this is guaranteed in the drop glue through field | ||
| // order. | ||
| cart: C, | ||
@@ -203,3 +207,8 @@ } | ||
| Self { | ||
| yokeable: KindaSortaDangling::new(unsafe { Y::make(deserialized) }), | ||
| yokeable: KindaSortaDangling::new( | ||
| // Safety: the resulting `yokeable` is dropped before the `cart` because | ||
| // of the Yoke invariant. See the safety docs at the bottom of this file | ||
| // for the justification of why yokeable could only borrow from the Cart. | ||
| unsafe { Y::make(deserialized) }, | ||
| ), | ||
| cart, | ||
@@ -217,6 +226,12 @@ } | ||
| F: for<'de> FnOnce(&'de <C as Deref>::Target) -> Result<<Y as Yokeable<'de>>::Output, E>, | ||
| <C as Deref>::Target: 'static, | ||
| { | ||
| let deserialized = f(cart.deref())?; | ||
| Ok(Self { | ||
| yokeable: KindaSortaDangling::new(unsafe { Y::make(deserialized) }), | ||
| yokeable: KindaSortaDangling::new( | ||
| // Safety: the resulting `yokeable` is dropped before the `cart` because | ||
| // of the Yoke invariant. See the safety docs at the bottom of this file | ||
| // for the justification of why yokeable could only borrow from the Cart. | ||
| unsafe { Y::make(deserialized) }, | ||
| ), | ||
| cart, | ||
@@ -373,2 +388,5 @@ }) | ||
| Yoke { | ||
| // Safety note: the safety invariant of this function guarantees that | ||
| // the data that the yokeable references has its ownership (if any) | ||
| // transferred to the new cart before self.cart is dropped. | ||
| yokeable: self.yokeable, | ||
@@ -472,6 +490,5 @@ cart: f(self.cart), | ||
| pub fn wrap_cart_in_option(self) -> Yoke<Y, Option<C>> { | ||
| unsafe { | ||
| // safe because the cart is preserved, just wrapped | ||
| self.replace_cart(Some) | ||
| } | ||
| // Safety: the cart is preserved (since it is just wrapped into a Some), | ||
| // so any data it owns is too. | ||
| unsafe { self.replace_cart(Some) } | ||
| } | ||
@@ -504,2 +521,4 @@ } | ||
| Self { | ||
| // Safety note: this `yokeable` certainly does not reference data owned by (), so we do | ||
| // not have to worry about when the `yokeable` is dropped. | ||
| yokeable: KindaSortaDangling::new(yokeable), | ||
@@ -516,2 +535,4 @@ cart: (), | ||
| pub fn into_yokeable(self) -> Y { | ||
| // Safety note: since `yokeable` cannot reference data owned by `()`, this is certainly | ||
| // safe. | ||
| self.yokeable.into_inner() | ||
@@ -550,2 +571,3 @@ } | ||
| Self { | ||
| // Safety note: this `yokeable` is known not to borrow from the cart. | ||
| yokeable: KindaSortaDangling::new(yokeable), | ||
@@ -622,2 +644,4 @@ cart: None, | ||
| Some(cart) => Yoke { | ||
| // Safety note: CartableOptionPointer::from_cartable only wraps the `cart`, | ||
| // so the data referenced by the yokeable is still live. | ||
| yokeable: self.yokeable, | ||
@@ -627,2 +651,3 @@ cart: CartableOptionPointer::from_cartable(cart), | ||
| None => Yoke { | ||
| // Safety note: this Yokeable cannot refer to any data since self.cart is None. | ||
| yokeable: self.yokeable, | ||
@@ -668,7 +693,13 @@ cart: CartableOptionPointer::none(), | ||
| #[cfg(feature = "alloc")] | ||
| // Safety: Rc<T> implements CloneStableDeref. | ||
| unsafe impl<T: ?Sized> CloneableCart for Rc<T> {} | ||
| #[cfg(feature = "alloc")] | ||
| // Safety: Arc<T> implements CloneStableDeref. | ||
| unsafe impl<T: ?Sized> CloneableCart for Arc<T> {} | ||
| // Safety: Option<T> cannot deref to anything that T doesn't already deref to. | ||
| unsafe impl<T: CloneableCart> CloneableCart for Option<T> {} | ||
| // Safety: &'a T is indeed StableDeref, and cloning it refers to the same data. | ||
| // &'a T does not own in the first place, so ownership is preserved. | ||
| unsafe impl<'a, T: ?Sized> CloneableCart for &'a T {} | ||
| // Safety: () cannot deref to anything. | ||
| unsafe impl CloneableCart for () {} | ||
@@ -694,3 +725,7 @@ | ||
| Yoke { | ||
| yokeable: KindaSortaDangling::new(unsafe { Y::make(this_hack.clone().0) }), | ||
| yokeable: KindaSortaDangling::new( | ||
| // Safety: C being a CloneableCart guarantees that the data referenced by the | ||
| // `yokeable` is kept alive by the clone of the cart. | ||
| unsafe { Y::make(this_hack.clone().0) }, | ||
| ), | ||
| cart: self.cart.clone(), | ||
@@ -799,3 +834,3 @@ } | ||
| // | ||
| // Safety docs can be found below on `__project_safety_docs()` | ||
| // Safety docs can be found at the end of the file. | ||
| pub fn map_project<P, F>(self, f: F) -> Yoke<P, C> | ||
@@ -811,3 +846,8 @@ where | ||
| Yoke { | ||
| yokeable: KindaSortaDangling::new(unsafe { P::make(p) }), | ||
| yokeable: KindaSortaDangling::new( | ||
| // Safety: the resulting `yokeable` is dropped before the `cart` because | ||
| // of the Yoke invariant. See the safety docs below for the justification of why | ||
| // yokeable could only borrow from the Cart. | ||
| unsafe { P::make(p) }, | ||
| ), | ||
| cart: self.cart, | ||
@@ -833,3 +873,8 @@ } | ||
| Yoke { | ||
| yokeable: KindaSortaDangling::new(unsafe { P::make(p) }), | ||
| yokeable: KindaSortaDangling::new( | ||
| // Safety: the resulting `yokeable` is dropped before the `cart` because | ||
| // of the Yoke invariant. See the safety docs below for the justification of why | ||
| // yokeable could only borrow from the Cart. | ||
| unsafe { P::make(p) }, | ||
| ), | ||
| cart: self.cart.clone(), | ||
@@ -910,3 +955,8 @@ } | ||
| Ok(Yoke { | ||
| yokeable: KindaSortaDangling::new(unsafe { P::make(p) }), | ||
| yokeable: KindaSortaDangling::new( | ||
| // Safety: the resulting `yokeable` is dropped before the `cart` because | ||
| // of the Yoke invariant. See the safety docs below for the justification of why | ||
| // yokeable could only borrow from the Cart. | ||
| unsafe { P::make(p) }, | ||
| ), | ||
| cart: self.cart, | ||
@@ -932,3 +982,8 @@ }) | ||
| Ok(Yoke { | ||
| yokeable: KindaSortaDangling::new(unsafe { P::make(p) }), | ||
| yokeable: KindaSortaDangling::new( | ||
| // Safety: the resulting `yokeable` is dropped before the `cart` because | ||
| // of the Yoke invariant. See the safety docs below for the justification of why | ||
| // yokeable could only borrow from the Cart. | ||
| unsafe { P::make(p) }, | ||
| ), | ||
| cart: self.cart.clone(), | ||
@@ -960,3 +1015,8 @@ }) | ||
| Yoke { | ||
| yokeable: KindaSortaDangling::new(unsafe { P::make(p) }), | ||
| yokeable: KindaSortaDangling::new( | ||
| // Safety: the resulting `yokeable` is dropped before the `cart` because | ||
| // of the Yoke invariant. See the safety docs below for the justification of why | ||
| // yokeable could only borrow from the Cart. | ||
| unsafe { P::make(p) }, | ||
| ), | ||
| cart: self.cart, | ||
@@ -986,3 +1046,8 @@ } | ||
| Yoke { | ||
| yokeable: KindaSortaDangling::new(unsafe { P::make(p) }), | ||
| yokeable: KindaSortaDangling::new( | ||
| // Safety: the resulting `yokeable` is dropped before the `cart` because | ||
| // of the Yoke invariant. See the safety docs below for the justification of why | ||
| // yokeable could only borrow from the Cart. | ||
| unsafe { P::make(p) }, | ||
| ), | ||
| cart: self.cart.clone(), | ||
@@ -1016,3 +1081,8 @@ } | ||
| Ok(Yoke { | ||
| yokeable: KindaSortaDangling::new(unsafe { P::make(p) }), | ||
| yokeable: KindaSortaDangling::new( | ||
| // Safety: the resulting `yokeable` is dropped before the `cart` because | ||
| // of the Yoke invariant. See the safety docs below for the justification of why | ||
| // yokeable could only borrow from the Cart. | ||
| unsafe { P::make(p) }, | ||
| ), | ||
| cart: self.cart, | ||
@@ -1043,3 +1113,8 @@ }) | ||
| Ok(Yoke { | ||
| yokeable: KindaSortaDangling::new(unsafe { P::make(p) }), | ||
| yokeable: KindaSortaDangling::new( | ||
| // Safety: the resulting `yokeable` is dropped before the `cart` because | ||
| // of the Yoke invariant. See the safety docs below for the justification of why | ||
| // yokeable could only borrow from the Cart. | ||
| unsafe { P::make(p) }, | ||
| ), | ||
| cart: self.cart.clone(), | ||
@@ -1088,7 +1163,4 @@ }) | ||
| pub fn erase_rc_cart(self) -> Yoke<Y, ErasedRcCart> { | ||
| unsafe { | ||
| // safe because the cart is preserved, just | ||
| // type-erased | ||
| self.replace_cart(|c| c as ErasedRcCart) | ||
| } | ||
| // Safety: safe because the cart is preserved, as it is just type-erased | ||
| unsafe { self.replace_cart(|c| c as ErasedRcCart) } | ||
| } | ||
@@ -1135,7 +1207,4 @@ } | ||
| pub fn erase_arc_cart(self) -> Yoke<Y, ErasedArcCart> { | ||
| unsafe { | ||
| // safe because the cart is preserved, just | ||
| // type-erased | ||
| self.replace_cart(|c| c as ErasedArcCart) | ||
| } | ||
| // Safety: safe because the cart is preserved, as it is just type-erased | ||
| unsafe { self.replace_cart(|c| c as ErasedArcCart) } | ||
| } | ||
@@ -1182,7 +1251,4 @@ } | ||
| pub fn erase_box_cart(self) -> Yoke<Y, ErasedBoxCart> { | ||
| unsafe { | ||
| // safe because the cart is preserved, just | ||
| // type-erased | ||
| self.replace_cart(|c| c as ErasedBoxCart) | ||
| } | ||
| // Safety: safe because the cart is preserved, as it is just type-erased | ||
| unsafe { self.replace_cart(|c| c as ErasedBoxCart) } | ||
| } | ||
@@ -1199,6 +1265,4 @@ } | ||
| pub fn wrap_cart_in_box(self) -> Yoke<Y, Box<C>> { | ||
| unsafe { | ||
| // safe because the cart is preserved, just wrapped | ||
| self.replace_cart(Box::new) | ||
| } | ||
| // Safety: safe because the cart is preserved, as it is just wrapped. | ||
| unsafe { self.replace_cart(Box::new) } | ||
| } | ||
@@ -1212,6 +1276,4 @@ /// Helper function allowing one to wrap the cart type `C` in an `Rc<T>`. | ||
| pub fn wrap_cart_in_rc(self) -> Yoke<Y, Rc<C>> { | ||
| unsafe { | ||
| // safe because the cart is preserved, just wrapped | ||
| self.replace_cart(Rc::new) | ||
| } | ||
| // Safety: safe because the cart is preserved, as it is just wrapped | ||
| unsafe { self.replace_cart(Rc::new) } | ||
| } | ||
@@ -1225,6 +1287,4 @@ /// Helper function allowing one to wrap the cart type `C` in an `Rc<T>`. | ||
| pub fn wrap_cart_in_arc(self) -> Yoke<Y, Arc<C>> { | ||
| unsafe { | ||
| // safe because the cart is preserved, just wrapped | ||
| self.replace_cart(Arc::new) | ||
| } | ||
| // Safety: safe because the cart is preserved, as it is just wrapped | ||
| unsafe { self.replace_cart(Arc::new) } | ||
| } | ||
@@ -1242,6 +1302,4 @@ } | ||
| pub fn wrap_cart_in_either_a<B>(self) -> Yoke<Y, EitherCart<C, B>> { | ||
| unsafe { | ||
| // safe because the cart is preserved, just wrapped | ||
| self.replace_cart(EitherCart::A) | ||
| } | ||
| // Safety: safe because the cart is preserved, as it is just wrapped. | ||
| unsafe { self.replace_cart(EitherCart::A) } | ||
| } | ||
@@ -1256,6 +1314,4 @@ /// Helper function allowing one to wrap the cart type `C` in an [`EitherCart`]. | ||
| pub fn wrap_cart_in_either_b<A>(self) -> Yoke<Y, EitherCart<A, C>> { | ||
| unsafe { | ||
| // safe because the cart is preserved, just wrapped | ||
| self.replace_cart(EitherCart::B) | ||
| } | ||
| // Safety: safe because the cart is preserved, as it is just wrapped. | ||
| unsafe { self.replace_cart(EitherCart::B) } | ||
| } | ||
@@ -1271,2 +1327,4 @@ } | ||
| /// | ||
| /// Note that correctness arguments are similar if you replace `fn` with `FnOnce`. | ||
| /// | ||
| /// What we want this function to do is take a Yokeable (`Y`) that is borrowing from the cart, and | ||
@@ -1273,0 +1331,0 @@ /// produce another Yokeable (`P`) that also borrows from the same cart. There are a couple potential |
+58
-8
@@ -7,6 +7,8 @@ // This file is part of ICU4X. For terms of use, please see the file | ||
| use alloc::borrow::{Cow, ToOwned}; | ||
| use core::mem; | ||
| use core::{marker::PhantomData, mem}; | ||
| /// The `Yokeable<'a>` trait is implemented on the `'static` version of any zero-copy type; for | ||
| /// example, `Cow<'static, T>` implements `Yokeable<'a>` (for all `'a`). One can use | ||
| /// example, `Cow<'static, T>` implements `Yokeable<'a>` (for all `'a`). | ||
| /// | ||
| /// One can use | ||
| /// `Yokeable::Output` on this trait to obtain the "lifetime'd" value of the `Cow<'static, T>`, | ||
@@ -40,2 +42,4 @@ /// e.g. `<Cow<'static, T> as Yokeable<'a>'>::Output` is `Cow<'a, T>`. | ||
| /// | ||
| /// This trait is also safe to implement on types that do not borrow memory. | ||
| /// | ||
| /// There are further constraints on implementation safety on individual methods. | ||
@@ -234,2 +238,15 @@ /// | ||
| /// ``` | ||
| /// | ||
| /// More formally, a reference to an object that `f` assigns to a reference | ||
| /// in Self<'a> could be obtained from: | ||
| /// - a local variable: the compiler rejects the assignment because 'a certainly | ||
| /// outlives local variables in f. | ||
| /// - a field in its argument: because of the for<'b> bound, the call to `f` | ||
| /// must be valid for a particular 'b that is strictly shorter than 'a. Thus, | ||
| /// the compiler rejects the assignment. | ||
| /// - a reference field in Self<'a>: this does not extend the set of | ||
| /// non-static lifetimes reachable from Self<'a>, so this is fine. | ||
| /// - one of f's captures: since F: 'static, the resulting reference must refer | ||
| /// to 'static data. | ||
| /// - a static or thread_local variable: ditto. | ||
| fn transform_mut<F>(&'a mut self, f: F) | ||
@@ -242,2 +259,3 @@ where | ||
| #[cfg(feature = "alloc")] | ||
| // Safety: Cow<'a, _> is covariant in 'a. | ||
| unsafe impl<'a, T: 'static + ToOwned + ?Sized> Yokeable<'a> for Cow<'static, T> | ||
@@ -265,4 +283,6 @@ where | ||
| let ptr: *const Self = (&from as *const Self::Output).cast(); | ||
| mem::forget(from); | ||
| core::ptr::read(ptr) | ||
| let _ = core::mem::ManuallyDrop::new(from); | ||
| // Safety: `ptr` is certainly valid, aligned and points to a properly initialized value, as | ||
| // it comes from a value that was moved into a ManuallyDrop. | ||
| unsafe { core::ptr::read(ptr) } | ||
| } | ||
@@ -275,2 +295,4 @@ #[inline] | ||
| // Cast away the lifetime of Self | ||
| // Safety: this is equivalent to f(transmute(self)), and the documentation of the trait | ||
| // method explains why doing so is sound. | ||
| unsafe { f(mem::transmute::<&'a mut Self, &'a mut Self::Output>(self)) } | ||
@@ -280,2 +302,3 @@ } | ||
| // Safety: &'a T is covariant in 'a. | ||
| unsafe impl<'a, T: 'static + ?Sized> Yokeable<'a> for &'static T { | ||
@@ -295,3 +318,5 @@ type Output = &'a T; | ||
| unsafe fn make(from: &'a T) -> Self { | ||
| mem::transmute(from) | ||
| // Safety: function safety invariant guarantees that the returned reference | ||
| // will never be used beyond its original lifetime. | ||
| unsafe { mem::transmute(from) } | ||
| } | ||
@@ -304,2 +329,4 @@ #[inline] | ||
| // Cast away the lifetime of Self | ||
| // Safety: this is equivalent to f(transmute(self)), and the documentation of the trait | ||
| // method explains why doing so is sound. | ||
| unsafe { f(mem::transmute::<&'a mut Self, &'a mut Self::Output>(self)) } | ||
@@ -310,2 +337,3 @@ } | ||
| #[cfg(feature = "alloc")] | ||
| // Safety: Vec<T: 'static> never borrows. | ||
| unsafe impl<'a, T: 'static> Yokeable<'a> for alloc::vec::Vec<T> { | ||
@@ -315,3 +343,2 @@ type Output = alloc::vec::Vec<T>; | ||
| fn transform(&'a self) -> &'a alloc::vec::Vec<T> { | ||
| // Doesn't need unsafe: `'a` is covariant so this lifetime cast is always safe | ||
| self | ||
@@ -321,3 +348,2 @@ } | ||
| fn transform_owned(self) -> alloc::vec::Vec<T> { | ||
| // Doesn't need unsafe: `'a` is covariant so this lifetime cast is always safe | ||
| self | ||
@@ -334,5 +360,29 @@ } | ||
| { | ||
| // Doesn't need unsafe: `'a` is covariant so this lifetime cast is always safe | ||
| f(self) | ||
| } | ||
| } | ||
| // Safety: PhantomData is a ZST. | ||
| unsafe impl<'a, T: ?Sized + 'static> Yokeable<'a> for PhantomData<T> { | ||
| type Output = PhantomData<T>; | ||
| fn transform(&'a self) -> &'a Self::Output { | ||
| self | ||
| } | ||
| fn transform_owned(self) -> Self::Output { | ||
| self | ||
| } | ||
| unsafe fn make(from: Self::Output) -> Self { | ||
| from | ||
| } | ||
| fn transform_mut<F>(&'a mut self, f: F) | ||
| where | ||
| // be VERY CAREFUL changing this signature, it is very nuanced (see above) | ||
| F: 'static + for<'b> FnOnce(&'b mut Self::Output), | ||
| { | ||
| f(self) | ||
| } | ||
| } |
Sorry, the diff of this file is not supported yet