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}