agui_core/reference.rs
1use std::{
2 fmt::Debug,
3 sync::{Arc, Weak},
4};
5
6/// Holds a reference that is either `None`, `Owned`, or `Borrowed`.
7///
8/// It's used to give a single field that can accept `Option` (without additional wrapping),
9/// an owned value, or a reference to an owned value (to prevent unnecessary clones).
10///
11/// # Example
12///
13/// ```
14/// pub struct Button {
15/// // Allows the Button to provide its own default, accept an owned value from a parent
16/// // widget, or a reference to a layout.
17/// pub layout: Ref<Layout>,
18/// }
19/// ```
20pub enum Ref<V>
21where
22 V: ?Sized,
23{
24 /// No value.
25 None,
26
27 /// Owned data.
28 Owned(Arc<V>),
29
30 /// Borrowed data. Unlike Owned, this is not guaranteed to exist, as it only
31 /// holds a weak reference to the Owned value. It should never be expected for the value
32 /// to exist.
33 Borrowed(Weak<V>),
34}
35
36impl<V> Default for Ref<V> {
37 fn default() -> Self {
38 Self::None
39 }
40}
41
42impl<V> Debug for Ref<V>
43where
44 V: Debug,
45{
46 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47 match self {
48 Self::None => write!(f, "None"),
49 Self::Owned(value) => Debug::fmt(&value, f),
50 Self::Borrowed(value) => match value.upgrade() {
51 Some(value) => Debug::fmt(&value, f),
52 None => write!(f, "Gone"),
53 },
54 }
55 }
56}
57
58impl<V> Ref<V> {
59 /// Creates an Owned reference to `value`.
60 #[must_use]
61 pub fn new(value: V) -> Self {
62 Self::Owned(Arc::new(value))
63 }
64
65 /// Returns true if this reference points to a value in memory.
66 ///
67 /// Will always be `true` if the Ref is `Owned`, will always be `None` if the Ref is `None`,
68 /// but if it's `Borrowed`, it will only return `true` if the borrowed value is still in memory.
69 #[must_use]
70 pub fn is_valid(&self) -> bool {
71 match self {
72 Self::None => false,
73 Self::Owned(_) => true,
74 Self::Borrowed(weak) => weak.strong_count() > 0,
75 }
76 }
77
78 /// Attempst to fetch the value that this reference is wrapping.
79 #[must_use]
80 pub fn try_get(&self) -> Option<Arc<V>> {
81 match self {
82 Self::None => None,
83 Self::Owned(value) => Some(Arc::clone(value)),
84 Self::Borrowed(weak) => weak.upgrade(),
85 }
86 }
87
88 /// Fetch the underlying value that this reference is wrapping.
89 ///
90 /// # Panics
91 ///
92 /// Will panic if the value no longer exists, or the reference is empty.
93 #[must_use]
94 pub fn get(&self) -> Arc<V> {
95 match self {
96 Self::None => panic!("layout ref points to nothing"),
97 Self::Owned(value) => Arc::clone(value),
98 Self::Borrowed(weak) => match weak.upgrade() {
99 Some(value) => value,
100 None => panic!("value no longer exists"),
101 },
102 }
103 }
104}
105
106impl<V> Clone for Ref<V> {
107 fn clone(&self) -> Self {
108 match self {
109 Self::None => Self::None,
110 Self::Owned(value) => Self::Borrowed(Arc::downgrade(value)),
111 Self::Borrowed(value) => Self::Borrowed(Weak::clone(value)),
112 }
113 }
114}
115
116impl<T> From<T> for Ref<T> {
117 fn from(val: T) -> Self {
118 Self::Owned(Arc::new(val))
119 }
120}