Skip to content

Commit 91432d9

Browse files
committed
Experiment with option memos
U cannot get this to work. It's close but I think it requires lifetime bounds on the HRTB lifetimes e.g. `F: for<'a, 'store: 'a> ...`, which currently isn't possible (seems to have been possible at one point? rust-lang/rust#50555 Could also be just that the syntax didn't result in an error, but had no semantic meaning attached to it.)
1 parent b41cb91 commit 91432d9

File tree

9 files changed

+118
-23
lines changed

9 files changed

+118
-23
lines changed

examples/playground.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![feature(generic_associated_types)]
2+
13
fn main() {
24
use futures::StreamExt;
35

src/memo/cell.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub struct CellMemo<C, S> {
1212
_marker: marker::PhantomData<*const C>,
1313
}
1414

15-
impl<C, S, T> CellMemo<C, S>
15+
impl<C, S, T: 'static> CellMemo<C, S>
1616
where
1717
C: TypeConstructor,
1818
S: for<'a, 'store> Fn(&'a C::Type<'store>, ReadContext<'store>) -> &'a VersionedCell<'store, T>,
@@ -29,14 +29,14 @@ where
2929
}
3030
}
3131

32-
impl<C, S, T> Memo for CellMemo<C, S>
32+
impl<C, S, T: 'static> Memo for CellMemo<C, S>
3333
where
3434
C: TypeConstructor,
3535
S: for<'a, 'store> Fn(&'a C::Type<'store>, ReadContext<'store>) -> &'a VersionedCell<'store, T>
3636
+ Clone,
3737
{
3838
type RootTC = C;
39-
type Value<'store> = VersionedCell<'store, T>;
39+
type Value<'a, 'store: 'a> = &'a VersionedCell<'store, T>;
4040
type ValueResolver = CellResolver<C, S>;
4141

4242
fn store_id(&self) -> usize {
@@ -47,7 +47,7 @@ where
4747
&mut self,
4848
root: &'a C::Type<'store>,
4949
cx: ReadContext<'store>,
50-
) -> Refresh<&'a Self::Value<'store>> {
50+
) -> Refresh<Self::Value<'a, 'store>> {
5151
let cell = (self.select)(root, cx);
5252
let version = cell.version();
5353
let last_version = self.last_version;
@@ -74,19 +74,19 @@ pub struct CellResolver<C, S> {
7474
_marker: marker::PhantomData<*const C>,
7575
}
7676

77-
impl<C, S, T> ValueResolver for CellResolver<C, S>
77+
impl<C, S, T: 'static> ValueResolver for CellResolver<C, S>
7878
where
7979
C: TypeConstructor,
8080
S: for<'a, 'store> Fn(&'a C::Type<'store>, ReadContext<'store>) -> &'a VersionedCell<'store, T>,
8181
{
8282
type RootTC = C;
83-
type Value<'store> = VersionedCell<'store, T>;
83+
type Value<'a, 'store: 'a> = &'a VersionedCell<'store, T>;
8484

8585
fn select<'a, 'store>(
8686
&self,
8787
root: &'a C::Type<'store>,
8888
cx: ReadContext<'store>,
89-
) -> &'a Self::Value<'store> {
89+
) -> Self::Value<'a, 'store> {
9090
(self.lens)(root, cx)
9191
}
9292
}

src/memo/memo.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,26 +33,23 @@ impl<T> Deref for Refresh<T> {
3333
pub trait Memo {
3434
type RootTC: TypeConstructor;
3535

36-
type Value<'store>;
36+
type Value<'a, 'store: 'a>;
3737

38-
type ValueResolver: for<'store> ValueResolver<
39-
RootTC = Self::RootTC,
40-
Value<'store> = Self::Value<'store>,
41-
>;
38+
type ValueResolver: ValueResolver;
4239

4340
fn store_id(&self) -> usize;
4441

4542
fn refresh_unchecked<'a, 'store>(
4643
&mut self,
4744
root: &'a <Self::RootTC as TypeConstructor>::Type<'store>,
4845
cx: ReadContext<'store>,
49-
) -> Refresh<&'a Self::Value<'store>>;
46+
) -> Refresh<Self::Value<'a, 'store>>;
5047

5148
fn refresh<'a, 'store>(
5249
&mut self,
5350
root: &'a <Self::RootTC as TypeConstructor>::Type<'store>,
5451
cx: ReadContext<'store>,
55-
) -> Refresh<&'a Self::Value<'store>> {
52+
) -> Refresh<Self::Value<'a, 'store>> {
5653
if self.store_id() != cx.store_id() {
5754
panic!(
5855
"memo is associated with a different store than the read context that was passed"

src/memo/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,8 @@ pub use self::memo::*;
77
mod node;
88
pub use self::node::*;
99

10+
mod option_cell;
11+
pub use self::option_cell::*;
12+
1013
mod value_resolver;
1114
pub use self::value_resolver::*;

src/memo/node.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ where
4646
+ Clone,
4747
{
4848
type RootTC = C;
49-
type Value<'store> = VersionedCell<'store, N::Type<'store>>;
49+
type Value<'a, 'store: 'a> = &'a VersionedCell<'store, N::Type<'store>>;
5050
type ValueResolver = NodeSelector<N, C, S>;
5151

5252
fn store_id(&self) -> usize {
@@ -57,7 +57,7 @@ where
5757
&mut self,
5858
root: &'a C::Type<'store>,
5959
cx: ReadContext<'store>,
60-
) -> Refresh<&'a Self::Value<'store>> {
60+
) -> Refresh<Self::Value<'a, 'store>> {
6161
let cell = (self.select)(root, cx);
6262
let version = cell.version();
6363
let last_version = self.last_version;
@@ -96,13 +96,13 @@ where
9696
) -> &'a VersionedCell<'store, N::Type<'store>>,
9797
{
9898
type RootTC = C;
99-
type Value<'store> = VersionedCell<'store, N::Type<'store>>;
99+
type Value<'a, 'store: 'a> = &'a VersionedCell<'store, N::Type<'store>>;
100100

101101
fn select<'a, 'store>(
102102
&self,
103103
root: &'a C::Type<'store>,
104104
cx: ReadContext<'store>,
105-
) -> &'a Self::Value<'store> {
105+
) -> Self::Value<'a, 'store> {
106106
(self.lens)(root, cx)
107107
}
108108
}

src/memo/option_cell.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
use std::sync::atomic::AtomicU64;
2+
use std::marker;
3+
use crate::TypeConstructor;
4+
use crate::store::{ReadContext, Store};
5+
use crate::versioned_cell::VersionedCell;
6+
use crate::memo::{Memo, Refresh, ValueResolver};
7+
use std::sync::atomic;
8+
9+
pub struct OptionCellMemo<C, S> {
10+
select: S,
11+
store_id: usize,
12+
last_version: Option<u64>,
13+
_marker: marker::PhantomData<*const C>,
14+
}
15+
16+
impl<C, S, T: 'static> OptionCellMemo<C, S>
17+
where
18+
C: TypeConstructor,
19+
S: for<'a, 'store> Fn(&'a C::Type<'store>, ReadContext<'store>) -> Option<&'a VersionedCell<'store, T>>,
20+
{
21+
pub fn new(store: &Store<C>, select: S) -> Self {
22+
let last_version = store.with(|root, cx| select(root, cx).map(|c| c.version()));
23+
24+
OptionCellMemo {
25+
select,
26+
store_id: store.id(),
27+
last_version,
28+
_marker: marker::PhantomData,
29+
}
30+
}
31+
}
32+
33+
impl<C, S, T: 'static> Memo for OptionCellMemo<C, S>
34+
where
35+
C: TypeConstructor,
36+
S: for<'a, 'store> Fn(&'a C::Type<'store>, ReadContext<'store>) -> Option<&'a VersionedCell<'store, T>>
37+
+ Clone,
38+
{
39+
type RootTC = C;
40+
type Value<'a, 'store: 'a> = Option<&'a VersionedCell<'store, T>>;
41+
type ValueResolver = OptionCellResolver<C, S>;
42+
43+
fn store_id(&self) -> usize {
44+
self.store_id
45+
}
46+
47+
fn refresh_unchecked<'a, 'store>(
48+
&mut self,
49+
root: &'a C::Type<'store>,
50+
cx: ReadContext<'store>,
51+
) -> Refresh<Self::Value<'a, 'store>> {
52+
let cell = (self.select)(root, cx);
53+
let version = cell.map(|c| c.version());
54+
let last_version = self.last_version;
55+
56+
self.last_version = version;
57+
58+
if version == last_version {
59+
Refresh::Unchanged(cell)
60+
} else {
61+
Refresh::Changed(cell)
62+
}
63+
}
64+
65+
fn value_resolver(&self) -> Self::ValueResolver {
66+
OptionCellResolver {
67+
lens: self.select.clone(),
68+
_marker: marker::PhantomData,
69+
}
70+
}
71+
}
72+
73+
pub struct OptionCellResolver<C, S> {
74+
lens: S,
75+
_marker: marker::PhantomData<*const C>,
76+
}
77+
78+
impl<C, S, T: 'static> ValueResolver for OptionCellResolver<C, S>
79+
where
80+
C: TypeConstructor,
81+
S: for<'a, 'store> Fn(&'a C::Type<'store>, ReadContext<'store>) -> Option<&'a VersionedCell<'store, T>>,
82+
{
83+
type RootTC = C;
84+
type Value<'a, 'store: 'a> = Option<&'a VersionedCell<'store, T>>;
85+
86+
fn select<'a, 'store>(
87+
&self,
88+
root: &'a C::Type<'store>,
89+
cx: ReadContext<'store>,
90+
) -> Self::Value<'a, 'store> {
91+
(self.lens)(root, cx)
92+
}
93+
}

src/memo/value_resolver.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ use crate::TypeConstructor;
44
pub trait ValueResolver {
55
type RootTC: TypeConstructor;
66

7-
type Value<'store>;
7+
type Value<'a, 'store: 'a>;
88

99
fn select<'a, 'store>(
1010
&self,
1111
root: &'a <Self::RootTC as TypeConstructor>::Type<'store>,
1212
cx: ReadContext<'store>,
13-
) -> &'a Self::Value<'store>;
13+
) -> Self::Value<'a, 'store>;
1414
}

src/versioned_cell.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ impl fmt::Display for BorrowMutError {
3434
}
3535
}
3636

37-
pub struct VersionedCell<'store, T: ?Sized> {
37+
pub struct VersionedCell<'store, T: 'store + ?Sized> {
3838
// Note: don't need atomics to track the version or borrow flag, as they can only change inside
3939
// an update scope, which guarantees there are never sync issues.
4040
version: UnsafeCell<u64>,

src/watcher.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ where
8282
{
8383
pub fn with<F, O>(&self, f: F) -> O
8484
where
85-
F: for<'store> FnOnce(&R::Value<'store>, ReadContext<'store>) -> O,
85+
F: for<'a, 'store> FnOnce(R::Value<'a, 'store>, ReadContext<'store>) -> O,
8686
{
8787
self.store
8888
.with(|root, cx| f(self.resolver.select(root, cx), cx))
@@ -183,7 +183,7 @@ where
183183
{
184184
pub fn with<F, O>(&self, f: F) -> O
185185
where
186-
F: for<'store> FnOnce((&R0::Value<'store>, &R1::Value<'store>), ReadContext<'store>) -> O,
186+
F: for<'a, 'store> FnOnce((R0::Value<'a, 'store>, R1::Value<'a, 'store>), ReadContext<'store>) -> O,
187187
{
188188
self.store.with(|root, cx| {
189189
let resolver_0 = self.resolver_0.select(root, cx);

0 commit comments

Comments
 (0)