table/value/
mod.rs

1// Copyright (C) 2018  Project Tsukurou!
2//
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License
14// along with this program.  If not, see <https://www.gnu.org/licenses/>.
15
16//! Implementation of the `Value` type and its default conversions.
17
18mod serde;
19
20pub use self::serde::{to_value, from_value};
21
22use table::Table;
23
24/// The types of values that can be stored by tables.
25///
26/// Because most file formats don't care about integer size or floating point
27/// precision, those details have aslo been omitted in implementation here.
28///
29/// # Examples
30/// 
31/// TODO
32#[derive(Debug, Clone, PartialEq)]
33pub enum Value {
34
35    /// The lack of a meaningful value; always gets parsed as `None`.
36    Null,
37
38    /// A boolean primitive, true or false.
39    ///
40    /// Can be parsed using `FromValue` and `FromValueMut` with the following
41    /// types:
42    ///
43    /// - `bool` - Direct copy
44    /// - `String` - Formatted with `Display`
45    Boolean(bool),
46
47    /// A signed 64-bit integer type.
48    ///
49    /// Can be parsed using `FromValue` and `FromValueMut` with the following
50    /// types:
51    ///
52    /// - `i64` - Direct copy
53    /// - Other integer types - Casted (will fail if out of range).
54    /// - `f64`, `f32` - Casted
55    /// - `bool` - Only false when zero.
56    /// - `String` - Formatted with `Display`.
57    Integer(i64),
58
59    /// A floating-point numeric type with 64-bit precision.
60    ///
61    /// Can be parsed using `FromValue` and `FromValueMut` with the following
62    /// types:
63    ///
64    /// - `f64` - Direct copy
65    /// - `f32` - Casted, with truncated precison.
66    /// - `String` - Formatted with `Display`.
67    Number(f64),
68
69    /// A string of text.
70    /// 
71    /// Can be parsed using `FromValue` and `FromValueMut` with the following
72    /// types:
73    ///
74    /// - `&String`, `&mut String` - Direct reference
75    /// - `String` - Cloned
76    /// - Integers, floating point, boolean - will attempt to parse with `FromStr`
77    Text(String),
78
79    /// An ordered list of values that may or may not be the same type.
80    ///
81    /// Can be parsed using `FromValue` and `FromValueMut` with the following
82    /// types:
83    ///
84    /// - `&Vec<Value>`, `&mut Vec<Value>` - Direct reference
85    List(Vec<Value>),
86
87    /// A nested table of named values.
88    /// 
89    /// Can be parsed using `FromValue` and `FromValueMut` with the following
90    /// types:
91    ///
92    /// - `&Table`, `&mut Table` - Direct reference
93    Table(Table),
94}
95
96/// Attempt to unwrap or parse `Self` from a referenced `Value`.
97pub trait FromValue<'a>: Sized {
98    /// Attempts to perform the conversion, returning `None` if the given value
99    /// can not be used to produce `Self`.
100    fn from_value(value: &'a Value) -> Option<Self>;
101}
102
103/// Attempt to unwrap or parse `Self` from a mutably referenced `Value`.
104pub trait FromValueMut<'a>: Sized {
105    /// Attempts to perform the conversion, returning `None` if the given value
106    /// can not be used to produce `Self`.
107    fn from_value_mut(value: &'a mut Value) -> Option<Self>;
108}
109
110impl <'a, T> FromValue<'a> for T
111where
112    T: From<&'a Value>,
113{
114    fn from_value(value: &'a Value) -> Option<T> {
115        Some(T::from(value))
116    }
117}
118
119impl<'a, T> FromValueMut<'a> for T
120where
121    T: FromValue<'a>,
122{
123    fn from_value_mut(value: &'a mut Value) -> Option<T> {
124        T::from_value(value)
125    }
126}
127
128impl From<bool> for Value {
129    fn from(x: bool) -> Value {
130        Value::Boolean(x)
131    }
132}
133
134impl<'a> FromValue<'a> for bool {
135    fn from_value(value: &'a Value) -> Option<bool> {
136        match value {
137            Value::Boolean(x) => Some(*x),
138            Value::Integer(x) => Some(*x != 0),
139            Value::Text(x) => x.parse().ok(),
140            _ => None,
141        }
142    }
143}
144
145impl From<i64> for Value {
146    fn from(x: i64) -> Value {
147        Value::Integer(x)
148    }
149}
150
151impl<'a> FromValue<'a> for i64 {
152    fn from_value(value: &'a Value) -> Option<i64> {
153        match value {
154            Value::Integer(x) => Some(*x),
155            Value::Number(x) => Some(*x as i64),
156            Value::Text(x) => x.parse().ok(),
157            _ => None,
158        }
159    }
160}
161
162impl From<f64> for Value {
163    fn from(x: f64) -> Value {
164        Value::Number(x)
165    }
166}
167
168impl<'a> FromValue<'a> for f64 {
169    fn from_value(value: &'a Value) -> Option<f64> {
170        match value {
171            Value::Integer(x) => Some(*x as f64),
172            Value::Number(x) => Some(*x),
173            Value::Text(x) => x.parse().ok(),
174            _ => None,
175        }
176    }
177}
178
179impl From<String> for Value {
180    fn from(x: String) -> Value {
181        Value::Text(x)
182    }
183}
184
185impl<'a> FromValue<'a> for &'a String {
186    fn from_value(value: &'a Value) -> Option<&'a String> {
187        match value {
188            Value::Text(x) => Some(x),
189            _ => None,
190        }
191    }
192}
193
194impl<'a> FromValueMut<'a> for &'a mut String {
195    fn from_value_mut(value: &'a mut Value) -> Option<&'a mut String> {
196        match value {
197            Value::Text(x) => Some(x),
198            _ => None,
199        }
200    }
201}
202
203impl<'a> FromValue<'a> for String {
204    fn from_value(value: &'a Value) -> Option<String> {
205        match value {
206            Value::Boolean(x) => Some(x.to_string()),
207            Value::Integer(x) => Some(x.to_string()),
208            Value::Number(x) => Some(x.to_string()),
209            Value::Text(x) => Some(x.to_string()),
210            _ => None,
211        }
212    }
213}
214
215impl From<Vec<Value>> for Value {
216    fn from(x: Vec<Value>) -> Value {
217        Value::List(x)
218    }
219}
220
221impl<'a> FromValue<'a> for &'a Vec<Value> {
222    fn from_value(value: &'a Value) -> Option<&'a Vec<Value>> {
223        match value {
224            Value::List(x) => Some(x),
225            _ => None,
226        }
227    }
228}
229
230impl<'a> FromValueMut<'a> for &'a mut Vec<Value> {
231    fn from_value_mut(value: &'a mut Value) -> Option<&'a mut Vec<Value>> {
232        match value {
233            Value::List(x) => Some(x),
234            _ => None,
235        }
236    }
237}
238
239impl From<Table> for Value {
240    fn from(x: Table) -> Value {
241        Value::Table(x)
242    }
243}
244
245impl<'a> FromValue<'a> for &'a Table {
246    fn from_value(value: &'a Value) -> Option<&'a Table> {
247        match value {
248            Value::Table(x) => Some(x),
249            _ => None,
250        }
251    }
252}
253
254impl<'a> FromValueMut<'a> for &'a mut Table {
255    fn from_value_mut(value: &'a mut Value) -> Option<&'a mut Table> {
256        match value {
257            Value::Table(x) => Some(x),
258            _ => None,
259        }
260    }
261}
262
263impl<T> From<Option<T>> for Value
264where
265    Value: From<T>,
266{
267    fn from(x: Option<T>) -> Value {
268        match x {
269            None => Value::Null,
270            Some(t) => Value::from(t),
271        }
272    }
273}
274
275//FIXME Use From/TryFrom here
276macro_rules! derive_value {
277    ($x:ty as $($y:ty),*) => {$(
278        impl From<$y> for Value {
279            fn from(y: $y) -> Value {
280                Value::from(y as $x)
281            }
282        }
283
284        impl<'a> FromValue<'a> for $y {
285            fn from_value(value: &'a Value) -> Option<$y> {
286                <$x>::from_value(value)
287                    .map(|x| x as $y)
288            }
289        }
290    )*}
291}
292
293derive_value!(i64 as i8, i16, i32, isize, u8, u16, u32, u64, usize);
294derive_value!(f64 as f32);