Skip to content

Commit

Permalink
Add yoke crate
Browse files Browse the repository at this point in the history
  • Loading branch information
Manishearth committed May 1, 2021
1 parent 478c4a9 commit 2f12a0c
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ members = [
"utils/litemap",
"utils/pattern",
"utils/writeable",
"utils/yoke",
"utils/zerovec",
]

Expand Down
9 changes: 9 additions & 0 deletions utils/yoke/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "yoke"
version = "0.1.0"
authors = ["Manish Goregaokar <manishsmail@gmail.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
15 changes: 15 additions & 0 deletions utils/yoke/src/cart.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// 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 std::rc::Rc;

pub trait Cart {
fn as_bytes(&self) -> &[u8];
}

impl Cart for Rc<[u8]> {
fn as_bytes(&self) -> &[u8] {
&self
}
}
11 changes: 11 additions & 0 deletions utils/yoke/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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;
43 changes: 43 additions & 0 deletions utils/yoke/src/yoke.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// 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<Y: for<'a> 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<Y: for<'a> Yokeable<'a>, C: Cart> Yoke<Y, C> {
pub fn new(cart: C, yokeable: Y) -> Self {
Self { yokeable, cart }
}
pub fn get<'a>(&'a self) -> &'a <Y as Yokeable<'a>>::Output {
self.yokeable.transform()
}

pub fn backing_cart(&self) -> &C {
&self.cart
}
pub fn attach_to_cart<F>(cart: C, f: F) -> Self
where
for<'de> F: FnOnce(&'de [u8]) -> <Y as Yokeable<'de>>::Output,
{
let bytes = cart.as_bytes();
let deserialized = f(bytes);
Self {
yokeable: unsafe { Y::make(deserialized) },
cart,
}
}

pub fn with_mut<'a, F>(&'a mut self, f: F)
where
F: 'static + FnOnce(&'a mut <Y as Yokeable<'a>>::Output),
{
self.yokeable.with_mut(f)
}
}
58 changes: 58 additions & 0 deletions utils/yoke/src/yokeable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// 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 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;

fn with_mut<F>(&'a mut self, f: F)
where
F: 'static + FnOnce(&'a mut Self::Output);
}

unsafe impl<'a, T: 'static + ToOwned + ?Sized> Yokeable<'a> for Cow<'static, T>
where
<T as ToOwned>::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::<Cow<'a, T>>() == mem::size_of::<Self>());
// i hate this
// unfortunately Rust doesn't think `mem::transmute` is possible since it's not sure the sizes
// are the same
mem::transmute_copy(&from)
}

fn with_mut<F>(&'a mut self, f: F)
where
F: 'static + FnOnce(&'a mut Self::Output),
{
unsafe { f(mem::transmute(self)) }
}
}

// The following code should NOT compile!!!
//
// struct Foo {
// str: String,
// cow: Cow<'static, str>
// }

// fn unsound<'a>(foo: &'a mut Foo) {
// let a: &str = &foo.str;
// foo.cow.with_mut(|cow| *cow = Cow::Borrowed(a));
// }

0 comments on commit 2f12a0c

Please sign in to comment.