@@ -1,163 +0,0 @@
1−use crate::{Node, Render};
2−use bumpalo::Bump;
3−use std::cell::RefCell;
4−use std::mem;
5−use std::ops::{Deref, DerefMut};
6−
7−// TODO: This implementation will only cache the rendering (generation of the
8−// virtual DOM) but not the diffing of the cached subtree. We could skip diffing
9−// for cached tree by adding `fn is_cached(&self) -> bool` to `Node` that we can
10−// check during diffing. This comes at the cost of bloating `Node`'s size (since
11−// we don't have any padding to sneak an extra `bool` field into). We should
12−// investigate whether it is worth adding this or not.
13−
14−/// A renderable that supports caching for when rendering is expensive but can
15−/// generate the same DOM tree.
16−#[derive(Debug)]
17−pub struct Cached<R> {
18− inner: R,
19− bump: bumpalo::Bump,
20− // Actually a self-reference into `self.bump`. Safe because we ensure that
21− // whenever we hand out a cached node, we use a lifetime that cannot outlive
22− // its owning `Cached<R>`.
23− cached: RefCell<Option<Node<'static>>>,
24−}
25−
26−impl<R> Cached<R> {
27− /// Construct a new `Cached<R>` of an inner `R`.
28− ///
29− /// # Example
30− ///
31− /// ```
32− /// use bumpalo::Bump;
33− /// use dodrio::{Cached, Node, Render};
34− ///
35− /// pub struct Counter {
36− /// count: u32,
37− /// }
38− ///
39− /// impl Render for Counter {
40− /// fn render<'a, 'bump>(&'a self, bump: &'bump Bump) -> Node<'bump>
41− /// where
42− /// 'a: 'bump
43− /// {
44− /// // ...
45− /// # unimplemented!()
46− /// }
47− /// }
48− ///
49− /// // Create a render-able counter.
50− /// let counter = Counter { count: 0 };
51− ///
52− /// // And cache its rendering!
53− /// let cached_counter = Cached::new(counter);
54− /// ```
55− #[inline]
56− pub fn new(inner: R) -> Cached<R> {
57− let bump = Bump::new();
58− let cached = RefCell::new(None);
59− Cached {
60− inner,
61− bump,
62− cached,
63− }
64− }
65−
66− /// Invalidate the cached rendering.
67− ///
68− /// This method should be called whenever the inner `R` must be re-rendered,
69− /// and the cached `Node` from the last time `R::render` was invoked can no
70− /// longer be re-used.
71− ///
72− /// # Example
73− ///
74− /// The `Cached<Hello>` component must have its cache invalidated whenever
75− /// the `who` string is changed, or else the cached rendering will keep
76− /// displaying greetings to old `who`s.
77− ///
78− /// ```
79− /// use bumpalo::Bump;
80− /// use dodrio::{Cached, Node, Render};
81− ///
82− /// /// A component that renders to "<p>Hello, {who}!</p>"
83− /// pub struct Hello {
84− /// who: String
85− /// }
86− ///
87− /// impl Render for Hello {
88− /// fn render<'a, 'bump>(&'a self, bump: &'bump Bump) -> Node<'bump>
89− /// where
90− /// 'a: 'bump,
91− /// {
92− /// use dodrio::builder::*;
93− /// p(bump)
94− /// .children([text("Hello, "), text(&self.who), text("!")])
95− /// .finish()
96− /// }
97− /// }
98− ///
99− /// /// Whenever a `Cached<Hello>`'s `who` is updated, we need to invalidate the
100− /// /// cache so that we don't keep displaying greetings to old `who`s.
101− /// pub fn set_who(hello: &mut Cached<Hello>, who: String) {
102− /// hello.who = who;
103− /// Cached::invalidate(hello);
104− /// }
105− /// ```
106− #[inline]
107− pub fn invalidate(cached: &mut Self) {
108− *cached.cached.borrow_mut() = None;
109− }
110−
111− /// Convert a `Cached<R>` back into a plain `R`.
112− #[inline]
113− pub fn into_inner(cached: Cached<R>) -> R {
114− cached.inner
115− }
116−}
117−
118−impl<R> Deref for Cached<R> {
119− type Target = R;
120−
121− fn deref(&self) -> &R {
122− &self.inner
123− }
124−}
125−
126−impl<R> DerefMut for Cached<R> {
127− fn deref_mut(&mut self) -> &mut R {
128− &mut self.inner
129− }
130−}
131−
132−unsafe fn extend_node_lifetime<'a>(node: Node<'a>) -> Node<'static> {
133− mem::transmute(node)
134−}
135−
136−impl<R: Render> Render for Cached<R> {
137− fn render<'a, 'bump>(&'a self, _: &'bump Bump) -> Node<'bump>
138− where
139− 'a: 'bump,
140− {
141− let mut cached = self.cached.borrow_mut();
142−
143− if let Some(cached) = cached.as_ref() {
144− // The cached node is actually a self-reference, so it has the `'a`
145− // lifetime.
146− let cached: Node<'a> = cached.clone();
147−
148− // But the `'a` lifetime outlives `'bump`, so we can safely convert
149− // it to the narrower `'bump` lifetime.
150− let cached: Node<'bump> = cached;
151−
152− // Return the cached rendering!
153− return cached;
154− }
155−
156− // We don't have a cached node. Render into our own `Bump`, cache it for
157− // future renders, and return it. Same lifetimes as above.
158− let node: Node<'a> = self.inner.render(&self.bump);
159− *cached = Some(unsafe { extend_node_lifetime(node.clone()) });
160− let node: Node<'bump> = node;
161− node
162− }
163−}