summaryrefslogtreecommitdiffstats
path: root/vendor/yoke
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/yoke')
-rw-r--r--vendor/yoke/.cargo-checksum.json2
-rw-r--r--vendor/yoke/Cargo.toml13
-rw-r--r--vendor/yoke/src/erased.rs8
-rw-r--r--vendor/yoke/src/is_covariant.rs142
-rw-r--r--vendor/yoke/src/lib.rs2
-rw-r--r--vendor/yoke/src/macro_impls.rs3
-rw-r--r--vendor/yoke/src/yoke.rs228
-rw-r--r--vendor/yoke/src/zero_from.rs5
8 files changed, 218 insertions, 185 deletions
diff --git a/vendor/yoke/.cargo-checksum.json b/vendor/yoke/.cargo-checksum.json
index 1052beac5..4b8d4839c 100644
--- a/vendor/yoke/.cargo-checksum.json
+++ b/vendor/yoke/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"Cargo.toml":"a26eaa79fc44d47a95490b583429bc252338eafe17172ddecc5fed5b90709748","LICENSE":"4ad7541d66a407234e2c84902124cef325c29f3e966353efdb800bedb8b8da21","README.md":"30321954bbc84770e2b50e8cc6da2a9e98f97698cbf1fe829747d4f3c6f6f791","src/either.rs":"028bb043392d1f3d608589d65d997a241b5ba7bb5114cf023179a38bf1c1cf2b","src/erased.rs":"97e545e421f08ae22c6bd8b4d89c9f91876a0b502cc74984dce77f0506decc4d","src/is_covariant.rs":"2d7f92083473be10847b4471917994eee060bf9e31f5d2672ac78cfe64be91b9","src/lib.rs":"5cf0694e0168c8240de935a2187d3f34d2b1ebe03429662df45b5bd97d3226ff","src/macro_impls.rs":"7d626660f4f7a0148710c5b308511604bff1010b813f124ba43ec4e591057981","src/trait_hack.rs":"d3a8b93e0a984febabd288af558d25e5a93019e2bf9209bc023762c9182aa7fc","src/yoke.rs":"8ec18fbbeaf9a87d87a3b5cbc859c49d5929a0bdbf43586d70000294c6dae26f","src/yokeable.rs":"1b2e04f620ab7c06c557d23c44b7ebb67736ae239c44277f4fbefbacc011e549","src/zero_from.rs":"c863d016c1e73bbac25f189c78c544ae65649d20fc9412f385a023d30c9a16f5"},"package":"1fe1d55ca72c32d573bfbd5cb2f0ca65a497854c44762957a6d3da96041a5184"} \ No newline at end of file
+{"files":{"Cargo.toml":"73b21b61d53b8b31994e0a5f9509aa0d26212a28bcf2ac1606deb83c6e975197","LICENSE":"4ad7541d66a407234e2c84902124cef325c29f3e966353efdb800bedb8b8da21","README.md":"30321954bbc84770e2b50e8cc6da2a9e98f97698cbf1fe829747d4f3c6f6f791","src/either.rs":"028bb043392d1f3d608589d65d997a241b5ba7bb5114cf023179a38bf1c1cf2b","src/erased.rs":"a97a1be3436314e34903a59330a8f61f96f5543c73d96853c09c32392dd09898","src/lib.rs":"9168593ad938bb19c867a3fde27911003b108ae40efed87741bd5d036c914a39","src/macro_impls.rs":"f81ac8af77ac3641bfee116d6295f5f756f92d4b3b6c7d43a228cd313174d355","src/trait_hack.rs":"d3a8b93e0a984febabd288af558d25e5a93019e2bf9209bc023762c9182aa7fc","src/yoke.rs":"91f8f8b5ea15b42d79c0790eaf1e08607a42bd92e9773db05281e3e1eb9dbb82","src/yokeable.rs":"1b2e04f620ab7c06c557d23c44b7ebb67736ae239c44277f4fbefbacc011e549","src/zero_from.rs":"71d97f87e003db0eb0e97064509bdf9355622ccd655549f926b6a0d9119db3ee"},"package":"222180af14a6b54ef2c33493c1eff77ae95a3687a21b243e752624006fb8f26e"} \ No newline at end of file
diff --git a/vendor/yoke/Cargo.toml b/vendor/yoke/Cargo.toml
index d8629127d..a20e850b6 100644
--- a/vendor/yoke/Cargo.toml
+++ b/vendor/yoke/Cargo.toml
@@ -12,7 +12,7 @@
[package]
edition = "2018"
name = "yoke"
-version = "0.6.2"
+version = "0.7.0"
authors = ["Manish Goregaokar <manishsmail@gmail.com>"]
include = [
"src/**/*",
@@ -40,6 +40,9 @@ license = "Unicode-DFS-2016"
repository = "https://github.com/unicode-org/icu4x"
resolver = "2"
+[package.metadata.workspaces]
+independent = true
+
[package.metadata.docs.rs]
all-features = true
@@ -53,11 +56,11 @@ version = "1.2.0"
default-features = false
[dependencies.yoke-derive]
-version = "0.6.0"
+version = "0.7.0"
optional = true
[dependencies.zerofrom]
-version = "0.1.0"
+version = "0.1.1"
optional = true
default-features = false
@@ -70,7 +73,7 @@ version = "1.0.125"
[features]
alloc = [
"stable_deref_trait/alloc",
- "serde/alloc",
+ "serde?/alloc",
"zerofrom/alloc",
]
default = [
@@ -78,6 +81,6 @@ default = [
"zerofrom",
]
derive = [
- "yoke-derive",
+ "dep:yoke-derive",
"zerofrom/derive",
]
diff --git a/vendor/yoke/src/erased.rs b/vendor/yoke/src/erased.rs
index c314d5186..bc4de9791 100644
--- a/vendor/yoke/src/erased.rs
+++ b/vendor/yoke/src/erased.rs
@@ -7,7 +7,7 @@
//! See the docs of [`Yoke::erase_rc_cart()`](crate::Yoke::erase_rc_cart)
//! and [`Yoke::erase_box_cart()`](crate::Yoke::erase_box_cart) for more info.
//!
-//! Available with the `"alloc"` feature enabled.
+//! Available with the `"alloc"` Cargo feature enabled.
use alloc::boxed::Box;
use alloc::rc::Rc;
@@ -25,17 +25,17 @@ impl<T: 'static> ErasedDestructor for T {}
///
/// See the docs of [`Yoke::erase_arc_cart()`](crate::Yoke::erase_rc_cart) for more info.
///
-/// Available with the `"alloc"` feature enabled.
+/// Available with the `"alloc"` Cargo feature enabled.
pub type ErasedArcCart = Arc<dyn ErasedDestructor + Send + Sync>;
/// A type-erased Cart that has `Rc` semantics
///
/// See the docs of [`Yoke::erase_rc_cart()`](crate::Yoke::erase_rc_cart) for more info.
///
-/// Available with the `"alloc"` feature enabled.
+/// Available with the `"alloc"` Cargo feature enabled.
pub type ErasedRcCart = Rc<dyn ErasedDestructor>;
/// A type-erased Cart that has `Box` semantics
///
/// See the docs of [`Yoke::erase_box_cart()`](crate::Yoke::erase_box_cart) for more info.
///
-/// Available with the `"alloc"` feature enabled.
+/// Available with the `"alloc"` Cargo feature enabled.
pub type ErasedBoxCart = Box<dyn ErasedDestructor>;
diff --git a/vendor/yoke/src/is_covariant.rs b/vendor/yoke/src/is_covariant.rs
deleted file mode 100644
index 75d123c84..000000000
--- a/vendor/yoke/src/is_covariant.rs
+++ /dev/null
@@ -1,142 +0,0 @@
-// This file is part of ICU4X. For terms of use, please see the file
-// called LICENSE at the top level of the ICU4X source tree
-// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
-
-#[cfg(feature = "alloc")]
-use alloc::{
- borrow::{Cow, ToOwned},
- boxed::Box,
- rc::Rc,
- string::String,
-};
-
-/// A type implementing `IsCovariant<'a>` is covariant with respect to lifetime `'a`.
-///
-/// Lifetime parameters that are safely cast in [`Yokeable`] are also valid for `IsCovariant`.
-///
-/// `IsCovariant` exists primarily to serve in trait bounds. The primary use case is to safely
-/// perform lifetime casting on trait objects (`dyn Trait`). This enables a type-erased [`Yoke`]
-/// consisting of only trait objects. See the examples.
-///
-/// `IsCovariant` is auto-implemented in [`#[derive(Yokeable)]`](macro@crate::Yokeable).
-///
-/// # Safety
-///
-/// This trait is safe to implement on types with a _covariant_ lifetime parameter. This will
-/// occur when the lifetime parameter is used within references, but not in the arguments of
-/// function pointers or in mutable positions (either in `&mut` or via interior mutability).
-///
-/// If a struct has multiple lifetime parameters, only the one used in `IsCovariant<'a>` needs to
-/// be covariant.
-///
-/// # Examples
-///
-/// Implementing on a simple struct with a single covariant lifetime:
-///
-/// ```
-/// # use yoke::*;
-/// struct MyStruct<'a>(&'a str);
-///
-/// // This is safe because 'a is covariant
-/// unsafe impl<'a> IsCovariant<'a> for MyStruct<'a> {}
-/// ```
-///
-/// By constraining the trait `ExampleTrait<'a>` on `IsCovariant<'a>`, we can safely implement
-/// [`Yokeable`] and [`ZeroFrom`] on its trait object:
-///
-/// ```
-/// # use yoke::*;
-/// # use zerofrom::*;
-/// # use core::mem;
-/// trait ExampleTrait<'a>: IsCovariant<'a> {
-/// fn get_message(&self) -> &'a str;
-/// }
-///
-/// // This wrapper is required because of the blanket Yokeable impl on &'static T
-/// pub struct ExampleTraitDynRef<'a>(pub &'a dyn ExampleTrait<'a>);
-///
-/// // The following impl is safe because the trait object requires IsCovariant.
-/// unsafe impl<'a> Yokeable<'a> for ExampleTraitDynRef<'static> {
-/// type Output = ExampleTraitDynRef<'a>;
-/// fn transform(&'a self) -> &'a Self::Output {
-/// unsafe { mem::transmute(self) }
-/// }
-///
-/// fn transform_owned(self) -> Self::Output {
-/// unsafe { mem::transmute(self) }
-/// }
-///
-/// unsafe fn make(from: Self::Output) -> Self {
-/// unsafe { mem::transmute(from) }
-/// }
-///
-/// fn transform_mut<F>(&'a mut self, f: F)
-/// where
-/// F: 'static + FnOnce(&'a mut Self::Output),
-/// {
-/// unsafe { f(mem::transmute::<&mut Self, &mut Self::Output>(self)) }
-/// }
-/// }
-///
-/// impl<'zf, 'a> ZeroFrom<'zf, dyn ExampleTrait<'a> + 'a> for ExampleTraitDynRef<'zf> {
-/// fn zero_from(this: &'zf (dyn ExampleTrait<'a> + 'a)) -> ExampleTraitDynRef<'zf> {
-/// // This is safe because the trait object requires IsCovariant.
-/// ExampleTraitDynRef(unsafe { core::mem::transmute(this) })
-/// }
-/// }
-///
-/// // Implement ExampleTrait on the struct from the previous example
-/// # struct MyStruct<'a>(&'a str);
-/// # unsafe impl<'a> IsCovariant<'a> for MyStruct<'a> {}
-/// impl<'a> ExampleTrait<'a> for MyStruct<'a> {
-/// fn get_message(&self) -> &'a str {
-/// self.0
-/// }
-/// }
-///
-/// // Example usage: a Yoke of a trait object
-/// let s = "Hello World".to_string();
-/// let yoke: Yoke<ExampleTraitDynRef<'static>, Box<dyn ExampleTrait>> =
-/// Yoke::attach_to_zero_copy_cart(Box::new(MyStruct(&s)));
-///
-/// assert_eq!(yoke.get().0.get_message(), "Hello World");
-/// ```
-///
-/// [`Yoke`]: crate::Yoke
-/// [`Yokeable`]: crate::Yokeable
-/// [`ZeroFrom`]: crate::ZeroFrom
-pub unsafe trait IsCovariant<'a>: 'a {}
-
-// IsCovariant is implemented on the standard library Copy types in macro_impls.rs
-
-// The following impls are safe because there is only one lifetime, 'a, and 'a is covariant
-
-unsafe impl<'a> IsCovariant<'a> for () {}
-
-unsafe impl<'a> IsCovariant<'a> for str {}
-#[cfg(feature = "alloc")]
-unsafe impl<'a> IsCovariant<'a> for String {}
-
-unsafe impl<'a, T: IsCovariant<'a>> IsCovariant<'a> for Option<T> {}
-
-unsafe impl<'a, T1: IsCovariant<'a>, T2: IsCovariant<'a>> IsCovariant<'a> for (T1, T2) {}
-
-unsafe impl<'a, T: IsCovariant<'a>> IsCovariant<'a> for [T] {}
-
-unsafe impl<'a, T: IsCovariant<'a>, const N: usize> IsCovariant<'a> for [T; N] {}
-
-#[cfg(feature = "alloc")]
-unsafe impl<'a, T: IsCovariant<'a> + ?Sized> IsCovariant<'a> for Box<T> {}
-
-#[cfg(feature = "alloc")]
-unsafe impl<'a, T: IsCovariant<'a> + ?Sized> IsCovariant<'a> for Rc<T> {}
-
-// This is safe because T has a covariant lifetime, and Cow's lifetime is also covariant
-#[cfg(feature = "alloc")]
-unsafe impl<'a, T: IsCovariant<'a> + ToOwned + ?Sized> IsCovariant<'a> for Cow<'a, T> where
- <T as ToOwned>::Owned: Sized
-{
-}
-
-// This is safe because T has a covariant lifetime, and the reference lifetime is also covariant
-unsafe impl<'a, T: IsCovariant<'a> + ?Sized> IsCovariant<'a> for &'a T {}
diff --git a/vendor/yoke/src/lib.rs b/vendor/yoke/src/lib.rs
index 666e179e9..1524c067c 100644
--- a/vendor/yoke/src/lib.rs
+++ b/vendor/yoke/src/lib.rs
@@ -48,7 +48,6 @@ extern crate alloc;
pub mod either;
#[cfg(feature = "alloc")]
pub mod erased;
-mod is_covariant;
mod macro_impls;
pub mod trait_hack;
mod yoke;
@@ -59,7 +58,6 @@ mod zero_from;
#[cfg(feature = "derive")]
pub use yoke_derive::Yokeable;
-pub use crate::is_covariant::IsCovariant;
pub use crate::yoke::{CloneableCart, Yoke};
pub use crate::yokeable::Yokeable;
diff --git a/vendor/yoke/src/macro_impls.rs b/vendor/yoke/src/macro_impls.rs
index 664816818..060061b20 100644
--- a/vendor/yoke/src/macro_impls.rs
+++ b/vendor/yoke/src/macro_impls.rs
@@ -6,7 +6,7 @@
// than using pointer casts
#![allow(clippy::transmute_ptr_to_ptr)]
-use crate::{IsCovariant, Yokeable};
+use crate::Yokeable;
use core::{mem, ptr};
macro_rules! copy_yoke_impl {
@@ -38,7 +38,6 @@ macro_rules! impl_copy_type {
type Output = Self;
copy_yoke_impl!();
}
- unsafe impl<'a> IsCovariant<'a> for $ty {}
};
}
diff --git a/vendor/yoke/src/yoke.rs b/vendor/yoke/src/yoke.rs
index c3d8c37d9..7468b4d99 100644
--- a/vendor/yoke/src/yoke.rs
+++ b/vendor/yoke/src/yoke.rs
@@ -6,7 +6,6 @@ use crate::either::EitherCart;
#[cfg(feature = "alloc")]
use crate::erased::{ErasedArcCart, ErasedBoxCart, ErasedRcCart};
use crate::trait_hack::YokeTraitHack;
-use crate::IsCovariant;
use crate::Yokeable;
use core::marker::PhantomData;
use core::ops::Deref;
@@ -48,8 +47,7 @@ use alloc::sync::Arc;
/// into another `Yoke` containing a different type that may contain elements of the original yoked
/// value. See the [`Yoke::map_project()`] docs for more details.
///
-/// In general, `C` is a concrete type, but it is also possible for it to be a trait object;
-/// for more information, see [`IsCovariant`].
+/// In general, `C` is a concrete type, but it is also possible for it to be a trait object.
///
/// # Example
///
@@ -83,7 +81,10 @@ pub struct Yoke<Y: for<'a> Yokeable<'a>, C> {
cart: C,
}
-impl<Y: for<'a> Yokeable<'a>, C: StableDeref> Yoke<Y, C> {
+impl<Y: for<'a> Yokeable<'a>, C: StableDeref> Yoke<Y, C>
+where
+ <C as Deref>::Target: 'static,
+{
/// Construct a [`Yoke`] by yokeing an object to a cart in a closure.
///
/// See also [`Yoke::try_attach_to_cart()`] to return a `Result` from the closure.
@@ -116,7 +117,14 @@ impl<Y: for<'a> Yokeable<'a>, C: StableDeref> Yoke<Y, C> {
/// ```
pub fn attach_to_cart<F>(cart: C, f: F) -> Self
where
+ // safety note: This works by enforcing that the *only* place the return value of F
+ // can borrow from is the cart, since `F` must be valid for all lifetimes `'de`
+ //
+ // The <C as Deref>::Target: 'static on the impl is crucial for safety as well
+ //
+ // See safety docs at the bottom of this file for more information
F: for<'de> FnOnce(&'de <C as Deref>::Target) -> <Y as Yokeable<'de>>::Output,
+ <C as Deref>::Target: 'static,
{
let deserialized = f(cart.deref());
Self {
@@ -220,8 +228,10 @@ impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
/// ```
/// use yoke::Yoke;
///
- /// let local_data = "foo".to_string();
- /// let yoke = Yoke::<&'static str, Box<String>>::attach_to_zero_copy_cart(Box::new(local_data));
+ /// let local_data = "foo".to_owned();
+ /// let yoke = Yoke::<&'static str, Box<String>>::attach_to_zero_copy_cart(
+ /// Box::new(local_data),
+ /// );
/// assert_eq!(*yoke.get(), "foo");
///
/// // Get back the cart
@@ -235,9 +245,11 @@ impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
/// use std::borrow::Cow;
/// use yoke::Yoke;
///
- /// let local_data = "foo".to_string();
+ /// let local_data = "foo".to_owned();
/// let mut yoke =
- /// Yoke::<Cow<'static, str>, Box<String>>::attach_to_zero_copy_cart(Box::new(local_data));
+ /// Yoke::<Cow<'static, str>, Box<String>>::attach_to_zero_copy_cart(
+ /// Box::new(local_data),
+ /// );
/// assert_eq!(yoke.get(), "foo");
///
/// // Override data in the cart
@@ -265,6 +277,9 @@ impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
/// - `f()` must not panic
/// - References from the yokeable `Y` should still be valid for the lifetime of the
/// returned cart type `C`.
+ /// - Lifetimes inside C must not be lengthened, even if they are themselves contravariant.
+ /// I.e., if C contains an `fn(&'a u8)`, it cannot be replaced with `fn(&'static u8),
+ /// even though that is typically safe.
///
/// Typically, this means implementing `f` as something which _wraps_ the inner cart type `C`.
/// `Yoke` only really cares about destructors for its carts so it's fine to erase other
@@ -506,12 +521,9 @@ where
}
}
-// This is safe because Y is 'static and C has a covariant lifetime
-unsafe impl<'b, Y: for<'a> Yokeable<'a>, C: IsCovariant<'b>> IsCovariant<'b> for Yoke<Y, C> {}
-
#[test]
fn test_clone() {
- let local_data = "foo".to_string();
+ let local_data = "foo".to_owned();
let y1 = Yoke::<alloc::borrow::Cow<'static, str>, Rc<String>>::attach_to_zero_copy_cart(
Rc::new(local_data),
);
@@ -575,7 +587,9 @@ impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
/// string_2: &'a str,
/// }
///
- /// fn map_project_string_1(bar: Yoke<Bar<'static>, Rc<[u8]>>) -> Yoke<&'static str, Rc<[u8]>> {
+ /// fn map_project_string_1(
+ /// bar: Yoke<Bar<'static>, Rc<[u8]>>,
+ /// ) -> Yoke<&'static str, Rc<[u8]>> {
/// bar.map_project(|bar, _| bar.string_1)
/// }
///
@@ -651,7 +665,9 @@ impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
/// # use yoke::Yoke;
/// # use std::str::{self, Utf8Error};
/// #
- /// fn slice(y: Yoke<&'static [u8], Rc<[u8]>>) -> Result<Yoke<&'static str, Rc<[u8]>>, Utf8Error> {
+ /// fn slice(
+ /// y: Yoke<&'static [u8], Rc<[u8]>>,
+ /// ) -> Result<Yoke<&'static str, Rc<[u8]>>, Utf8Error> {
/// y.try_map_project(move |bytes, _| str::from_utf8(bytes))
/// }
/// ```
@@ -671,7 +687,9 @@ impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
/// string_2: &'a str,
/// }
///
- /// fn map_project_string_1(bar: Yoke<Bar<'static>, Rc<[u8]>>) -> Result<Yoke<&'static str, Rc<[u8]>>, Utf8Error> {
+ /// fn map_project_string_1(
+ /// bar: Yoke<Bar<'static>, Rc<[u8]>>,
+ /// ) -> Result<Yoke<&'static str, Rc<[u8]>>, Utf8Error> {
/// bar.try_map_project(|bar, _| str::from_utf8(bar.bytes_1))
/// }
///
@@ -861,17 +879,19 @@ impl<Y: for<'a> Yokeable<'a>, C: 'static + Sized> Yoke<Y, Rc<C>> {
/// let buffer1: Rc<String> = Rc::new(" foo bar baz ".into());
/// let buffer2: Box<String> = Box::new(" baz quux ".into());
///
- /// let yoke1 = Yoke::<&'static str, _>::attach_to_cart(buffer1, |rc| rc.trim());
+ /// let yoke1 =
+ /// Yoke::<&'static str, _>::attach_to_cart(buffer1, |rc| rc.trim());
/// let yoke2 = Yoke::<&'static str, _>::attach_to_cart(buffer2, |b| b.trim());
///
/// let erased1: Yoke<_, ErasedRcCart> = yoke1.erase_rc_cart();
/// // Wrap the Box in an Rc to make it compatible
- /// let erased2: Yoke<_, ErasedRcCart> = yoke2.wrap_cart_in_rc().erase_rc_cart();
+ /// let erased2: Yoke<_, ErasedRcCart> =
+ /// yoke2.wrap_cart_in_rc().erase_rc_cart();
///
/// // Now erased1 and erased2 have the same type!
/// ```
///
- /// Available with the `"alloc"` feature enabled.
+ /// Available with the `"alloc"` Cargo feature enabled.
pub fn erase_rc_cart(self) -> Yoke<Y, ErasedRcCart> {
unsafe {
// safe because the cart is preserved, just
@@ -905,17 +925,19 @@ impl<Y: for<'a> Yokeable<'a>, C: 'static + Sized + Send + Sync> Yoke<Y, Arc<C>>
/// let buffer1: Arc<String> = Arc::new(" foo bar baz ".into());
/// let buffer2: Box<String> = Box::new(" baz quux ".into());
///
- /// let yoke1 = Yoke::<&'static str, _>::attach_to_cart(buffer1, |arc| arc.trim());
+ /// let yoke1 =
+ /// Yoke::<&'static str, _>::attach_to_cart(buffer1, |arc| arc.trim());
/// let yoke2 = Yoke::<&'static str, _>::attach_to_cart(buffer2, |b| b.trim());
///
/// let erased1: Yoke<_, ErasedArcCart> = yoke1.erase_arc_cart();
/// // Wrap the Box in an Rc to make it compatible
- /// let erased2: Yoke<_, ErasedArcCart> = yoke2.wrap_cart_in_arc().erase_arc_cart();
+ /// let erased2: Yoke<_, ErasedArcCart> =
+ /// yoke2.wrap_cart_in_arc().erase_arc_cart();
///
/// // Now erased1 and erased2 have the same type!
/// ```
///
- /// Available with the `"alloc"` feature enabled.
+ /// Available with the `"alloc"` Cargo feature enabled.
pub fn erase_arc_cart(self) -> Yoke<Y, ErasedArcCart> {
unsafe {
// safe because the cart is preserved, just
@@ -949,17 +971,19 @@ impl<Y: for<'a> Yokeable<'a>, C: 'static + Sized> Yoke<Y, Box<C>> {
/// let buffer1: Rc<String> = Rc::new(" foo bar baz ".into());
/// let buffer2: Box<String> = Box::new(" baz quux ".into());
///
- /// let yoke1 = Yoke::<&'static str, _>::attach_to_cart(buffer1, |rc| rc.trim());
+ /// let yoke1 =
+ /// Yoke::<&'static str, _>::attach_to_cart(buffer1, |rc| rc.trim());
/// let yoke2 = Yoke::<&'static str, _>::attach_to_cart(buffer2, |b| b.trim());
///
/// // Wrap the Rc in an Box to make it compatible
- /// let erased1: Yoke<_, ErasedBoxCart> = yoke1.wrap_cart_in_box().erase_box_cart();
+ /// let erased1: Yoke<_, ErasedBoxCart> =
+ /// yoke1.wrap_cart_in_box().erase_box_cart();
/// let erased2: Yoke<_, ErasedBoxCart> = yoke2.erase_box_cart();
///
/// // Now erased1 and erased2 have the same type!
/// ```
///
- /// Available with the `"alloc"` feature enabled.
+ /// Available with the `"alloc"` Cargo feature enabled.
pub fn erase_box_cart(self) -> Yoke<Y, ErasedBoxCart> {
unsafe {
// safe because the cart is preserved, just
@@ -974,7 +998,7 @@ impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
/// Helper function allowing one to wrap the cart type `C` in a `Box<T>`.
/// Can be paired with [`Yoke::erase_box_cart()`]
///
- /// Available with the `"alloc"` feature enabled.
+ /// Available with the `"alloc"` Cargo feature enabled.
#[inline]
pub fn wrap_cart_in_box(self) -> Yoke<Y, Box<C>> {
unsafe {
@@ -986,7 +1010,7 @@ impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
/// Can be paired with [`Yoke::erase_rc_cart()`], or generally used
/// to make the [`Yoke`] cloneable.
///
- /// Available with the `"alloc"` feature enabled.
+ /// Available with the `"alloc"` Cargo feature enabled.
#[inline]
pub fn wrap_cart_in_rc(self) -> Yoke<Y, Rc<C>> {
unsafe {
@@ -998,7 +1022,7 @@ impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
/// Can be paired with [`Yoke::erase_arc_cart()`], or generally used
/// to make the [`Yoke`] cloneable.
///
- /// Available with the `"alloc"` feature enabled.
+ /// Available with the `"alloc"` Cargo feature enabled.
#[inline]
pub fn wrap_cart_in_arc(self) -> Yoke<Y, Arc<C>> {
unsafe {
@@ -1037,7 +1061,7 @@ impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
}
}
-/// Safety docs for project()
+/// # Safety docs for project()
///
/// (Docs are on a private const to allow the use of compile_fail doctests)
///
@@ -1140,3 +1164,151 @@ impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
/// the output yokeable can _only_ have borrowed data flow in to it from the input. All paths of unsoundness require the
/// unification of an existential and universal lifetime, which isn't possible.
const _: () = ();
+
+/// # Safety docs for attach_to_cart()'s signature
+///
+/// The `attach_to_cart()` family of methods get by by using the following bound:
+///
+/// ```rust,ignore
+/// F: for<'de> FnOnce(&'de <C as Deref>::Target) -> <Y as Yokeable<'de>>::Output,
+/// C::Target: 'static
+/// ```
+///
+/// to enforce that the yoking closure produces a yokeable that is *only* allowed to borrow from the cart.
+/// A way to be sure of this is as follows: imagine if `F` *did* borrow data of lifetime `'a` and stuff it in
+/// its output. Then that lifetime `'a` would have to live at least as long as `'de` *for all `'de`*.
+/// The only lifetime that satisfies that is `'static` (since at least one of the potential `'de`s is `'static`),
+/// and we're fine with that.
+///
+/// ## Implied bounds and variance
+///
+/// The `C::Target: 'static` bound is tricky, however. Let's imagine a situation where we *didn't* have that bound.
+///
+/// One thing to remember is that we are okay with the cart itself borrowing from places,
+/// e.g. `&[u8]` is a valid cart, as is `Box<&[u8]>`. `C` is not `'static`.
+///
+/// (I'm going to use `CT` in prose to refer to `C::Target` here, since almost everything here has to do
+/// with C::Target and not C itself.)
+///
+/// Unfortunately, there's a sneaky additional bound inside `F`. The signature of `F` is *actually*
+///
+/// ```rust,ignore
+/// F: for<'de> where<C::Target: 'de> FnOnce(&'de C::Target) -> <Y as Yokeable<'de>>::Output
+/// ```
+///
+/// using made-up "where clause inside HRTB" syntax to represent a type that can be represented inside the compiler
+/// and type system but not in Rust code. The `CT: 'de` bond comes from the `&'de C::Target`: any time you
+/// write `&'a T`, an implied bound of `T: 'a` materializes and is stored alongside it, since references cannot refer
+/// to data that itself refers to data of shorter lifetimes. If a reference is valid, its referent must be valid for
+/// the duration of the reference's lifetime, so every reference *inside* its referent must also be valid, giving us `T: 'a`.
+/// This kind of constraint is often called a "well formedness" constraint: `&'a T` is not "well formed" without that
+/// bound, and rustc is being helpful by giving it to us for free.
+///
+/// Unfortunately, this messes with our universal quantification. The `for<'de>` is no longer "For all lifetimes `'de`",
+/// it is "for all lifetimes `'de` *where `CT: 'de`*". And if `CT` borrows from somewhere (with lifetime `'ct`), then we get a
+/// `'ct: 'de` bound, and `'de` candidates that live longer than `'ct` won't actually be considered.
+/// The neat little logic at the beginning stops working.
+///
+/// `attach_to_cart()` will instead enforce that the produced yokeable *either* borrows from the cart (fine), or from
+/// data that has a lifetime that is at least `'ct`. Which means that `attach_to_cart()` will allow us to borrow locals
+/// provided they live at least as long as `'ct`.
+///
+/// Is this a problem?
+///
+/// This is totally fine if CT's lifetime is covariant: if C is something like `Box<&'ct [u8]>`, even if our
+/// yoked object borrows from locals outliving `'ct`, our Yoke can't outlive that
+/// lifetime `'ct` anyway (since it's a part of the cart type), so we're fine.
+///
+/// However it's completely broken for contravariant carts (e.g. `Box<fn(&'ct u8)>`). In that case
+/// we still get `'ct: 'de`, and we still end up being able to
+/// borrow from locals that outlive `'ct`. However, our Yoke _can_ outlive
+/// that lifetime, because Yoke shares its variance over `'ct`
+/// with the cart type, and the cart type is contravariant over `'ct`.
+/// So the Yoke can be upcast to having a longer lifetime than `'ct`, and *that* Yoke
+/// can outlive `'ct`.
+///
+/// We fix this by forcing `C::Target: 'static` in `attach_to_cart()`, which would make it work
+/// for fewer types, but would also allow Yoke to continue to be covariant over cart lifetimes if necessary.
+///
+/// An alternate fix would be to not allowing yoke to ever be upcast over lifetimes contained in the cart
+/// by forcing them to be invariant. This is a bit more restrictive and affects *all* `Yoke` users, not just
+/// those using `attach_to_cart()`.
+///
+/// See https://github.com/unicode-org/icu4x/issues/2926
+/// See also https://github.com/rust-lang/rust/issues/106431 for potentially fixing this upstream by
+/// changing how the bound works.
+///
+/// # Tests
+///
+/// Here's a broken `attach_to_cart()` that attempts to borrow from a local:
+///
+/// ```rust,compile_fail
+/// use yoke::{Yoke, Yokeable};
+///
+/// let cart = vec![1, 2, 3, 4].into_boxed_slice();
+/// let local = vec![4, 5, 6, 7];
+/// let yoke: Yoke<&[u8], Box<[u8]>> = Yoke::attach_to_cart(cart, |_| &*local);
+/// ```
+///
+/// Fails as expected.
+///
+/// And here's a working one with a local borrowed cart that does not do any sneaky borrows whilst attaching.
+///
+/// ```rust
+/// use yoke::{Yoke, Yokeable};
+///
+/// let cart = vec![1, 2, 3, 4].into_boxed_slice();
+/// let local = vec![4, 5, 6, 7];
+/// let yoke: Yoke<&[u8], &[u8]> = Yoke::attach_to_cart(&cart, |c| &*c);
+/// ```
+///
+/// Here's an `attach_to_cart()` that attempts to borrow from a longer-lived local due to
+/// the cart being covariant. It fails, but would not if the alternate fix of forcing Yoke to be invariant
+/// were implemented. It is technically a safe operation:
+///
+/// ```rust,compile_fail
+/// use yoke::{Yoke, Yokeable};
+/// // longer lived
+/// let local = vec![4, 5, 6, 7];
+///
+/// let backing = vec![1, 2, 3, 4];
+/// let cart = Box::new(&*backing);
+///
+/// let yoke: Yoke<&[u8], Box<&[u8]>> = Yoke::attach_to_cart(cart, |_| &*local);
+/// println!("{:?}", yoke.get());
+/// ```
+///
+/// Finally, here's an `attach_to_cart()` that attempts to borrow from a longer lived local
+/// in the case of a contravariant lifetime. It does not compile, but in and of itself is not dangerous:
+///
+/// ```rust,compile_fail
+/// use yoke::Yoke;
+///
+/// type Contra<'a> = fn(&'a ());
+///
+/// let local = String::from("Hello World!");
+/// let yoke: Yoke<&'static str, Box<Contra<'_>>> = Yoke::attach_to_cart(Box::new((|_| {}) as _), |_| &local[..]);
+/// println!("{:?}", yoke.get());
+/// ```
+///
+/// It is dangerous if allowed to transform (testcase from #2926)
+///
+/// ```rust,compile_fail
+/// use yoke::Yoke;
+///
+/// type Contra<'a> = fn(&'a ());
+///
+///
+/// let local = String::from("Hello World!");
+/// let yoke: Yoke<&'static str, Box<Contra<'_>>> = Yoke::attach_to_cart(Box::new((|_| {}) as _), |_| &local[..]);
+/// println!("{:?}", yoke.get());
+/// let yoke_longer: Yoke<&'static str, Box<Contra<'static>>> = yoke;
+/// let leaked: &'static Yoke<&'static str, Box<Contra<'static>>> = Box::leak(Box::new(yoke_longer));
+/// let reference: &'static str = leaked.get();
+///
+/// println!("pre-drop: {reference}");
+/// drop(local);
+/// println!("post-drop: {reference}");
+///
+/// ```
+const _: () = ();
diff --git a/vendor/yoke/src/zero_from.rs b/vendor/yoke/src/zero_from.rs
index 679a28d59..d876d9c06 100644
--- a/vendor/yoke/src/zero_from.rs
+++ b/vendor/yoke/src/zero_from.rs
@@ -26,6 +26,7 @@ where
Y: for<'a> Yokeable<'a>,
for<'a> YokeTraitHack<<Y as Yokeable<'a>>::Output>: ZeroFrom<'a, <C as Deref>::Target>,
C: StableDeref + Deref,
+ <C as Deref>::Target: 'static,
{
/// Construct a [`Yoke`]`<Y, C>` from a cart implementing `StableDeref` by zero-copy cloning
/// the cart to `Y` and then yokeing that object to the cart.
@@ -42,7 +43,9 @@ where
/// use std::borrow::Cow;
/// use yoke::Yoke;
///
- /// let yoke = Yoke::<Cow<'static, str>, String>::attach_to_zero_copy_cart("demo".to_string());
+ /// let yoke = Yoke::<Cow<'static, str>, String>::attach_to_zero_copy_cart(
+ /// "demo".to_owned(),
+ /// );
///
/// assert_eq!("demo", yoke.get());
/// ```