1use bigdecimal::BigDecimal;
2use chrono::{DateTime, Utc};
3use prost_types;
4use prost_types::{Timestamp, Value};
5use serde::{Deserialize, Serialize};
6use serde_json::Value as JsonValue;
7use std::cmp::Eq;
8use std::collections::HashMap;
9use std::hash::Hash;
10
11use crate::result::{self, Result};
12use crate::{ProtoPack, ProtoUnpack};
13
14macro_rules! impl_option {
15 ($rust:ty => $proto:ty) => {
16 impl ProtoPack<Option<$proto>> for $rust {
17 fn pack(self) -> Result<Option<$proto>> {
18 Ok(Some(self.pack()?))
19 }
20 }
21
22 impl ProtoUnpack<Option<$proto>> for $rust {
23 fn unpack(value: Option<$proto>) -> Result<$rust> {
24 if let Some(value) = value {
25 Ok(<$rust>::unpack(value)?)
26 } else {
27 Err(result::Error::ValueNotPresent)
28 }
29 }
30 }
31 };
32}
33
34impl ProtoPack<Value> for JsonValue {
37 fn pack(self) -> Result<Value> {
38 json_value_to_value(self)
39 }
40}
41
42impl ProtoUnpack<Value> for JsonValue {
43 fn unpack(value: Value) -> Result<JsonValue> {
44 value_to_json_value(value)
45 }
46}
47
48impl_option!(JsonValue => Value);
49
50const MAX_JSON_NEST: usize = 100;
51
52fn value_to_json_value(value: Value) -> Result<JsonValue> {
53 fn convert(nest: usize, value: Value) -> Result<JsonValue> {
54 use prost_types::{value::Kind, ListValue, Struct};
55 use serde_json::{Map as JsonMap, Number as JsonNumber};
56
57 if nest >= MAX_JSON_NEST {
58 return Err(result::Error::JsonValueNestedTooDeeply);
59 }
60
61 if let Some(kind) = value.kind {
62 let converted = match kind {
63 Kind::NullValue(_) => JsonValue::Null,
64 Kind::NumberValue(v) => {
65 if let Some(number) = JsonNumber::from_f64(v) {
66 JsonValue::Number(number)
67 } else {
68 JsonValue::Null
69 }
70 }
71 Kind::StringValue(v) => JsonValue::String(v),
72 Kind::BoolValue(v) => JsonValue::Bool(v),
73 Kind::StructValue(Struct { fields }) => JsonValue::Object({
74 let mut json_map = JsonMap::with_capacity(fields.len());
75 for (k, v) in fields {
76 json_map.insert(k, convert(nest + 1, v)?);
77 }
78 json_map
79 }),
80 Kind::ListValue(ListValue { values }) => {
81 let mut json_values = Vec::with_capacity(values.len());
82 for v in values {
83 json_values.push(convert(nest + 1, v)?);
84 }
85 JsonValue::Array(json_values)
86 }
87 };
88 Ok(converted)
89 } else {
90 Ok(JsonValue::Null)
91 }
92 }
93
94 convert(0, value)
95}
96
97fn json_value_to_value(value: JsonValue) -> Result<Value> {
98 fn convert(nest: usize, value: JsonValue) -> Result<Value> {
99 use prost_types::{value::Kind, ListValue, Struct};
100 use std::collections::BTreeMap;
101
102 if nest >= MAX_JSON_NEST {
103 return Err(result::Error::JsonValueNestedTooDeeply);
104 }
105
106 let kind = match value {
107 JsonValue::Null => Kind::NullValue(0),
108 JsonValue::Bool(v) => Kind::BoolValue(v),
109 JsonValue::Number(v) => {
110 if let Some(v) = v.as_f64() {
111 Kind::NumberValue(v)
112 } else {
113 Kind::NullValue(0)
114 }
115 }
116 JsonValue::String(v) => Kind::StringValue(v),
117 JsonValue::Array(values) => {
118 let mut value_values = Vec::with_capacity(values.len());
119 for v in values {
120 value_values.push(convert(nest + 1, v)?);
121 }
122 Kind::ListValue(ListValue {
123 values: value_values,
124 })
125 }
126 JsonValue::Object(map) => {
127 let mut value_map = BTreeMap::new();
128 for (k, v) in map {
129 value_map.insert(k, convert(nest + 1, v)?);
130 }
131 Kind::StructValue(Struct { fields: value_map })
132 }
133 };
134 Ok(Value { kind: Some(kind) })
135 }
136
137 convert(0, value)
138}
139
140pub struct Json<T>(pub T);
142
143impl<T> ProtoPack<Value> for Json<T>
144where
145 T: Serialize + for<'de> Deserialize<'de>,
146{
147 fn pack(self) -> Result<Value> {
148 pack_value(self.0)
149 }
150}
151
152impl<T> ProtoUnpack<Value> for Json<T>
153where
154 T: Serialize + for<'de> Deserialize<'de>,
155{
156 fn unpack(value: Value) -> Result<Json<T>> {
157 unpack_value(value).map(Json)
158 }
159}
160
161pub fn pack_value<T>(value: T) -> Result<Value>
162where
163 T: Serialize,
164{
165 serde_json::to_value(&value)?.pack()
166}
167
168pub fn unpack_value<T>(value: Value) -> Result<T>
169where
170 T: for<'de> Deserialize<'de>,
171{
172 let value = JsonValue::unpack(value)?;
173 Ok(serde_json::from_value(value)?)
174}
175
176impl ProtoPack<Timestamp> for DateTime<Utc> {
179 fn pack(self) -> Result<Timestamp> {
180 Ok(Timestamp {
181 seconds: self.timestamp(),
182 nanos: self.timestamp_subsec_nanos() as i32,
183 })
184 }
185}
186
187impl ProtoUnpack<Timestamp> for DateTime<Utc> {
188 fn unpack(Timestamp { seconds, nanos }: Timestamp) -> Result<DateTime<Utc>> {
189 let dt = chrono::NaiveDateTime::from_timestamp(seconds, nanos as u32);
190 Ok(DateTime::from_utc(dt, Utc))
191 }
192}
193
194impl ProtoPack<prost_types::Duration> for chrono::Duration {
197 fn pack(self) -> Result<prost_types::Duration> {
198 let duration = <prost_types::Duration as TryFrom<std::time::Duration>>::try_from(
199 self.to_std().map_err(|e| result::Error::ParseDuration {
200 message: e.to_string(),
201 })?,
202 )
203 .map_err(|e| result::Error::ParseDuration {
204 message: e.to_string(),
205 })?;
206
207 Ok(duration)
208 }
209}
210
211impl ProtoUnpack<prost_types::Duration> for chrono::Duration {
212 fn unpack(value: prost_types::Duration) -> Result<chrono::Duration> {
213 let std_duration = <prost_types::Duration as TryInto<std::time::Duration>>::try_into(value)
214 .map_err(|e| result::Error::ParseDuration {
215 message: format!(
216 "Source duration value is out of range for the target type: {}",
217 e.to_string()
218 ),
219 })?;
220
221 chrono::Duration::from_std(std_duration).map_err(|e| result::Error::ParseDuration {
222 message: e.to_string(),
223 })
224 }
225}
226
227impl_option!(DateTime<Utc> => Timestamp);
228impl_option!(chrono::Duration => prost_types::Duration);
229
230impl ProtoPack<String> for BigDecimal {
233 fn pack(self) -> Result<String> {
234 Ok(self.to_string())
235 }
236}
237
238impl<T> ProtoUnpack<T> for BigDecimal
239where
240 T: AsRef<str>,
241{
242 fn unpack(v: T) -> Result<BigDecimal> {
243 v.as_ref().parse().map_err(Into::into)
244 }
245}
246
247macro_rules! impl_self {
250 (
251 $($ty:ty),*
252 ) => {
253 $(
254 impl ProtoPack<$ty> for $ty {
255 fn pack(self) -> Result<$ty> {
256 Ok(self)
257 }
258 }
259
260 impl ProtoUnpack<$ty> for $ty {
261 fn unpack(value: $ty) -> Result<$ty> {
262 Ok(value)
263 }
264 }
265 )*
266 }
267}
268
269impl_self! {
270 f32,
271 f64,
272 i64,
273 u64,
274 i32,
275 u32,
276 bool,
277 String,
278 Vec<u8>
279}
280
281impl<T, T2> ProtoPack<Vec<T>> for Vec<T2>
284where
285 T2: ProtoPack<T>,
286{
287 fn pack(self) -> Result<Vec<T>> {
288 let mut r = vec![];
289 for (i, elem) in self.into_iter().enumerate() {
290 let item = elem.pack().map_err(|e| result::Error::ListElement {
291 source: Box::new(e),
292 index: i,
293 })?;
294 r.push(item);
295 }
296 Ok(r)
297 }
298}
299
300impl<T, T2> ProtoUnpack<Vec<T>> for Vec<T2>
301where
302 T2: ProtoUnpack<T>,
303{
304 fn unpack(value: Vec<T>) -> Result<Vec<T2>> {
305 let mut r = vec![];
306 for (i, elem) in value.into_iter().enumerate() {
307 let item = T2::unpack(elem).map_err(|e| result::Error::ListElement {
308 source: Box::new(e),
309 index: i,
310 })?;
311 r.push(item);
312 }
313 Ok(r)
314 }
315}
316
317impl<K, V, K2, V2> ProtoPack<HashMap<K, V>> for HashMap<K2, V2>
320where
321 K: Eq + Hash,
322 K2: ProtoPack<K> + Eq + Hash,
323 V2: ProtoPack<V>,
324{
325 fn pack(self) -> Result<HashMap<K, V>> {
326 let mut r = vec![];
327 for (k, v) in self.into_iter() {
328 let k2 = k.pack().map_err(|e| result::Error::MapEntry {
329 source: Box::new(e),
330 })?;
331 let v2 = v.pack().map_err(|e| result::Error::MapEntry {
332 source: Box::new(e),
333 })?;
334 r.push((k2, v2));
335 }
336 Ok(r.into_iter().collect())
337 }
338}
339
340impl<K, V, K2, V2> ProtoUnpack<HashMap<K, V>> for HashMap<K2, V2>
341where
342 K: Eq + Hash,
343 K2: ProtoUnpack<K> + Eq + Hash,
344 V2: ProtoUnpack<V>,
345{
346 fn unpack(value: HashMap<K, V>) -> Result<HashMap<K2, V2>> {
347 let mut r = vec![];
348 for (k, v) in value.into_iter() {
349 let k2 = K2::unpack(k).map_err(|e| result::Error::MapEntry {
350 source: Box::new(e),
351 })?;
352 let v2 = V2::unpack(v).map_err(|e| result::Error::MapEntry {
353 source: Box::new(e),
354 })?;
355 r.push((k2, v2));
356 }
357 Ok(r.into_iter().collect())
358 }
359}