Skip to content

Commit 3176f4d

Browse files
committed
Add yoke crate
1 parent 478c4a9 commit 3176f4d

File tree

6 files changed

+143
-0
lines changed

6 files changed

+143
-0
lines changed

Cargo.lock

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ members = [
2929
"utils/litemap",
3030
"utils/pattern",
3131
"utils/writeable",
32+
"utils/yoke",
3233
"utils/zerovec",
3334
]
3435

utils/yoke/Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "yoke"
3+
version = "0.1.0"
4+
authors = ["Manish Goregaokar <[email protected]>"]
5+
edition = "2018"
6+
7+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8+
9+
[dependencies]

utils/yoke/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
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+
5+
mod yoke;
6+
mod yokeable;
7+
8+
pub use yoke::Yoke;
9+
pub use yokeable::Yokeable;

utils/yoke/src/yoke.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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+
5+
use crate::Yokeable;
6+
use std::rc::Rc;
7+
8+
pub struct Yoke<Y: for<'a> Yokeable<'a>, C> {
9+
// must be the first field for drop order
10+
// this will have a 'static lifetime parameter, that parameter is a lie
11+
yokeable: Y,
12+
cart: C,
13+
}
14+
15+
impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
16+
pub fn new(cart: C, yokeable: Y) -> Self {
17+
Self { yokeable, cart }
18+
}
19+
pub fn get<'a>(&'a self) -> &'a <Y as Yokeable<'a>>::Output {
20+
self.yokeable.transform()
21+
}
22+
23+
pub fn backing_cart(&self) -> &C {
24+
&self.cart
25+
}
26+
27+
pub fn with_mut<'a, F>(&'a mut self, f: F)
28+
where
29+
F: 'static + FnOnce(&'a mut <Y as Yokeable<'a>>::Output),
30+
{
31+
self.yokeable.with_mut(f)
32+
}
33+
}
34+
35+
impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> {
36+
pub fn attach_to_cart<F>(cart: C, f: F) -> Self
37+
where
38+
for<'de> F: FnOnce(&'de C) -> <Y as Yokeable<'de>>::Output,
39+
{
40+
let deserialized = f(&cart);
41+
Self {
42+
yokeable: unsafe { Y::make(deserialized) },
43+
cart,
44+
}
45+
}
46+
}
47+
48+
impl<Y: for<'a> Yokeable<'a>, T: ?Sized> Clone for Yoke<Y, Rc<T>>
49+
where
50+
for<'a> <Y as Yokeable<'a>>::Output: Clone,
51+
{
52+
fn clone(&self) -> Self {
53+
Yoke {
54+
yokeable: unsafe { Y::make(self.get().clone()) },
55+
cart: self.cart.clone(),
56+
}
57+
}
58+
}

utils/yoke/src/yokeable.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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+
5+
use std::borrow::{Cow, ToOwned};
6+
use std::mem;
7+
8+
pub unsafe trait Yokeable<'a>: 'static {
9+
type Output: 'a + Sized; // MUST be `Self` with the lifetime swapped
10+
// used by `SharedData::get()`
11+
fn transform(&'a self) -> &'a Self::Output;
12+
13+
// Used for zero-copy deserialization. Safety constraint: `Self` must be
14+
// destroyed before the data `Self::Output` was deserialized
15+
// from is
16+
unsafe fn make(from: Self::Output) -> Self;
17+
18+
fn with_mut<F>(&'a mut self, f: F)
19+
where
20+
F: 'static + FnOnce(&'a mut Self::Output);
21+
}
22+
23+
unsafe impl<'a, T: 'static + ToOwned + ?Sized> Yokeable<'a> for Cow<'static, T>
24+
where
25+
<T as ToOwned>::Owned: Sized,
26+
{
27+
type Output = Cow<'a, T>;
28+
fn transform(&'a self) -> &'a Cow<'a, T> {
29+
self
30+
}
31+
32+
unsafe fn make(from: Cow<'a, T>) -> Self {
33+
debug_assert!(mem::size_of::<Cow<'a, T>>() == mem::size_of::<Self>());
34+
// i hate this
35+
// unfortunately Rust doesn't think `mem::transmute` is possible since it's not sure the sizes
36+
// are the same
37+
mem::transmute_copy(&from)
38+
}
39+
40+
fn with_mut<F>(&'a mut self, f: F)
41+
where
42+
F: 'static + FnOnce(&'a mut Self::Output),
43+
{
44+
unsafe { f(mem::transmute(self)) }
45+
}
46+
}
47+
48+
struct Foo {
49+
str: String,
50+
cow: Cow<'static, str>,
51+
}
52+
53+
// The following code should NOT compile!!!
54+
//
55+
// fn unsound<'a>(foo: &'a mut Foo) {
56+
// let a: &str = &foo.str;
57+
// foo.cow.with_mut(|cow| *cow = Cow::Borrowed(a));
58+
// }
59+
60+
fn sound<'a>(foo: &'a mut Foo) {
61+
foo.cow.with_mut(move |cow| cow.to_mut().push('a'));
62+
}

0 commit comments

Comments
 (0)