reactive_graph/owner/
arena_item.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use super::{
    arena::{Arena, NodeId},
    LocalStorage, Storage, SyncStorage, OWNER,
};
use crate::traits::{Dispose, IntoInner, IsDisposed};
use send_wrapper::SendWrapper;
use std::{any::Any, hash::Hash, marker::PhantomData};

/// A copyable, stable reference for any value, stored on the arena whose ownership is managed by the
/// reactive ownership tree.
#[derive(Debug)]
pub struct ArenaItem<T, S = SyncStorage> {
    node: NodeId,
    #[allow(clippy::type_complexity)]
    ty: PhantomData<fn() -> (SendWrapper<T>, S)>,
}

impl<T, S> Copy for ArenaItem<T, S> {}

impl<T, S> Clone for ArenaItem<T, S> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<T, S> PartialEq for ArenaItem<T, S> {
    fn eq(&self, other: &Self) -> bool {
        self.node == other.node
    }
}

impl<T, S> Eq for ArenaItem<T, S> {}

impl<T, S> Hash for ArenaItem<T, S> {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.node.hash(state);
    }
}

impl<T, S> ArenaItem<T, S>
where
    T: 'static,
    S: Storage<T>,
{
    /// Stores the given value in the arena allocator.
    #[track_caller]
    pub fn new_with_storage(value: T) -> Self {
        let node = {
            Arena::with_mut(|arena| {
                arena.insert(
                    Box::new(S::wrap(value)) as Box<dyn Any + Send + Sync>
                )
            })
        };
        OWNER.with(|o| {
            if let Some(owner) = &*o.borrow() {
                owner.register(node);
            }
        });

        Self {
            node,
            ty: PhantomData,
        }
    }
}

impl<T, S> Default for ArenaItem<T, S>
where
    T: Default + 'static,
    S: Storage<T>,
{
    #[track_caller] // Default trait is not annotated with #[track_caller]
    fn default() -> Self {
        Self::new_with_storage(Default::default())
    }
}

impl<T> ArenaItem<T>
where
    T: Send + Sync + 'static,
{
    /// Stores the given value in the arena allocator.
    #[track_caller]
    pub fn new(value: T) -> Self {
        ArenaItem::new_with_storage(value)
    }
}

impl<T> ArenaItem<T, LocalStorage>
where
    T: 'static,
{
    /// Stores the given value in the arena allocator.
    #[track_caller]
    pub fn new_local(value: T) -> Self {
        ArenaItem::new_with_storage(value)
    }
}

impl<T, S: Storage<T>> ArenaItem<T, S> {
    /// Applies a function to a reference to the stored value and returns the result, or `None` if it has already been disposed.
    #[track_caller]
    pub fn try_with_value<U>(&self, fun: impl FnOnce(&T) -> U) -> Option<U> {
        S::try_with(self.node, fun)
    }

    /// Applies a function to a mutable reference to the stored value and returns the result, or `None` if it has already been disposed.
    #[track_caller]
    pub fn try_update_value<U>(
        &self,
        fun: impl FnOnce(&mut T) -> U,
    ) -> Option<U> {
        S::try_with_mut(self.node, fun)
    }
}

impl<T: Clone, S: Storage<T>> ArenaItem<T, S> {
    /// Returns a clone of the stored value, or `None` if it has already been disposed.
    #[track_caller]
    pub fn try_get_value(&self) -> Option<T> {
        S::try_with(self.node, Clone::clone)
    }
}

impl<T, S> IsDisposed for ArenaItem<T, S> {
    fn is_disposed(&self) -> bool {
        Arena::with(|arena| !arena.contains_key(self.node))
    }
}

impl<T, S> Dispose for ArenaItem<T, S> {
    fn dispose(self) {
        Arena::with_mut(|arena| arena.remove(self.node));
    }
}

impl<T, S: Storage<T>> IntoInner for ArenaItem<T, S> {
    type Value = T;

    #[inline(always)]
    fn into_inner(self) -> Option<Self::Value> {
        S::take(self.node)
    }
}