wagon_value/
valueable.rs

1use crate::{Value, ValueResult};
2
3/// A trait to allow "extension" of the [`Value`] enum.
4///
5/// Sometimes, the basic types supported by `Value` are not enough and the newtype pattern is required to extend it.
6/// Registering this newtype as `Valueable` means that it supports all common operations associated with a `Value`.
7///
8/// Besides implementing the required methods. Any type that implements [`Valueable`] is required to implement the following traits: 
9/// * [`std::fmt::Debug`]
10/// * [`std::fmt::Display`]
11/// * [`Clone`]
12/// * [`Eq`]
13/// * [`PartialEq`]
14/// * [`PartialOrd`]
15/// * [`std::hash::Hash`]
16/// * [`std::ops::Add`]
17/// * [`std::ops::Sub`]
18/// * [`std::ops::Mul`]
19/// * [`std::ops::Div`]
20/// * [`std::ops::Rem`]
21/// * [`num_traits::Pow<Self>`]
22/// This is required such that we can expect any `Valueable` type to work more or less the same.
23///
24/// Most of the required traits can be automatically derived. You can use [`wagon_macros::ValueOps`] (or it's associated methods) to 
25/// automatically derive implementations for all the operative traits (`Add`, `Sub`, etc).
26pub trait Valueable: 
27    std::fmt::Debug 
28    + std::fmt::Display 
29    + Clone
30    + Eq 
31    + PartialEq 
32    + PartialOrd
33    + std::hash::Hash 
34    + std::ops::Add
35    + std::ops::Sub
36    + std::ops::Mul
37    + std::ops::Div
38    + std::ops::Rem
39    + num_traits::Pow<Self> 
40    {
41    /// Is this value seen as `true` or `false`?
42    ///
43    /// # Errors
44    /// Should return an error if this value can not be converted into a `bool`.
45    fn is_truthy(&self) -> ValueResult<bool, Self>;
46    /// Convert the value to a regular [`i32`].
47    ///
48    /// # Errors
49    /// Should return an error if this value can not be converted into an `i32`.
50    fn to_int(&self) -> ValueResult<i32, Self>;
51    /// Convert the value to a regular [`f32`].
52    ///
53    /// # Errors
54    /// Should return an error if this value can not be converted into an `f32`.
55    fn to_float(&self) -> ValueResult<f32, Self>;
56    /// Get a string representation of the value, as if it were a number. 
57    ///
58    /// # Errors
59    /// Should return an error if this value can not be displayed as a number
60    fn display_numerical(&self) -> ValueResult<String, Self>;
61}
62
63/// A second trait for "extension" of the [`Value`] enum.
64///
65/// This is intended to "extract" the inner value if possible and makes automatic implementation
66/// of [`Valueable`] possible. 
67/// If your type properly wraps [`Value`] (as in, it implements [`ToValue`], [`From<Value<Self>>`] and all the expected operations),
68/// [`Valueable`] is automatically implemented by simply taking the value returned by [`ToValue::to_value`] and using that implementation. 
69/// If you do not desire this behaviour, do not implement [`ToValue`].
70pub trait ToValue<T: Valueable> {
71    /// Return a reference to the [`Value`] that this type encompasses.
72    fn to_value(&self) -> &Value<T>;
73}
74
75impl<T: 
76    ToValue<T> 
77    + From<Value<T>> 
78    + Clone
79    + Eq 
80    + PartialEq 
81    + PartialOrd
82    + std::fmt::Debug 
83    + std::fmt::Display 
84    + std::hash::Hash 
85    + std::ops::Add
86    + std::ops::Sub
87    + std::ops::Mul
88    + std::ops::Div
89    + std::ops::Rem
90    + num_traits::Pow<T>> 
91    Valueable for T {
92    fn is_truthy(&self) -> ValueResult<bool, Self> {
93        Ok(self.to_value().is_truthy()?)
94    }
95
96    fn to_int(&self) -> ValueResult<i32, Self> {
97        Ok(self.to_value().to_int()?)
98    }
99
100    fn to_float(&self) -> ValueResult<f32, Self> {
101        Ok(self.to_value().to_float()?)
102    }
103
104    fn display_numerical(&self) -> ValueResult<String, Self> {
105        Ok(self.to_value().display_numerical()?)
106    }
107}