1#![deny(missing_docs)]
27
28use serde_json::{self, Value};
29use std::{collections::BTreeMap, io};
30
31#[cfg(test)]
32mod tests;
33
34pub fn to_writer<W, T: Sized>(mut writer: W, value: &T) -> Result<(), Error>
36where
37 W: io::Write,
38 T: serde::ser::Serialize,
39{
40 let v = serde_json::to_value(value)?;
41 let bytes = canonicalize(&v)?;
42 writer.write_all(&bytes)?;
43 Ok(())
44}
45
46pub fn to_vec<T: Sized>(value: &T) -> Result<Vec<u8>, Error>
48where
49 T: serde::Serialize,
50{
51 let mut writer = Vec::new();
52 to_writer(&mut writer, value)?;
53 Ok(writer)
54}
55
56pub fn to_string<T: Sized>(value: &T) -> Result<String, Error>
58where
59 T: serde::Serialize,
60{
61 Ok(unsafe { String::from_utf8_unchecked(to_vec(value)?) })
62}
63
64fn canonicalize(val: &serde_json::Value) -> Result<Vec<u8>, Error> {
65 let cv = from_value(val)?;
66 let mut buf = Vec::new();
67 let _ = cv.write(&mut buf);
68 Ok(buf)
69}
70
71enum CanonicalValue {
72 Null,
73 Bool(bool),
74 Number(Number),
75 String(String),
76 Array(Vec<CanonicalValue>),
77 Object(BTreeMap<String, CanonicalValue>),
78}
79
80enum Number {
81 I64(i64),
82}
83
84impl CanonicalValue {
85 fn write(&self, mut buf: &mut Vec<u8>) -> Result<(), Error> {
86 match *self {
87 CanonicalValue::Null => {
88 buf.extend(b"null");
89 Ok(())
90 }
91 CanonicalValue::Bool(true) => {
92 buf.extend(b"true");
93 Ok(())
94 }
95 CanonicalValue::Bool(false) => {
96 buf.extend(b"false");
97 Ok(())
98 }
99 CanonicalValue::Number(Number::I64(n)) => match itoa::write(buf, n) {
100 Ok(_) => Ok(()),
101 Err(err) => Err(Error::Custom(format!("cannot write number: {}", err))),
102 },
103 CanonicalValue::String(ref s) => {
104 let s = serde_json::to_string(&Value::String(s.clone()))?;
105 buf.extend(s.as_bytes());
106 Ok(())
107 }
108 CanonicalValue::Array(ref arr) => {
109 buf.push(b'[');
110 let mut first = true;
111 for a in arr.iter() {
112 if !first {
113 buf.push(b',');
114 }
115 a.write(&mut buf)?;
116 first = false;
117 }
118 buf.push(b']');
119 Ok(())
120 }
121 CanonicalValue::Object(ref obj) => {
122 buf.push(b'{');
123 let mut first = true;
124 for (k, v) in obj.iter() {
125 if !first {
126 buf.push(b',');
127 }
128 first = false;
129 let k = serde_json::to_string(&Value::String(k.clone()))?;
130 buf.extend(k.as_bytes());
131 buf.push(b':');
132 v.write(&mut buf)?;
133 }
134 buf.push(b'}');
135 Ok(())
136 }
137 }
138 }
139}
140
141fn from_value(val: &Value) -> Result<CanonicalValue, Error> {
142 match *val {
143 Value::Null => Ok(CanonicalValue::Null),
144 Value::Bool(b) => Ok(CanonicalValue::Bool(b)),
145 Value::Number(ref n) => {
146 let x = n.as_i64();
147 match x {
148 Some(x) => Ok(CanonicalValue::Number(Number::I64(x))),
149 None => Err(Error::Custom(String::from(format!(
150 "unsupported value in canonical JSON: {}",
151 n
152 )))),
153 }
154 }
155 Value::String(ref s) => Ok(CanonicalValue::String(s.clone())),
156 Value::Array(ref arr) => {
157 let mut out = Vec::new();
158 for res in arr.iter().map(|v| from_value(v)) {
159 out.push(res?)
160 }
161 Ok(CanonicalValue::Array(out))
162 }
163 Value::Object(ref obj) => {
164 let mut out = BTreeMap::new();
165 for (k, v) in obj.iter() {
166 let _ = out.insert(k.clone(), from_value(v)?);
167 }
168 Ok(CanonicalValue::Object(out))
169 }
170 }
171}
172
173#[derive(Debug)]
176pub enum Error {
177 Custom(String),
179 Io(io::Error),
181}
182
183impl From<serde_json::Error> for Error {
184 fn from(err: serde_json::Error) -> Error {
185 use serde_json::error::Category;
186 match err.classify() {
187 Category::Io => Error::Io(err.into()),
188 Category::Syntax | Category::Data | Category::Eof => {
189 Error::Custom(String::from(format!("{}", err)))
190 }
191 }
192 }
193}
194
195impl From<io::Error> for Error {
196 fn from(error: io::Error) -> Error {
197 Error::Io(error)
198 }
199}