zng_var/
var_value.rs

1use std::{
2    any::{Any, TypeId},
3    fmt, ops,
4    sync::Arc,
5};
6
7use smallbox::*;
8
9use crate::WeakVar;
10
11/// Small box for [`AnyVarValue`] values.
12pub struct BoxAnyVarValue(SmallBox<dyn AnyVarValue, space::S4>);
13impl ops::Deref for BoxAnyVarValue {
14    type Target = dyn AnyVarValue;
15
16    fn deref(&self) -> &Self::Target {
17        &*self.0
18    }
19}
20impl ops::DerefMut for BoxAnyVarValue {
21    fn deref_mut(&mut self) -> &mut Self::Target {
22        &mut *self.0
23    }
24}
25impl BoxAnyVarValue {
26    /// Box `value`.
27    pub fn new(value: impl AnyVarValue) -> Self {
28        BoxAnyVarValue(smallbox!(value))
29    }
30
31    /// Downcast to value.
32    pub fn downcast<T: VarValue>(self) -> Result<T, Self> {
33        // Can't cast to `SmallBox<dyn Any>` in stable, so need to clone here for now.
34        match self.downcast_ref::<T>() {
35            Some(v) => Ok(v.clone()),
36            None => Err(self),
37        }
38    }
39
40    /// Gets the [`TypeId`] of the boxed value.
41    ///
42    /// Note that if you call [`Any::type_id`] directly on this type you will get the `BoxAnyVarValue` type id, not
43    /// the id of the actual value.
44    pub fn type_id(&self) -> TypeId {
45        (*self.0).type_id()
46    }
47
48    /// Alternate formatter that writes detailed debug info about the box and value type name.
49    ///
50    /// The `std::fmt::Debug` implementation simply redirects to the value debug,
51    /// this wrapper provides more info.
52    pub fn detailed_debug(&self) -> impl fmt::Debug {
53        struct DetailedDebug<'a>(&'a BoxAnyVarValue);
54        impl<'a> fmt::Debug for DetailedDebug<'a> {
55            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56                let mut b = f.debug_struct("BoxAnyVarValue");
57                b.field("value", &*self.0.0);
58                #[cfg(feature = "type_names")]
59                b.field("type_name()", &self.0.0.type_name());
60                #[cfg(not(feature = "type_names"))]
61                b.field("type_id()", &self.0.type_id());
62                b.field("is_heap()", &SmallBox::is_heap(&self.0.0));
63                b.finish()
64            }
65        }
66        DetailedDebug(self)
67    }
68}
69impl Clone for BoxAnyVarValue {
70    fn clone(&self) -> Self {
71        self.0.clone_boxed()
72    }
73}
74impl fmt::Debug for BoxAnyVarValue {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        fmt::Debug::fmt(&*self.0, f)
77    }
78}
79// don't implement PartialEq for BoxAnyVarValue,
80// that would cause it to become a AnyVarValue itself and cause all sort of issues
81
82/// Represents any variable value.
83///
84/// # Trait Alias
85///
86/// This trait is used like a type alias for traits and is
87/// already implemented for all types it can apply to.
88///
89/// See [`VarValue<T>`] for more details.
90pub trait AnyVarValue: fmt::Debug + Any + Send + Sync {
91    /// Clone the value.
92    fn clone_boxed(&self) -> BoxAnyVarValue;
93    /// Gets if `self` and `other` are equal.
94    fn eq_any(&self, other: &dyn AnyVarValue) -> bool;
95    /// Value type name.
96    ///
97    /// Note that this string is not stable and should be used for debug only.
98    #[cfg(feature = "type_names")]
99    fn type_name(&self) -> &'static str;
100
101    /// Swap value with `other` if both are of the same type.
102    fn try_swap(&mut self, other: &mut dyn AnyVarValue) -> bool;
103}
104impl dyn AnyVarValue {
105    /// Returns some reference to the inner value if it is of type `T`, or
106    /// `None` if it isn't.
107    pub fn downcast_ref<T: VarValue>(&self) -> Option<&T> {
108        let any: &dyn Any = self;
109        any.downcast_ref()
110    }
111
112    /// Returns some mutable reference to the inner value if it is of type `T`, or
113    /// `None` if it isn't.
114    pub fn downcast_mut<T: VarValue>(&mut self) -> Option<&mut T> {
115        let any: &mut dyn Any = self;
116        any.downcast_mut()
117    }
118
119    /// Returns `true` if the inner type is the same as `T`.
120    pub fn is<T: VarValue>(&self) -> bool {
121        let any: &dyn Any = self;
122        any.is::<T>()
123    }
124}
125impl PartialEq for dyn AnyVarValue {
126    fn eq(&self, other: &Self) -> bool {
127        self.eq_any(other)
128    }
129}
130impl<T> AnyVarValue for T
131where
132    T: fmt::Debug + PartialEq + Clone + Any + Send + Sync,
133{
134    fn clone_boxed(&self) -> BoxAnyVarValue {
135        BoxAnyVarValue::new(self.clone())
136    }
137
138    fn eq_any(&self, other: &dyn AnyVarValue) -> bool {
139        match other.downcast_ref::<T>() {
140            Some(o) => self == o,
141            None => false,
142        }
143    }
144
145    #[cfg(feature = "type_names")]
146    fn type_name(&self) -> &'static str {
147        std::any::type_name::<T>()
148    }
149
150    fn try_swap(&mut self, other: &mut dyn AnyVarValue) -> bool {
151        if let Some(other) = other.downcast_mut::<T>() {
152            std::mem::swap(self, other);
153            return true;
154        }
155        false
156    }
157}
158
159/// Represents a type that can be a [`Var<T>`] value.
160///
161/// # Trait Alias
162///
163/// This trait is used like a type alias for traits and is
164/// already implemented for all types it can apply to.
165///
166/// # Implementing
167///
168/// Types need to be `Debug + Clone + PartialEq + Send + Sync + Any` to auto-implement this trait,
169/// if you want to place an external type in a variable and it does not implement all the traits
170/// you may need to declare a *newtype* wrapper.
171///
172/// If the external type is at least `Debug + Send + Sync + Any` you can use the [`ArcEq<T>`] wrapper
173/// to quickly implement `Clone + PartialEq`, this is particularly useful for error types in [`ResponseVar<Result<_, E>>`].
174///
175/// If you want to use another variable as value use the [`VarEq<T>`] wrapper to use [`Var::var_eq`] as `PartialEq`.
176/// Vars are not allowed to be values directly as that causes type inference issues.
177///
178/// [`Var<T>`]: crate::Var
179/// [`ResponseVar<Result<_, E>>`]: crate::ResponseVar
180/// [`Var::var_eq`]: crate::Var::var_eq
181pub trait VarValue: AnyVarValue + Clone + PartialEq {}
182impl<T: AnyVarValue + Clone + PartialEq> VarValue for T {}
183
184/// An [`Arc`] value that implements equality by pointer comparison.
185///
186/// This type allows external types that are only `Debug + Send + Sync` to become
187/// a full [`VarValue`] to be allowed as a variable value.
188pub struct ArcEq<T: fmt::Debug + Send + Sync>(pub Arc<T>);
189impl<T: fmt::Debug + Send + Sync> ArcEq<T> {
190    /// Create a new [`WeakEq<T>`] pointer.
191    pub fn downgrade(this: &Self) -> WeakEq<T> {
192        WeakEq(Arc::downgrade(&this.0))
193    }
194}
195impl<T: fmt::Debug + Send + Sync> ops::Deref for ArcEq<T> {
196    type Target = Arc<T>;
197
198    fn deref(&self) -> &Self::Target {
199        &self.0
200    }
201}
202impl<T: fmt::Debug + Send + Sync> ArcEq<T> {
203    /// Constructs a new `ArcEq<T>`.
204    pub fn new(value: T) -> Self {
205        Self(Arc::new(value))
206    }
207}
208impl<T: fmt::Debug + Send + Sync> PartialEq for ArcEq<T> {
209    fn eq(&self, other: &Self) -> bool {
210        Arc::ptr_eq(&self.0, &other.0)
211    }
212}
213impl<T: fmt::Debug + Send + Sync> Eq for ArcEq<T> {}
214impl<T: fmt::Debug + Send + Sync> Clone for ArcEq<T> {
215    fn clone(&self) -> Self {
216        Self(Arc::clone(&self.0))
217    }
218}
219impl<T: fmt::Debug + Send + Sync> fmt::Debug for ArcEq<T> {
220    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221        fmt::Debug::fmt(&*self.0, f)
222    }
223}
224
225/// An [`std::sync::Weak`] value that implements equality by pointer comparison.
226///
227/// This type allows external types that are only `Send + Sync` to become
228/// a full [`VarValue`] to be allowed as a variable value.
229pub struct WeakEq<T: Send + Sync>(pub std::sync::Weak<T>);
230impl<T: fmt::Debug + Send + Sync> WeakEq<T> {
231    /// Attempt to upgrade to [`ArcEq<T>`].
232    pub fn upgrade(&self) -> Option<ArcEq<T>> {
233        self.0.upgrade().map(ArcEq)
234    }
235}
236impl<T: Send + Sync> WeakEq<T> {
237    /// New without alloc.
238    pub const fn new() -> Self {
239        Self(std::sync::Weak::new())
240    }
241}
242impl<T: Send + Sync> Default for WeakEq<T> {
243    fn default() -> Self {
244        Self(Default::default())
245    }
246}
247impl<T: Send + Sync> ops::Deref for WeakEq<T> {
248    type Target = std::sync::Weak<T>;
249
250    fn deref(&self) -> &Self::Target {
251        &self.0
252    }
253}
254impl<T: Send + Sync> PartialEq for WeakEq<T> {
255    fn eq(&self, other: &Self) -> bool {
256        std::sync::Weak::ptr_eq(&self.0, &other.0)
257    }
258}
259impl<T: Send + Sync> Eq for WeakEq<T> {}
260impl<T: Send + Sync> Clone for WeakEq<T> {
261    fn clone(&self) -> Self {
262        Self(std::sync::Weak::clone(&self.0))
263    }
264}
265impl<T: Send + Sync> fmt::Debug for WeakEq<T> {
266    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
267        fmt::Debug::fmt(&self.0, f)
268    }
269}
270
271/// Represents a [`Var<T>`] as a value inside another variable.
272///
273/// Variable values must implement `PartialEq + Debug + Clone + Send + Sync + Any`. Variable types
274/// implement all of those except `PartialEq`, this type wraps a variable and adds equality using [`Var::var_eq`].
275///
276/// Variables cannot be be values directly because that breaks the [`IntoVar<T>`] blanket implementation for value types,
277/// as variables also implement `IntoVar<T>`. This could be solved with the *default impl* Rust feature, but it is not yet stable.
278/// This type is a workaround that limitation, it derefs to the wrapped var so it should require minimal refactoring as a drop-in replacement
279/// for `Var<T>` in struct fields.
280///
281/// [`Var<T>`]: crate::Var
282/// [`Var::var_eq`]: crate::Var::var_eq
283/// [`IntoVar<T>`]: crate::IntoVar
284#[derive(Clone)]
285pub struct VarEq<T: VarValue>(pub crate::Var<T>);
286impl<T: VarValue> ops::Deref for VarEq<T> {
287    type Target = crate::Var<T>;
288
289    fn deref(&self) -> &Self::Target {
290        &self.0
291    }
292}
293impl<T: VarValue> fmt::Debug for VarEq<T> {
294    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
295        fmt::Debug::fmt(&self.0, f)
296    }
297}
298impl<T: VarValue> PartialEq for VarEq<T> {
299    fn eq(&self, other: &Self) -> bool {
300        self.0.var_eq(&other.0)
301    }
302}
303impl<T: VarValue> VarEq<T> {
304    /// Create a weak reference to this variable.
305    pub fn downgrade(&self) -> WeakVarEq<T> {
306        WeakVarEq(self.0.downgrade())
307    }
308}
309
310/// Represents a [`WeakVar<T>`] as a value inside another variable.
311///
312/// See [`VarEq`] for more details.
313#[derive(Clone)]
314pub struct WeakVarEq<T: VarValue>(pub crate::WeakVar<T>);
315impl<T: VarValue> ops::Deref for WeakVarEq<T> {
316    type Target = WeakVar<T>;
317
318    fn deref(&self) -> &Self::Target {
319        &self.0
320    }
321}
322impl<T: VarValue> fmt::Debug for WeakVarEq<T> {
323    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
324        fmt::Debug::fmt(&self.0, f)
325    }
326}
327impl<T: VarValue> PartialEq for WeakVarEq<T> {
328    fn eq(&self, other: &Self) -> bool {
329        self.0.var_eq(&other.0)
330    }
331}
332impl<T: VarValue> WeakVarEq<T> {
333    /// Attempt to create a strong reference to the variable.
334    pub fn upgrade(&self) -> Option<VarEq<T>> {
335        self.0.upgrade().map(VarEq)
336    }
337}
338
339/// A property value that is not a variable but can be inspected.
340///
341/// # Implementing
342///
343/// The trait is only auto-implemented for `T: Into<T> + VarValue`, unfortunately actual type conversions
344/// must be manually implemented, note that the [`impl_from_and_into_var!`] macro auto-implements this conversion.
345///
346/// [`impl_from_and_into_var!`]: crate::impl_from_and_into_var
347#[diagnostic::on_unimplemented(
348    note = "`IntoValue<T>` is implemented for all `T: VarValue`",
349    note = "you can use `impl_from_and_into_var!` to implement conversions"
350)]
351pub trait IntoValue<T: VarValue>: Into<T> {}
352impl<T: VarValue> IntoValue<T> for T {}