From 9724f0d7947ac4c40c14729aee8d70b6a0b7bcf7 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 30 Apr 2021 14:25:04 -0700 Subject: [PATCH] Add yoke crate --- Cargo.lock | 4 ++++ Cargo.toml | 1 + utils/yoke/Cargo.toml | 9 +++++++++ utils/yoke/src/cart.rs | 11 +++++++++++ utils/yoke/src/lib.rs | 11 +++++++++++ utils/yoke/src/yoke.rs | 36 ++++++++++++++++++++++++++++++++++++ utils/yoke/src/yokeable.rs | 29 +++++++++++++++++++++++++++++ 7 files changed, 101 insertions(+) create mode 100644 utils/yoke/Cargo.toml create mode 100644 utils/yoke/src/cart.rs create mode 100644 utils/yoke/src/lib.rs create mode 100644 utils/yoke/src/yoke.rs create mode 100644 utils/yoke/src/yokeable.rs diff --git a/Cargo.lock b/Cargo.lock index 2a00eef0141..a31e1832c7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2441,6 +2441,10 @@ dependencies = [ "icu_benchmark_macros", ] +[[package]] +name = "yoke" +version = "0.1.0" + [[package]] name = "zerovec" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index 539f4985679..50bad3f890d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ members = [ "utils/litemap", "utils/pattern", "utils/writeable", + "utils/yoke", "utils/zerovec", ] diff --git a/utils/yoke/Cargo.toml b/utils/yoke/Cargo.toml new file mode 100644 index 00000000000..9e5c6cd1ea6 --- /dev/null +++ b/utils/yoke/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "yoke" +version = "0.1.0" +authors = ["Manish Goregaokar "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/utils/yoke/src/cart.rs b/utils/yoke/src/cart.rs new file mode 100644 index 00000000000..539f346411c --- /dev/null +++ b/utils/yoke/src/cart.rs @@ -0,0 +1,11 @@ +use std::rc::Rc; + +pub trait Cart { + fn as_bytes(&self) -> &[u8]; +} + +impl Cart for Rc<[u8]> { + fn as_bytes(&self) -> &[u8] { + &self + } +} diff --git a/utils/yoke/src/lib.rs b/utils/yoke/src/lib.rs new file mode 100644 index 00000000000..72e590280c7 --- /dev/null +++ b/utils/yoke/src/lib.rs @@ -0,0 +1,11 @@ +// 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 ). + +mod cart; +mod yoke; +mod yokeable; + +pub use cart::Cart; +pub use yoke::Yoke; +pub use yokeable::Yokeable; diff --git a/utils/yoke/src/yoke.rs b/utils/yoke/src/yoke.rs new file mode 100644 index 00000000000..d0a41bcd26c --- /dev/null +++ b/utils/yoke/src/yoke.rs @@ -0,0 +1,36 @@ +// 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 ). + +use crate::{Cart, Yokeable}; + +pub struct Yoke Yokeable<'a>, C: Cart> { + // must be the first field for drop order + // this will have a 'static lifetime parameter, that parameter is a lie + yokeable: Y, + cart: C, +} + +impl Yokeable<'a>, C: Cart> Yoke { + pub fn new(cart: C, yokeable: Y) -> Self { + Self { yokeable, cart } + } + pub fn get<'a>(&'a self) -> &'a >::Output { + self.yokeable.transform() + } + + pub fn backing_cart(&self) -> &C { + &self.cart + } + pub fn attach_to_cart(cart: C, f: F) -> Self + where + for<'de> F: FnOnce(&'de [u8]) -> >::Output, + { + let bytes = cart.as_bytes(); + let deserialized = f(bytes); + Self { + yokeable: unsafe { Y::make(deserialized) }, + cart, + } + } +} diff --git a/utils/yoke/src/yokeable.rs b/utils/yoke/src/yokeable.rs new file mode 100644 index 00000000000..7f067e2a0f7 --- /dev/null +++ b/utils/yoke/src/yokeable.rs @@ -0,0 +1,29 @@ +use std::borrow::{Cow, ToOwned}; +use std::mem; + +pub unsafe trait Yokeable<'a>: 'static { + type Output: 'a + Sized; // MUST be `Self` with the lifetime swapped + // used by `SharedData::get()` + fn transform(&'a self) -> &'a Self::Output; + + // Used for zero-copy deserialization. Safety constraint: `Self` must be + // destroyed before the data `Self::Output` was deserialized + // from is + unsafe fn make(from: Self::Output) -> Self; +} + +unsafe impl<'a, T: 'static + ToOwned + ?Sized> Yokeable<'a> for Cow<'static, T> +where + ::Owned: Sized, +{ + type Output = Cow<'a, T>; + fn transform(&'a self) -> &'a Cow<'a, T> { + self + } + + unsafe fn make(from: Cow<'a, T>) -> Self { + debug_assert!(mem::size_of::>() == mem::size_of::()); + // i hate this + mem::transmute_copy(&from) + } +}