summaryrefslogtreecommitdiff
path: root/serde_dhall/src/static_type.rs
blob: 19f1202cbbc10e0a336f80bfae9abc2f3b189534 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use crate::SimpleType;

/// A Rust type that can be represented as a Dhall type.
///
/// A typical example is `Option<bool>`, represented by the Dhall expression `Optional Bool`.
///
/// This trait can be automatically derived, and this is the recommended way of implementing it.
///
/// Some Rust types cannot implement this trait, because there isn't a single Dhall type that
/// corresponds to them. For example, `HashMap<String, u64>` could correspond to multiple different
/// Dhall types, e.g. `{ foo: Natural, bar: Natural }` and `{ baz: Natural }`.
///
/// # Example
///
/// ```rust
/// # fn main() -> serde_dhall::Result<()> {
/// use serde_dhall::{SimpleType, StaticType};
///
/// #[derive(StaticType)]
/// struct Foo {
///     x: bool,
///     y: Vec<u64>,
/// }
///
/// let ty: SimpleType =
///     serde_dhall::from_str("{ x: Bool, y: List Natural }")?;
///
/// assert_eq!(Foo::static_type(), ty);
/// # Ok(())
/// # }
/// ```
pub trait StaticType {
    fn static_type() -> SimpleType;
}

macro_rules! derive_builtin {
    ($rust_ty:ty, $dhall_ty:ident) => {
        impl StaticType for $rust_ty {
            fn static_type() -> SimpleType {
                SimpleType::$dhall_ty
            }
        }
    };
}

derive_builtin!(bool, Bool);
derive_builtin!(usize, Natural);
derive_builtin!(u64, Natural);
derive_builtin!(u32, Natural);
derive_builtin!(isize, Integer);
derive_builtin!(i64, Integer);
derive_builtin!(i32, Integer);
derive_builtin!(f64, Double);
derive_builtin!(f32, Double);
derive_builtin!(String, Text);

impl<A, B> StaticType for (A, B)
where
    A: StaticType,
    B: StaticType,
{
    fn static_type() -> SimpleType {
        SimpleType::Record(
            vec![
                ("_1".to_owned(), A::static_type()),
                ("_2".to_owned(), B::static_type()),
            ]
            .into_iter()
            .collect(),
        )
        .into()
    }
}

impl<T, E> StaticType for std::result::Result<T, E>
where
    T: StaticType,
    E: StaticType,
{
    fn static_type() -> SimpleType {
        SimpleType::Union(
            vec![
                ("Ok".to_owned(), Some(T::static_type())),
                ("Err".to_owned(), Some(E::static_type())),
            ]
            .into_iter()
            .collect(),
        )
        .into()
    }
}

impl<T> StaticType for Option<T>
where
    T: StaticType,
{
    fn static_type() -> SimpleType {
        SimpleType::Optional(Box::new(T::static_type())).into()
    }
}

impl<T> StaticType for Vec<T>
where
    T: StaticType,
{
    fn static_type() -> SimpleType {
        SimpleType::List(Box::new(T::static_type())).into()
    }
}

impl<'a, T> StaticType for &'a T
where
    T: StaticType,
{
    fn static_type() -> SimpleType {
        T::static_type()
    }
}