1use ::serde::{Deserialize, Deserializer, Serialize, Serializer};
2use chrono::{DateTime, Utc};
3use cosmwasm_std::StdResult;
4use serde::de;
5use serde::de::Visitor;
6
7use std::fmt;
8use std::str::FromStr;
9
10#[derive(Clone, PartialEq, Eq, ::prost::Message, schemars::JsonSchema)]
11pub struct Timestamp {
12 #[prost(int64, tag = "1")]
16 pub seconds: i64,
17 #[prost(int32, tag = "2")]
22 pub nanos: i32,
23}
24
25impl Serialize for Timestamp {
26 fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
27 where
28 S: Serializer,
29 {
30 let mut ts = prost_types::Timestamp {
31 seconds: self.seconds,
32 nanos: self.nanos,
33 };
34 ts.normalize();
35 let dt = DateTime::from_timestamp(ts.seconds, ts.nanos as u32)
36 .expect("invalid or out-of-range datetime");
37 serializer.serialize_str(format!("{:?}", dt).as_str())
38 }
39}
40
41impl<'de> Deserialize<'de> for Timestamp {
42 fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
43 where
44 D: Deserializer<'de>,
45 {
46 struct TimestampVisitor;
47
48 impl<'de> Visitor<'de> for TimestampVisitor {
49 type Value = Timestamp;
50
51 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
52 formatter.write_str("Timestamp in RFC3339 format")
53 }
54
55 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
56 where
57 E: de::Error,
58 {
59 let utc: DateTime<Utc> = chrono::DateTime::from_str(value).map_err(|err| {
60 serde::de::Error::custom(format!(
61 "Failed to parse {} as datetime: {:?}",
62 value, err
63 ))
64 })?;
65 let ts = Timestamp::from(utc);
66 Ok(ts)
67 }
68 }
69 deserializer.deserialize_str(TimestampVisitor)
70 }
71}
72
73impl From<DateTime<Utc>> for Timestamp {
74 fn from(dt: DateTime<Utc>) -> Self {
75 Timestamp {
76 seconds: dt.timestamp(),
77 nanos: dt.timestamp_subsec_nanos() as i32,
78 }
79 }
80}
81#[derive(Clone, PartialEq, Eq, ::prost::Message, schemars::JsonSchema)]
82pub struct Duration {
83 #[prost(int64, tag = "1")]
87 pub seconds: i64,
88 #[prost(int32, tag = "2")]
95 pub nanos: i32,
96}
97
98impl Serialize for Duration {
99 fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
100 where
101 S: Serializer,
102 {
103 let mut d = prost_types::Duration::from(self.to_owned());
104 d.normalize();
105
106 serializer.serialize_str(d.to_string().as_str())
107 }
108}
109
110impl<'de> Deserialize<'de> for Duration {
111 fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
112 where
113 D: Deserializer<'de>,
114 {
115 struct DurationVisitor;
116
117 impl<'de> Visitor<'de> for DurationVisitor {
118 type Value = Duration;
119
120 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
121 formatter.write_str("Timestamp in RFC3339 format")
122 }
123
124 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
125 where
126 E: de::Error,
127 {
128 value
129 .parse::<prost_types::Duration>()
130 .map(Into::into)
131 .map_err(de::Error::custom)
132 }
133 }
134 deserializer.deserialize_str(DurationVisitor)
135 }
136}
137
138#[derive(Clone, PartialEq, Eq, ::prost::Message, schemars::JsonSchema)]
139pub struct Any {
140 #[prost(string, tag = "1")]
169 pub type_url: ::prost::alloc::string::String,
170 #[prost(bytes = "vec", tag = "2")]
172 pub value: ::prost::alloc::vec::Vec<u8>,
173}
174
175macro_rules! expand_as_any {
176 ($($ty:path,)*) => {
177
178 impl Serialize for Any {
180 fn serialize<S>(
181 &self,
182 _serializer: S,
183 ) -> Result<<S as ::serde::Serializer>::Ok, <S as ::serde::Serializer>::Error>
184 where
185 S: ::serde::Serializer,
186 {
187 $(
188 if self.type_url == <$ty>::TYPE_URL {
189 let value: Result<$ty, <S as ::serde::Serializer>::Error> =
190 prost::Message::decode(self.value.as_slice()).map_err(ser::Error::custom);
191
192 if let Ok(value) = value {
193 return value.serialize(serializer);
194 }
195 }
196 )*
197
198 Err(serde::ser::Error::custom(
199 "data did not match any type that supports serialization as `Any`",
200 ))
201 }
202 }
203
204 impl<'de> Deserialize<'de> for Any {
205 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
206 where
207 D: serde::Deserializer<'de>,
208 {
209 let value = match serde_cw_value::Value::deserialize(deserializer) {
210 Ok(value) => value,
211 Err(err) => {
212 return Err(err);
213 }
214 };
215
216 let type_url = if let serde_cw_value::Value::Map(m) = value.clone() {
218 m.get(&serde_cw_value::Value::String("@type".to_string()))
219 .map(|t| match t.to_owned() {
220 serde_cw_value::Value::String(s) => Ok(s),
221 _ => Err(serde::de::Error::custom("type_url must be String")),
222 })
223 .transpose()
224 } else {
225 Err(serde::de::Error::custom("data must have map structure"))
226 }?;
227
228 match type_url {
229 Some(_) => {
231 $(
232 if t == <$ty>::TYPE_URL {
233 return <$ty>::deserialize(
234 serde_cw_value::ValueDeserializer::<serde_cw_value::DeserializerError>::new(
235 value.clone(),
236 ),
237 )
238 .map(|v| Any {
239 type_url: <$ty>::TYPE_URL.to_string(),
240 value: v.encode_to_vec(),
241 })
242 .map_err(serde::de::Error::custom);
243 }
244 )*
245 }
246 None => {
248 $(
249 if let Ok(v) = <$ty>::deserialize(
250 serde_cw_value::ValueDeserializer::<serde_cw_value::DeserializerError>::new(
251 value.clone(),
252 ),
253 ) {
254 return Ok(Any {
255 type_url: <$ty>::TYPE_URL.to_string(),
256 value: v.encode_to_vec(),
257 });
258 }
259 )*
260 }
261 };
262
263 Err(serde::de::Error::custom(
264 "data did not match any type that supports deserialization as `Any`",
265 ))
266 }
267 }
268
269 $(
270 impl TryFrom<Any> for $ty {
271 type Error = prost::DecodeError;
272
273 fn try_from(value: Any) -> Result<Self, Self::Error> {
274 prost::Message::decode(value.value.as_slice())
275 }
276 }
277 )*
278 };
279}
280
281expand_as_any!();
286
287macro_rules! impl_prost_types_exact_conversion {
288 ($t:ident | $($arg:ident),*) => {
289 impl From<$t> for prost_types::$t {
290 fn from(src: $t) -> Self {
291 prost_types::$t {
292 $(
293 $arg: src.$arg,
294 )*
295 }
296 }
297 }
298
299 impl From<prost_types::$t> for $t {
300 fn from(src: prost_types::$t) -> Self {
301 $t {
302 $(
303 $arg: src.$arg,
304 )*
305 }
306 }
307 }
308 };
309}
310
311impl_prost_types_exact_conversion! { Timestamp | seconds, nanos }
312impl_prost_types_exact_conversion! { Duration | seconds, nanos }
313impl_prost_types_exact_conversion! { Any | type_url, value }
314
315impl From<cosmwasm_std::Coin> for crate::types::cosmos::base::v1beta1::Coin {
316 fn from(cosmwasm_std::Coin { denom, amount }: cosmwasm_std::Coin) -> Self {
317 crate::types::cosmos::base::v1beta1::Coin {
318 denom,
319 amount: amount.into(),
320 }
321 }
322}
323
324impl TryFrom<crate::types::cosmos::base::v1beta1::Coin> for cosmwasm_std::Coin {
325 type Error = cosmwasm_std::StdError;
326
327 fn try_from(
328 crate::types::cosmos::base::v1beta1::Coin { denom, amount }: crate::types::cosmos::base::v1beta1::Coin,
329 ) -> cosmwasm_std::StdResult<Self> {
330 Ok(cosmwasm_std::Coin {
331 denom,
332 amount: amount.parse()?,
333 })
334 }
335}
336
337pub fn try_proto_to_cosmwasm_coins(
339 coins: impl IntoIterator<Item = crate::types::cosmos::base::v1beta1::Coin>,
340) -> StdResult<Vec<cosmwasm_std::Coin>> {
341 coins.into_iter().map(|c| c.try_into()).collect()
342}
343
344pub fn cosmwasm_to_proto_coins(
346 coins: impl IntoIterator<Item = cosmwasm_std::Coin>,
347) -> Vec<crate::types::cosmos::base::v1beta1::Coin> {
348 coins.into_iter().map(|c| c.into()).collect()
349}
350
351#[cfg(test)]
352mod tests {
353 use cosmwasm_std::Uint128;
354
355 use super::*;
356
357 #[test]
358 fn test_coins_conversion() {
359 let coins = vec![
360 cosmwasm_std::Coin {
361 denom: "uatom".to_string(),
362 amount: Uint128::new(100),
363 },
364 cosmwasm_std::Coin {
365 denom: "uosmo".to_string(),
366 amount: Uint128::new(200),
367 },
368 ];
369
370 let proto_coins = cosmwasm_to_proto_coins(coins.clone());
371 let cosmwasm_coins = try_proto_to_cosmwasm_coins(proto_coins).unwrap();
372
373 assert_eq!(coins, cosmwasm_coins);
374 }
375}