kserd/
to_kserd.rs

1use crate::{
2    ds::{InvalidFieldName, InvalidId},
3    Kserd, Value,
4};
5use std::{error, fmt};
6
7/// _Convert_ something into a `Kserd`.
8///
9/// This differs to [_encoding_](crate::encode::Encoder) in that the object is _consumed_. This trait
10/// allows for less copying as data can be _moved_, in the case of strings or byte arrays.
11///
12/// # Implementing
13/// The crate `kserd_derive` can be used to annotate objects with `#[derive(ToKserd)]`. The crate
14/// works much in the same way as `serde_derive`.
15///
16/// If you want to manually implement `ToKserd` an example is given below.
17///
18/// ```rust
19/// use kserd::*;
20/// # #[cfg(feature = "fmt")] {
21/// struct MyStruct<'a> {
22///     e: MyEnum,
23///     s: &'a str,
24///     v: Vec<(isize, isize)>,
25/// }
26///
27/// enum MyEnum {
28///     Variant1,
29///     Variant2(usize)
30/// }
31///
32/// // let's implement MyEnum first
33/// // it has no references so can be valid for the static lifetime
34/// impl ToKserd<'static> for MyEnum {
35///     fn into_kserd(self) -> Result<Kserd<'static>, ToKserdErr> {
36///         let r = match self {
37///             MyEnum::Variant1 =>
38///                 Kserd::with_id("Variant1", Value::Unit)?,
39///             // A variant with items is a named Tuple
40///             MyEnum::Variant2(i) =>
41///                 Kserd::with_id("Variant2", Value::Tuple(vec![
42///                     i.into_kserd()?
43///                 ]))?,
44///         };
45///         Ok(r)
46///     }
47/// }
48///
49/// // now implement MyStruct
50/// // it has a reference so make it last for that long
51/// impl<'a> ToKserd<'a> for MyStruct<'a> {
52///     fn into_kserd(self) -> Result<Kserd<'a>, ToKserdErr> {
53///         Ok(Kserd::with_id("MyStruct", Value::new_cntr(vec![
54///             ("e", self.e.into_kserd()?),
55///             ("s", self.s.into_kserd()?),
56///             ("v", self.v.into_kserd()?),
57///         ]).unwrap())?) // notice the ? to propogate the error
58///     }
59/// }
60///
61/// // lets test it
62/// let mys = MyStruct {
63///     e: MyEnum::Variant2(101),
64///     s: "Hello, world!",
65///     v: vec![
66///         (0, 1),
67///         (2, 3),
68///         (4, 5)
69///     ]
70/// };
71///
72/// let kserd = mys.into_kserd().unwrap();
73///
74/// let s = kserd.as_str();
75///
76/// assert_eq!(
77/// &s,
78/// r#"MyStruct (
79///     e = Variant2 (101)
80///     s = "Hello, world!"
81///     v = [(0, 1), (2, 3), (4, 5)]
82/// )"#
83/// );
84/// # }
85/// ```
86pub trait ToKserd<'a> {
87    /// Consume the object and convert it into a [`Kserd`](Kserd) data object.
88    fn into_kserd(self) -> Result<Kserd<'a>, ToKserdErr>;
89}
90
91/// Errors that can occur when using [`ToKserd`](ToKserd).
92#[derive(Debug, PartialEq, Clone)]
93pub enum ToKserdErr {
94    /// The identity contained invalid characters.
95    InvalidId(InvalidId),
96    /// A container's field name contained invalid characters.
97    InvalidFieldName(InvalidFieldName),
98}
99
100impl error::Error for ToKserdErr {}
101
102impl fmt::Display for ToKserdErr {
103    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
104        match self {
105            ToKserdErr::InvalidId(s) => write!(f, "{}", s),
106            ToKserdErr::InvalidFieldName(s) => write!(f, "{}", s),
107        }
108    }
109}
110
111impl<'a> ToKserd<'a> for Kserd<'a> {
112    fn into_kserd(self) -> Result<Kserd<'a>, ToKserdErr> {
113        Ok(self)
114    }
115}
116
117impl From<InvalidId> for ToKserdErr {
118    fn from(id: InvalidId) -> ToKserdErr {
119        ToKserdErr::InvalidId(id)
120    }
121}
122
123impl From<InvalidFieldName> for ToKserdErr {
124    fn from(x: InvalidFieldName) -> ToKserdErr {
125        ToKserdErr::InvalidFieldName(x)
126    }
127}
128
129#[cfg(test)]
130use rand::{random, thread_rng, Rng};
131#[cfg(test)]
132fn random_string() -> String {
133    let mut rng = rand::thread_rng();
134    let len = rng.gen::<u8>() as usize;
135    let mut s = String::new();
136    for _ in 0..len {
137        s.push(rng.gen());
138    }
139    s
140}
141
142#[test]
143fn test_kserd_to_kserd() {
144    let kserd = (random_string(), rand::random::<usize>())
145        .into_kserd()
146        .unwrap();
147    let kserdnew = kserd.clone().into_kserd().unwrap();
148    assert_eq!(kserd, kserdnew);
149}
150
151#[test]
152fn test_tokserderr_display() {
153    let e: ToKserdErr = Kserd::with_id(".", Value::Unit).unwrap_err().into();
154    assert_eq!(
155        &e.to_string(),
156        r#"identity '.' contains invalid characters. Invalid characters: '(){}[]<> ,./\='"#
157    );
158
159    let e: ToKserdErr = Value::new_cntr(vec![("/", Kserd::new_unit())])
160        .unwrap_err()
161        .into();
162    assert_eq!(
163        &e.to_string(),
164        r#"invalid field name: invalid character '/' exists in name '/'"#
165    );
166}
167
168// ********************* COPY-ABLE PRIMITIVES *********************************
169
170macro_rules! number {
171    ( $( $x:ty ) * ) => {
172        $(
173            impl ToKserd<'static> for $x {
174                fn into_kserd(self) -> Result<Kserd<'static>, ToKserdErr> {
175                    Ok(Kserd::new_num(self))
176                }
177            }
178        )*
179    }
180}
181
182number!(
183    usize u8 u16 u32 u64 u128
184    isize i8 i16 i32 i64 i128
185    f32 f64
186);
187
188impl ToKserd<'static> for () {
189    fn into_kserd(self) -> Result<Kserd<'static>, ToKserdErr> {
190        Ok(Kserd::new_unit())
191    }
192}
193
194impl ToKserd<'static> for bool {
195    fn into_kserd(self) -> Result<Kserd<'static>, ToKserdErr> {
196        Ok(Kserd::new_bool(self))
197    }
198}
199
200impl ToKserd<'static> for char {
201    fn into_kserd(self) -> Result<Kserd<'static>, ToKserdErr> {
202        Ok(Kserd::with_id_unchk(
203            "char",
204            Value::Str(self.to_string().into()),
205        ))
206    }
207}
208
209#[test]
210fn test_copyable_primitives() {
211    assert_eq!(123_456.into_kserd(), Ok(Kserd::new_num(123_456)));
212    assert_eq!((-1_234_567).into_kserd(), Ok(Kserd::new_num(-1_234_567)));
213    assert_eq!(3.14.into_kserd(), Ok(Kserd::new_num(3.14)));
214    assert_eq!(().into_kserd(), Ok(Kserd::new_unit()));
215    assert_eq!(true.into_kserd(), Ok(Kserd::new_bool(true)));
216    assert_eq!('y'.into_kserd(), Ok(Kserd::new_str("y")));
217}
218
219// ********************* STRINGS AND BYTE ARRAYS ******************************
220
221impl ToKserd<'static> for String {
222    fn into_kserd(self) -> Result<Kserd<'static>, ToKserdErr> {
223        Ok(Kserd::new_string(self))
224    }
225}
226
227impl<'a> ToKserd<'a> for &'a str {
228    fn into_kserd(self) -> Result<Kserd<'a>, ToKserdErr> {
229        Ok(Kserd::new_str(self))
230    }
231}
232
233#[test]
234fn test_strings() {
235    let s = random_string();
236    assert_eq!(s.as_str().into_kserd(), Ok(Kserd::new_str(&s)));
237    assert_eq!(s.clone().into_kserd(), Ok(Kserd::new_string(s)));
238}
239
240// ********************* TUPLES AND ARRAYS ************************************
241
242macro_rules! tuples {
243    ( $( $lifetime:tt|$element:tt|$idx:tt ),+ ) => {
244        impl<'kserd, $($lifetime: 'kserd,)* $($element,)*> ToKserd<'kserd> for ($($element,)*)
245        where
246            $(
247                $element: ToKserd<$lifetime>,
248            )*
249        {
250            fn into_kserd(self) -> Result<Kserd<'kserd>, ToKserdErr> {
251                let v = vec![$(
252                    self.$idx.into_kserd()?,
253                )*];
254                Ok(Kserd::new(Value::Tuple(v)))
255            }
256        }
257    }
258}
259
260tuples!('a|A|0);
261tuples!('a|A|0,'b|B|1);
262tuples!('a|A|0,'b|B|1,'c|C|2);
263tuples!('a|A|0,'b|B|1,'c|C|2, 'd|D|3);
264tuples!('a|A|0,'b|B|1,'c|C|2, 'd|D|3, 'e|E|4);
265tuples!('a|A|0,'b|B|1,'c|C|2, 'd|D|3, 'e|E|4, 'f|F|5);
266tuples!('a|A|0,'b|B|1,'c|C|2, 'd|D|3, 'e|E|4, 'f|F|5, 'g|G|6);
267tuples!('a|A|0,'b|B|1,'c|C|2, 'd|D|3, 'e|E|4, 'f|F|5, 'g|G|6, 'h|H|7);
268tuples!('a|A|0,'b|B|1,'c|C|2, 'd|D|3, 'e|E|4, 'f|F|5, 'g|G|6, 'h|H|7, 'i|I|8);
269tuples!('a|A|0,'b|B|1,'c|C|2, 'd|D|3, 'e|E|4, 'f|F|5, 'g|G|6, 'h|H|7, 'i|I|8, 'j|J|9);
270tuples!('a|A|0,'b|B|1,'c|C|2, 'd|D|3, 'e|E|4, 'f|F|5, 'g|G|6, 'h|H|7, 'i|I|8, 'j|J|9, 'k|K|10);
271tuples!('a|A|0,'b|B|1,'c|C|2, 'd|D|3, 'e|E|4, 'f|F|5, 'g|G|6, 'h|H|7, 'i|I|8, 'j|J|9, 'k|K|10, 'l|L|11);
272
273macro_rules! array {
274    ( $( $x:literal ) * ) => {
275        $(
276            impl<'a, T: ToKserd<'a>> ToKserd<'a> for [T; $x] {
277                fn into_kserd(self) -> Result<Kserd<'a>, ToKserdErr> {
278                    let b: Box<[T]> = Box::new(self);
279                    let arr = b.into_vec();
280                    let mut v = Vec::with_capacity(arr.len());
281                    for i in arr.into_iter() {
282                        v.push(i.into_kserd()?);
283                    }
284                    Ok(Kserd::with_id_unchk("array", Value::Seq(v)))
285                }
286            }
287        )*
288    }
289}
290
291array!(
292     1  2  3  4  5  6  7  8
293     9 10 11 12 13 14 15 16
294    17 18 19 20 21 22 23 24
295    25 26 27 28 29 30 31 32
296);
297
298#[test]
299fn tuples_and_array_test() {
300    let mut rng = thread_rng();
301
302    macro_rules! tester {
303        (arrays $( $size:literal ) * ) => {{
304            $(
305            let mut arr = [0u8; $size];
306            rng.fill(&mut arr[..]);
307            let v = arr.iter().copied().collect::<Vec<_>>();
308            assert_eq!(arr.into_kserd(), v.into_kserd());
309            )*
310        }};
311        (tuples $tuple:expr => $($idx:tt),*) => {{
312            let tuple = $tuple;
313            let kserd = tuple.clone().into_kserd().unwrap();
314            let vec = match kserd.val {
315                Value::Tuple(v) => v,
316                _ => unreachable!("should be a tuple")
317            };
318            $(
319                assert_eq!(tuple.$idx.clone().into_kserd().unwrap(), vec[$idx]);
320            )*
321        }}
322    };
323
324    tester!(arrays
325         1  2  3  4  5  6  7  8
326         9 10 11 12 13 14 15 16
327        17 18 19 20 21 22 23 24
328        25 26 27 28 29 30 31 32
329    );
330
331    tester!(tuples (random_string(),) => 0);
332    tester!(tuples (random_string(), rng.gen::<usize>()) => 0,1);
333    tester!(tuples (random_string(), rng.gen::<usize>(), random_string()) => 0,1,2);
334    tester!(tuples (random_string(), rng.gen::<usize>(), random_string(), rng.gen::<char>()) => 0,1,2,3);
335    tester!(tuples (random_string(), rng.gen::<usize>(), random_string(), rng.gen::<char>(), random_string()) => 0,1,2,3,4);
336    tester!(tuples (random_string(), rng.gen::<usize>(), random_string(), rng.gen::<char>(), random_string(), random_string()) => 0,1,2,3,4,5);
337    tester!(tuples (random_string(), rng.gen::<usize>(), random_string(), rng.gen::<char>(), random_string(), random_string(), rng.gen::<isize>()) => 0,1,2,3,4,5,6);
338    tester!(tuples (random_string(), random::<usize>(), random_string(), rng.gen::<char>(), random_string(), random_string(), rng.gen::<isize>(), rng.gen::<bool>()) => 0,1,2,3,4,5,6,7);
339    tester!(tuples (random_string(), rng.gen::<usize>(), random_string(), rng.gen::<char>(), random_string(), random_string(), rng.gen::<isize>(), rng.gen::<bool>(), rng.gen::<char>()) => 0,1,2,3,4,5,6,7,8);
340    tester!(tuples (random_string(), rng.gen::<usize>(), random_string(), rng.gen::<char>(), random_string(), random_string(), rng.gen::<isize>(), rng.gen::<bool>(), rng.gen::<char>(), rng.gen::<f64>()) => 0,1,2,3,4,5,6,7,8,9);
341    tester!(tuples (random_string(), rng.gen::<usize>(), random_string(), rng.gen::<char>(), random_string(), random_string(), rng.gen::<isize>(), rng.gen::<bool>(), rng.gen::<char>(), rng.gen::<f64>(), random_string()) => 0,1,2,3,4,5,6,7,8,9,10);
342    tester!(tuples (random_string(), rng.gen::<usize>(), random_string(), rng.gen::<char>(), random_string(), random_string(), rng.gen::<isize>(), rng.gen::<bool>(), rng.gen::<char>(), rng.gen::<f64>(), random_string(), random_string()) => 0,1,2,3,4,5,6,7,8,9,10,11);
343}
344
345// ********************* SEQUENCES AND MAPS ***********************************
346
347impl<'a, T: ToKserd<'a>> ToKserd<'a> for Vec<T> {
348    fn into_kserd(self) -> Result<Kserd<'a>, ToKserdErr> {
349        let mut v = Vec::with_capacity(self.len());
350        for i in self {
351            v.push(i.into_kserd()?);
352        }
353        Ok(Kserd::with_id_unchk("Vec", Value::Seq(v)))
354    }
355}
356
357// ********************* BLANKET IMPLEMENTATIONS ******************************
358
359impl<'a, T> ToKserd<'a> for Box<T>
360where
361    T: ToKserd<'a>,
362{
363    fn into_kserd(self) -> Result<Kserd<'a>, ToKserdErr> {
364        (*self).into_kserd()
365    }
366}
367
368/// Blanket implementation for `Option<T>`.
369///
370/// The implementation _does not wrap `Some` values_. Rather, if there is something, it is just
371/// that value, or it will be an empty tuple with the name `None`.
372///
373/// ```rust
374/// # use kserd::*;
375/// let option = Some(String::from("Hello, world!"));
376/// assert_eq!(option.into_kserd(), Ok(Kserd::new_str("Hello, world!")));
377/// let option: Option<String> = None;
378/// assert_eq!(option.into_kserd(), Kserd::with_id("None", Value::Tuple(vec![])).map_err(From::from));
379/// ```
380impl<'a, T> ToKserd<'a> for Option<T>
381where
382    T: ToKserd<'a>,
383{
384    fn into_kserd(self) -> Result<Kserd<'a>, ToKserdErr> {
385        match self {
386            Some(x) => x.into_kserd(),
387            None => Ok(Kserd::with_id_unchk("None", Value::Tuple(Vec::new()))),
388        }
389    }
390}
391
392impl<'kserd, 't: 'kserd, 'e: 'kserd, T, E> ToKserd<'kserd> for Result<T, E>
393where
394    T: ToKserd<'t>,
395    E: ToKserd<'e>,
396{
397    fn into_kserd(self) -> Result<Kserd<'kserd>, ToKserdErr> {
398        Ok(match self {
399            Ok(x) => Kserd::with_id_unchk("Ok", Value::Tuple(vec![x.into_kserd()?])),
400            Err(x) => Kserd::with_id_unchk("Err", Value::Tuple(vec![x.into_kserd()?])),
401        })
402    }
403}
404
405#[test]
406fn blanket_impls_tests() {
407    let boxed = Box::new(String::from("Hello, world!"));
408    assert_eq!(boxed.into_kserd(), Ok(Kserd::new_str("Hello, world!")));
409
410    let option = Some(String::from("Hello, world!"));
411    assert_eq!(option.into_kserd(), Ok(Kserd::new_str("Hello, world!")));
412    let option: Option<String> = None;
413    assert_eq!(
414        option.into_kserd(),
415        Kserd::with_id("None", Value::Tuple(vec![])).map_err(From::from)
416    );
417
418    let ok: Result<String, String> = Ok(String::from("I am okay!"));
419    assert_eq!(
420        ok.into_kserd(),
421        Ok(Kserd::new(Value::Tuple(vec![Kserd::new_str("I am okay!")])))
422    );
423    let err: Result<String, String> = Err(String::from("I am not!"));
424    assert_eq!(
425        err.into_kserd(),
426        Ok(Kserd::new(Value::Tuple(vec![Kserd::new_str("I am not!")])))
427    );
428}
429
430// ********************* STRINGS AND BYTE ARRAYS ******************************
431// ********************* STRINGS AND BYTE ARRAYS ******************************
432// ********************* STRINGS AND BYTE ARRAYS ******************************