realm_db_reader/value/
into.rs

1use std::any::type_name;
2use std::error::Error;
3
4use chrono::{DateTime, Utc};
5
6use crate::error::ValueError;
7use crate::table::Row;
8use crate::value::{ARRAY_VALUE_KEY, Backlink, Link, Value};
9
10macro_rules! value_try_into {
11    (Option<$target:ty>, $source:ident) => {
12        impl TryFrom<Value> for Option<$target> {
13            type Error = ValueError;
14
15            fn try_from(value: Value) -> Result<Self, Self::Error> {
16                match value {
17                    Value::$source(val) => Ok(Some(val)),
18                    Value::None => Ok(None),
19                    value => Err(ValueError::UnexpectedType {
20                        expected: stringify!($target),
21                        found: value,
22                    }),
23                }
24            }
25        }
26    };
27
28    ($target:ty, $source:ident) => {
29        impl TryFrom<Value> for $target {
30            type Error = ValueError;
31
32            fn try_from(value: Value) -> Result<Self, Self::Error> {
33                match value {
34                    Value::$source(val) => Ok(val),
35                    value => Err(ValueError::UnexpectedType {
36                        expected: stringify!($target),
37                        found: value,
38                    }),
39                }
40            }
41        }
42
43        impl<'a> TryFrom<Row<'a>> for $target {
44            type Error = ValueError;
45
46            fn try_from(mut value: Row<'a>) -> Result<Self, Self::Error> {
47                let Some(value) = value.take(ARRAY_VALUE_KEY) else {
48                    return Err(ValueError::ExpectedArrayRow {
49                        field: ARRAY_VALUE_KEY,
50                        found: value.into_owned(),
51                    });
52                };
53
54                value.try_into()
55            }
56        }
57    };
58}
59
60value_try_into!(String, String);
61value_try_into!(Option<String>, String);
62value_try_into!(i64, Int);
63value_try_into!(Option<i64>, Int);
64value_try_into!(bool, Bool);
65value_try_into!(f32, Float);
66value_try_into!(f64, Double);
67value_try_into!(DateTime<Utc>, Timestamp);
68value_try_into!(Option<DateTime<Utc>>, Timestamp);
69value_try_into!(Backlink, BackLink);
70value_try_into!(Link, Link);
71value_try_into!(Option<Link>, Link);
72
73impl<'a, T> TryFrom<Value> for Vec<T>
74where
75    T: TryFrom<Row<'a>>,
76    T::Error: Error + 'static,
77{
78    type Error = ValueError;
79
80    fn try_from(value: Value) -> Result<Self, Self::Error> {
81        match value {
82            Value::Table(rows) => {
83                let mut result = Vec::with_capacity(rows.len());
84                for row in rows {
85                    result.push(row.try_into().map_err(|e| ValueError::VecConversionError {
86                        element_type: type_name::<T>(),
87                        source: Box::new(e),
88                    })?);
89                }
90
91                Ok(result)
92            }
93            value => Err(ValueError::ExpectedTable { found: value }),
94        }
95    }
96}