blot/value/
mod.rs

1// Copyright 2018 Arnau Siches
2
3// Licensed under the MIT license <LICENSE or http://opensource.org/licenses/MIT>.
4// This file may not be copied, modified, or distributed except
5// according to those terms.
6
7//! Represents a multi-type value able to express any Objecthash combination.
8
9use std::fmt::{self, Display};
10
11use core::Blot;
12use multihash::{Harvest, Multihash};
13use seal::Seal;
14use std::collections::HashMap;
15use tag::Tag;
16
17#[cfg(feature = "blot_json")]
18pub mod de;
19
20#[derive(Clone, Debug, PartialEq)]
21pub enum Value<T: Multihash> {
22    /// Represents a null value (similar to JSON's null).
23    Null,
24    /// Represents a boolean.
25    Bool(bool),
26    /// Represents a signed 64-bit integer.
27    Integer(i64),
28    /// Represents a 64-bit floating point.
29    Float(f64),
30    /// Represents a string.
31    String(String),
32    /// Represents a RFC3339 timestamp.
33    Timestamp(String),
34    /// Represents a sealed value (i.e. hash resulting of a redacted value).
35    Redacted(Seal<T>),
36    /// Represents a raw list of bytes.
37    Raw(Vec<u8>),
38    /// Represents a list of values.
39    List(Vec<Value<T>>),
40    /// Represents a set of values.
41    Set(Vec<Value<T>>),
42    /// Represents an attribute-value dictionary.
43    Dict(HashMap<String, Value<T>>),
44}
45
46impl<T: Multihash> Value<T> {
47    pub fn sequences_as_sets(self) -> Self {
48        match self {
49            Value::List(list) => Value::Set(list),
50            Value::Dict(dict) => Value::Dict(
51                dict.into_iter()
52                    .map(|(k, v)| (k, v.sequences_as_sets()))
53                    .collect(),
54            ),
55            value => value,
56        }
57    }
58}
59
60#[derive(Debug)]
61pub enum ValueError {
62    Unknown,
63}
64
65impl Display for ValueError {
66    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
67        write!(formatter, "{:?}", self)
68    }
69}
70
71impl<T: Multihash> Blot for Value<T> {
72    fn blot<D: Multihash>(&self, digester: &D) -> Harvest {
73        match self {
74            Value::Null => None::<u8>.blot(digester),
75            Value::Bool(raw) => raw.blot(digester),
76            Value::Integer(raw) => raw.blot(digester),
77            Value::Float(raw) => raw.blot(digester),
78            Value::String(raw) => raw.blot(digester),
79            Value::Timestamp(raw) => digester
80                .clone()
81                .digest_primitive(Tag::Timestamp, raw.as_bytes()),
82            Value::Redacted(raw) => raw.blot(digester),
83            Value::Raw(raw) => raw.as_slice().blot(digester),
84            Value::List(raw) => raw.blot(digester),
85            Value::Set(raw) => {
86                println!("in set");
87                let mut list: Vec<Vec<u8>> = raw
88                    .iter()
89                    .map(|item| {
90                        item.blot(digester)
91                            .as_slice()
92                            .iter()
93                            .map(|x| *x)
94                            .collect::<Vec<u8>>()
95                    }).collect();
96
97                list.sort_unstable();
98                list.dedup();
99
100                digester.clone().digest_collection(Tag::Set, list)
101            }
102            Value::Dict(raw) => raw.blot(digester),
103        }
104    }
105}
106
107#[macro_export]
108macro_rules! set {
109    ( $( $x:expr ),* ) => {
110        {
111            let mut temp_vec = Vec::new();
112            $(
113                temp_vec.push($x.into());
114            )*
115            Value::Set(temp_vec)
116        }
117    };
118}
119
120#[macro_export]
121macro_rules! raw {
122    ($input:expr) => {{
123        Vec::from_hex($input).map(|hash| Value::Raw(hash))
124    }};
125}
126
127#[macro_export]
128macro_rules! list {
129    ( $( $x:expr ),* ) => {
130        {
131            let mut temp_vec = Vec::new();
132            $(
133                temp_vec.push($x.into());
134            )*
135            Value::List(temp_vec)
136        }
137    };
138}
139
140#[macro_export]
141macro_rules! seal {
142    ($input:expr) => {{
143        Seal::from_str($input).map(Value::Redacted)
144    }};
145}
146
147impl<'a, T: Multihash> From<&'a str> for Value<T> {
148    fn from(raw: &str) -> Value<T> {
149        Value::String(raw.into())
150    }
151}
152
153impl<'a, T: Multihash> From<String> for Value<T> {
154    fn from(raw: String) -> Value<T> {
155        Value::String(raw)
156    }
157}
158
159impl<T: Multihash> From<i64> for Value<T> {
160    fn from(raw: i64) -> Value<T> {
161        Value::Integer(raw)
162    }
163}
164
165impl<T: Multihash> From<f64> for Value<T> {
166    fn from(raw: f64) -> Value<T> {
167        Value::Float(raw)
168    }
169}
170
171impl<T: Multihash> From<Vec<Value<T>>> for Value<T> {
172    fn from(raw: Vec<Value<T>>) -> Value<T> {
173        Value::List(raw)
174    }
175}
176
177impl<T: Multihash> From<Seal<T>> for Value<T> {
178    fn from(raw: Seal<T>) -> Value<T> {
179        Value::Redacted(raw)
180    }
181}
182
183#[cfg(test)]
184mod tests {
185    use super::*;
186    use multihash::Sha2256;
187
188    #[test]
189    fn common() {
190        let expected = "122032ae896c413cfdc79eec68be9139c86ded8b279238467c216cf2bec4d5f1e4a2";
191        let value: Value<Sha2256> = vec!["foo".into(), "bar".into()].into();
192        let actual = format!("{}", &value.digest(Sha2256));
193
194        assert_eq!(actual, expected);
195    }
196
197    #[test]
198    fn int_list() {
199        let pairs: [(Value<Sha2256>, &str); 4] = [
200            (
201                list![123],
202                "12201b93f704451e1a7a1b8c03626ffcd6dec0bc7ace947ff60d52e1b69b4658ccaa",
203            ),
204            (
205                list![1, 2, 3],
206                "1220157bf16c70bd4c9673ffb5030552df0ee2c40282042ccdf6167850edc9044ab7",
207            ),
208            (
209                list![123456789012345],
210                "12203488b9bc37cce8223a032760a9d4ef488cdfebddd9e1af0b31fcd1d7006369a4",
211            ),
212            (
213                list![123456789012345, 678901234567890],
214                "1220031ef1aaeccea3bced3a1c6237a4fc00ed4d629c9511922c5a3f4e5c128b0ae4",
215            ),
216        ];
217
218        for (value, expected) in pairs.iter() {
219            let actual = format!("{}", &value.digest(Sha2256));
220
221            assert_eq!(&actual, expected);
222        }
223    }
224
225    #[test]
226    fn floats() {
227        let mut map: HashMap<String, Value<Sha2256>> = HashMap::new();
228        map.insert(
229            "bar".into(),
230            list![
231                "baz",
232                Value::Null,
233                1.0,
234                1.5,
235                0.0001,
236                1000.0,
237                2.0,
238                -23.1234,
239                2.0
240            ],
241        );
242        let value = list!["foo", Value::Dict(map)];
243        let expected = "1220783a423b094307bcb28d005bc2f026ff44204442ef3513585e7e73b66e3c2213";
244        let actual = format!("{}", &value.digest(Sha2256));
245
246        assert_eq!(&actual, expected);
247    }
248
249    #[test]
250    fn int_floats() {
251        let mut map: HashMap<String, Value<Sha2256>> = HashMap::new();
252        map.insert(
253            "bar".into(),
254            vec![
255                "baz".into(),
256                Value::Null,
257                1.into(),
258                1.5.into(),
259                0.0001.into(),
260                1000.into(),
261                2.into(),
262                (-23.1234).into(),
263                2.into(),
264            ].into(),
265        );
266        let value = Value::List(vec!["foo".into(), Value::Dict(map)]);
267        let expected = "1220726e7ae9e3fadf8a2228bf33e505a63df8db1638fa4f21429673d387dbd1c52a";
268        let actual = format!("{}", &value.digest(Sha2256));
269
270        assert_eq!(&actual, expected);
271    }
272
273    #[test]
274    fn set() {
275        let mut map: HashMap<String, Value<Sha2256>> = HashMap::new();
276        let mut map2: HashMap<String, Value<Sha2256>> = HashMap::new();
277        map2.insert(
278            "thing2".into(),
279            Value::Set(vec![1.into(), 2.into(), "s".into()]),
280        );
281        map.insert("thing1".into(), Value::Dict(map2));
282        map.insert("thing3".into(), 1234.567.into());
283        let value = Value::Dict(map);
284
285        let expected = "1220618cf0582d2e716a70e99c2f3079d74892fec335e3982eb926835967cb0c246c";
286        let actual = format!("{}", &value.digest(Sha2256));
287
288        assert_eq!(&actual, expected);
289    }
290
291    #[test]
292    fn complex_set() {
293        let value: Value<Sha2256> = set!{"foo", 23.6, set!{set!{}}, set!{set!{1}}};
294
295        let expected = "12203773b0a5283f91243a304d2bb0adb653564573bc5301aa8bb63156266ea5d398";
296        let actual = format!("{}", &value.digest(Sha2256));
297
298        assert_eq!(&actual, expected);
299    }
300
301    #[test]
302    fn complex_set_repeated() {
303        let value: Value<Sha2256> = set!{
304            "foo",
305            23.6,
306            set!{set!{}},
307            set!{set!{1}},
308            set!{set!{}}
309        };
310
311        let expected = "12203773b0a5283f91243a304d2bb0adb653564573bc5301aa8bb63156266ea5d398";
312        let actual = format!("{}", &value.digest(Sha2256));
313
314        assert_eq!(&actual, expected);
315    }
316
317    #[test]
318    fn raw() {
319        let pairs: [(Value<Sha2256>, &str); 3] = [
320            (
321                Value::Raw(vec![]),
322                "1220454349e422f05297191ead13e21d3db520e5abef52055e4964b82fb213f593a1",
323            ),
324            (
325                Value::Raw(vec![255, 255]),
326                "122043ad246c14bf0bc0b2ac9cab9fae202a181ab4c6abb07fb40cad8c67a4cab8ee",
327            ),
328            (
329                Value::Raw(vec![0, 0, 0]),
330                "1220d877bf4e5023a6df5262218800a7162e240c84e44696bb2c3ad1c5e756f3dac1",
331            ),
332        ];
333
334        for (value, expected) in pairs.iter() {
335            let actual = format!("{}", &value.digest(Sha2256));
336
337            assert_eq!(&actual, expected);
338        }
339    }
340
341    #[test]
342    fn redacted() {
343        let expected = "1220454349e422f05297191ead13e21d3db520e5abef52055e4964b82fb213f593a1";
344        let seal: Seal<Sha2256> = Seal::from_str(
345            "**REDACTED**1220454349e422f05297191ead13e21d3db520e5abef52055e4964b82fb213f593a1",
346        ).unwrap();
347        let value = Value::Redacted(seal);
348        let actual = format!("{}", &value.digest(Sha2256));
349        assert_eq!(&actual, expected);
350    }
351
352    #[test]
353    fn redacted_mix() {
354        let expected_value: Value<Sha2256> = list!["foo", "bar"];
355        let expected = expected_value.digest(Sha2256);
356        let foo: Seal<Sha2256> = Seal::from_str(
357            "**REDACTED**1220a6a6e5e783c363cd95693ec189c2682315d956869397738679b56305f2095038",
358        ).unwrap();
359        let actual = list![foo, "bar"].digest(Sha2256);
360        assert_eq!(actual.to_string(), expected.to_string());
361    }
362
363}