1#![deny(missing_docs)]
55#![deny(rust_2018_compatibility)]
56#![deny(rust_2018_idioms)]
57#![no_std]
62
63extern crate alloc;
64#[cfg(test)]
65extern crate std;
66
67pub mod de;
68pub mod ser;
69
70#[doc(inline)]
71pub use self::de::{from_slice, from_str};
72#[doc(inline)]
73pub use self::ser::{to_string, to_vec};
74
75#[cfg(test)]
76mod test {
77 use alloc::borrow::ToOwned;
78 use alloc::collections::BTreeMap;
79 use alloc::string::{String, ToString};
80 use alloc::vec;
81 use alloc::vec::Vec;
82
83 use super::*;
84 use serde_derive::{Deserialize, Serialize};
85
86 #[derive(Debug, Deserialize, Serialize, PartialEq)]
87 struct Address(String);
88
89 #[derive(Debug, Deserialize, Serialize, PartialEq)]
90 struct CommentId(u32);
91
92 #[derive(Debug, Deserialize, Serialize, PartialEq)]
93 enum Model {
94 Comment,
95 Post { category: String, author: Address },
96 }
97
98 #[derive(Debug, Deserialize, Serialize, PartialEq)]
99 struct Stats {
100 views: u64,
101 score: i64,
102 }
103
104 #[derive(Debug, Deserialize, Serialize, PartialEq)]
105 struct Item {
106 model: Model,
107 title: String,
108 content: Option<String>,
109 list: Vec<u32>,
110 published: bool,
111 comments: Vec<CommentId>,
112 stats: Stats,
113 balances: BTreeMap<String, u16>,
114 }
115
116 #[test]
117 fn can_serde() {
118 let min = Item {
119 model: Model::Comment,
120 title: String::new(),
121 content: None,
122 list: vec![],
123 published: false,
124 comments: vec![],
125 stats: Stats { views: 0, score: 0 },
126 balances: BTreeMap::new(),
127 };
128 let mut balances: BTreeMap<String, u16> = BTreeMap::new();
129 balances.insert("chareen".into(), 347);
130 let max = Item {
131 model: Model::Post {
132 category: "fun".to_string(),
133 author: Address("sunnyboy85".to_string()),
134 },
135 title: "Nice message".to_string(),
136 content: Some("Happy \"blogging\" 👏\n\n\tCheers, I'm out\0\0\0".to_string()),
137 list: vec![0, 1, 2, 3, 42, 154841, u32::MAX],
138 published: true,
139 comments: vec![CommentId(2), CommentId(700)],
140 stats: Stats {
141 views: u64::MAX,
142 score: i64::MIN,
143 },
144 balances,
145 };
146
147 assert_eq!(from_slice::<Item>(&to_vec(&min).unwrap()).unwrap(), min);
149 assert_eq!(from_slice::<Item>(&to_vec(&max).unwrap()).unwrap(), max);
150
151 assert_eq!(from_str::<Item>(&to_string(&min).unwrap()).unwrap(), min);
153 assert_eq!(from_str::<Item>(&to_string(&max).unwrap()).unwrap(), max);
154 }
155
156 #[test]
157 fn untagged() {
158 #[derive(Debug, Deserialize, Serialize, PartialEq)]
159 #[serde(untagged)]
160 enum UntaggedEnum {
161 S(String),
162 I(i64),
163 }
164
165 let s = UntaggedEnum::S("Some string".to_owned());
166 let i = UntaggedEnum::I(32);
167
168 assert_eq!(from_slice::<UntaggedEnum>(&to_vec(&s).unwrap()).unwrap(), s);
169 assert_eq!(from_slice::<UntaggedEnum>(&to_vec(&i).unwrap()).unwrap(), i);
170
171 assert_eq!(
172 from_str::<UntaggedEnum>(&to_string(&s).unwrap()).unwrap(),
173 s
174 );
175 assert_eq!(
176 from_str::<UntaggedEnum>(&to_string(&i).unwrap()).unwrap(),
177 i
178 );
179 }
180
181 #[test]
182 fn untagged_structures() {
183 #[derive(Debug, Deserialize, Serialize, PartialEq)]
184 #[serde(untagged)]
185 enum ModelOrItem {
186 Model(Model),
187 Item(Item),
188 }
189
190 let model = ModelOrItem::Model(Model::Post {
191 category: "Rust".to_owned(),
192 author: Address("no-reply@domain.com".to_owned()),
193 });
194
195 let mut balances: BTreeMap<String, u16> = BTreeMap::new();
196 balances.insert("chareen".into(), 347);
197
198 let item = ModelOrItem::Item(Item {
199 model: Model::Comment,
200 title: "Title".to_owned(),
201 content: None,
202 list: vec![13, 14],
203 published: true,
204 comments: vec![],
205 stats: Stats {
206 views: 110,
207 score: 12,
208 },
209 balances,
210 });
211
212 assert_eq!(
213 from_slice::<ModelOrItem>(&to_vec(&model).unwrap()).unwrap(),
214 model
215 );
216 assert_eq!(
217 from_slice::<ModelOrItem>(&to_vec(&item).unwrap()).unwrap(),
218 item
219 );
220
221 assert_eq!(
222 from_str::<ModelOrItem>(&to_string(&model).unwrap()).unwrap(),
223 model
224 );
225 assert_eq!(
226 from_str::<ModelOrItem>(&to_string(&item).unwrap()).unwrap(),
227 item
228 );
229 }
230
231 #[test]
232 fn no_stack_overflow() {
233 const AMOUNT: usize = 2000;
234 let mut json = String::from(r#"{"":"#);
235
236 #[derive(Debug, Deserialize, Serialize)]
237 pub struct Person {
238 name: String,
239 age: u8,
240 phones: Vec<String>,
241 }
242
243 for _ in 0..AMOUNT {
244 json.push('[');
245 }
246 for _ in 0..AMOUNT {
247 json.push(']');
248 }
249
250 json.push_str(r#"] }[[[[[[[[[[[[[[[[[[[[[ ""","age":35,"phones":["#);
251
252 let err = from_str::<Person>(&json).unwrap_err();
253 assert_eq!(err, crate::de::Error::RecursionLimitExceeded);
254 }
255}