1mod decoders;
2mod map_fns;
3
4pub use decoders::{
5 and_then, boolean, fail, field, float, integer, json, list, map, option, serde, string,
6 succeed, unsigned_integer, BoxDecoder,
7};
8pub use map_fns::*;
9
10pub trait Decoder<'a, DecodesTo> {
11 fn decode(&self, value: &serde_json::Value) -> Result<DecodesTo, DecodeError>;
19}
20
21#[derive(thiserror::Error, Debug, PartialEq)]
22pub enum DecodeError {
23 #[error("Could not find field {0} in {1}")]
24 MissingField(String, String),
25 #[error("Expected a {0} but found a {1}")]
26 IncorrectType(String, String),
27 #[error("Invalid integer: {0}")]
28 InvalidInteger(String),
29 #[error("Integer {0} was too big to decode as {1}")]
30 IntegerOverflow(String, &'static str),
31 #[error("Serde error: {0}")]
32 SerdeError(String),
33 #[error("Error: {0}")]
34 Other(String),
35}
36
37#[cfg(test)]
38mod tests {
39 use super::*;
40
41 #[derive(Debug, PartialEq)]
42 struct TestStruct {
43 field_one: String,
44 }
45
46 impl TestStruct {
47 fn new(field_one: String) -> Self {
48 TestStruct { field_one }
49 }
50 }
51
52 #[test]
53 fn decode_a_struct() {
54 let decoder = map(TestStruct::new, field("field_one", string()));
55
56 let json = serde_json::from_str(r#"{"field_one": "test"}"#).unwrap();
57
58 assert_eq!(
59 decoder.decode(&json),
60 Ok(TestStruct {
61 field_one: "test".to_string()
62 })
63 )
64 }
65
66 #[derive(Debug, PartialEq)]
67 struct Test4Struct {
68 field_one: String,
69 field_two: i64,
70 field_three: bool,
71 field_four: f64,
72 }
73
74 impl Test4Struct {
75 fn new(field_one: String, field_two: i64, field_three: bool, field_four: f64) -> Self {
76 Test4Struct {
77 field_one,
78 field_two,
79 field_three,
80 field_four,
81 }
82 }
83 }
84
85 #[test]
89 fn one_of_the_macro_map_fns() {
90 let decoder = map4(
91 Test4Struct::new,
92 field("field_one", string()),
93 field("field_two", integer()),
94 field("field_three", boolean()),
95 field("field_four", float()),
96 );
97
98 let json = serde_json::json!({"field_one": "test", "field_two": 10000, "field_three": true, "field_four": 1.0});
99
100 assert_eq!(
101 decoder.decode(&json),
102 Ok(Test4Struct {
103 field_one: "test".to_string(),
104 field_two: 10000,
105 field_three: true,
106 field_four: 1.0
107 })
108 )
109 }
110
111 #[test]
112 fn decoding_a_list() {
113 let decoder = list::<_, Vec<_>>(string());
114
115 let json = serde_json::json!(["one", "two", "three", "four"]);
116
117 assert_eq!(
118 decoder.decode(&json),
119 Ok(vec![
120 "one".to_string(),
121 "two".to_string(),
122 "three".to_string(),
123 "four".to_string()
124 ])
125 )
126 }
127
128 #[test]
129 fn decoding_opt_vec_opt() {
130 let decoder = option(list::<_, Vec<_>>(option(string())));
131
132 assert_eq!(
133 decoder.decode(&serde_json::json!(["hello", null])),
134 Ok(Some(vec![Some("hello".to_string()), None]))
135 );
136 assert_eq!(decoder.decode(&serde_json::json!(null)), Ok(None))
137 }
138
139 #[test]
140 fn decode_using_serde() {}
141
142 #[test]
143 fn test_and_then() {
144 let decoder = and_then(
145 |s| {
146 if s == "ok" {
147 succeed(Some(s))
148 } else {
149 fail("Go Away")
150 }
151 },
152 string(),
153 );
154
155 assert_eq!(
156 decoder.decode(&serde_json::json!("ok")),
157 Ok(Some("ok".to_string()))
158 );
159
160 assert_eq!(
161 decoder.decode(&serde_json::json!("fail")),
162 Err(DecodeError::Other("Go Away".into()))
163 );
164 }
165
166 #[test]
167 #[allow(clippy::unnecessary_cast)]
168 fn decoding_integers() {
169 assert_eq!(integer().decode(&serde_json::json!(1)), Ok(1 as i32));
170 assert_eq!(integer().decode(&serde_json::json!(1)), Ok(1 as i64));
171 assert_eq!(
172 integer::<i8>().decode(&serde_json::json!(512)),
173 Err(DecodeError::IntegerOverflow("512".to_string(), "i8"))
174 );
175
176 assert_eq!(
177 unsigned_integer().decode(&serde_json::json!(1)),
178 Ok(1 as u32)
179 );
180 assert_eq!(
181 unsigned_integer().decode(&serde_json::json!(1)),
182 Ok(1 as u64)
183 );
184 assert_eq!(
185 unsigned_integer::<u8>().decode(&serde_json::json!(512)),
186 Err(DecodeError::IntegerOverflow("512".to_string(), "u8"))
187 );
188 }
189}