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