rhaki_cw_plus/
serde_value.rs

1use {
2    crate::{
3        encdec::{self, base64_encode},
4        traits::IntoStdResult,
5    },
6    cosmwasm_schema::cw_serde,
7    cosmwasm_std::{CosmosMsg, StdError, StdResult},
8    serde::{de::DeserializeOwned, Deserialize, Serialize},
9    std::{collections::HashMap, fmt::Debug, hash::Hash},
10};
11
12pub use {
13    serde_cw_value::Value,
14    serde_json::{json, Value as StdValue},
15    serde_json_wasm::{from_str as sjw_from_str, to_string as sjw_to_string, to_vec as sjw_to_vec},
16};
17
18#[cw_serde]
19pub enum PathKey {
20    Index(u64),
21    Key(String),
22}
23
24/// `Serialize` a `serde_cw_value::Value` to `String`
25pub fn value_to_string(value: &Value) -> StdResult<String> {
26    sjw_to_string(&value).into_std_result()
27}
28
29/// `Deserialize` a `String` into `serde_cw_value::Value`
30pub fn value_from_string(string: &str) -> StdResult<Value> {
31    serde_json_wasm::from_slice(
32        serde_json_wasm::to_vec(string)
33            .into_std_result()?
34            .as_slice(),
35    )
36    .into_std_result()
37}
38
39/// `Deserialize` a `String` in `base64` into `serde_cw_value::Value`
40pub fn value_from_b64(b64_string: &str) -> StdResult<Value> {
41    value_from_string(&encdec::base64_decode_as_string(b64_string)?)
42}
43
44pub fn value_to_b64_string(value: &Value) -> StdResult<String> {
45    Ok(base64_encode(&value_to_string(value)?))
46}
47
48/// Parse a `serde_json::Value` into `serde_json_wasm::Value`
49pub fn std_to_sjw_value(std_value: StdValue) -> StdResult<Value> {
50    sjw_from_str::<Value>(&std_value.to_string()).into_std_result()
51}
52
53/// Parse a `Value` into a CosmosMsg
54pub fn value_to_comsos_msg(value: &Value) -> StdResult<CosmosMsg> {
55    value.clone().deserialize_into().into_std_result()
56}
57
58pub trait SerdeValue {
59    fn from_b64(encoded_b64: impl Into<String>) -> StdResult<Value>;
60    fn from_string(string: impl Into<String>) -> StdResult<Value>;
61    fn as_string(&self) -> StdResult<String>;
62    fn to_cosmos_msg(&self) -> StdResult<CosmosMsg>;
63    fn to_b64_encoded(&self) -> StdResult<String>;
64    fn get_value_by_path<C: DeserializeOwned>(&self, path_key: Vec<PathKey>) -> StdResult<C>;
65    fn get_array_index(&self, index: impl Into<usize>) -> StdResult<Value>;
66    fn get_map_value(&self, value: impl Into<Value> + Clone) -> StdResult<Value>;
67}
68
69impl SerdeValue for Value {
70    fn from_b64(encoded_b64: impl Into<String>) -> StdResult<Value> {
71        value_from_b64(&encoded_b64.into())
72    }
73
74    fn from_string(string: impl Into<String>) -> StdResult<Value> {
75        value_from_string(&string.into())
76    }
77
78    fn as_string(&self) -> StdResult<String> {
79        value_to_string(self)
80    }
81
82    fn to_cosmos_msg(&self) -> StdResult<CosmosMsg> {
83        value_to_comsos_msg(self)
84    }
85
86    fn to_b64_encoded(&self) -> StdResult<String> {
87        value_to_b64_string(self)
88    }
89
90    fn get_value_by_path<C: DeserializeOwned>(&self, path_key: Vec<PathKey>) -> StdResult<C> {
91        let mut value = self.clone();
92        for k in path_key {
93            match k {
94                PathKey::Index(index) => match value {
95                    Value::Seq(val) => value = val[index as usize].clone(),
96                    _ => panic!(),
97                },
98                PathKey::Key(key) => match value {
99                    Value::Map(val) => value = val[&Value::from_string(key).unwrap()].clone(),
100                    _ => panic!(),
101                },
102            }
103        }
104        serde_json_wasm::from_slice(
105            serde_json_wasm::to_vec(&value)
106                .into_std_result()?
107                .as_slice(),
108        )
109        .into_std_result()
110        // Ok(value)
111    }
112
113    fn get_array_index(&self, index: impl Into<usize>) -> StdResult<Value> {
114        if let Value::Seq(array) = self {
115            Ok(array[index.into()].clone())
116        } else {
117            Err(StdError::generic_err(format!(
118                "Value is not a Seq: {:?}",
119                self
120            )))
121        }
122    }
123
124    fn get_map_value(&self, value: impl Into<Value> + Clone) -> StdResult<Value> {
125        if let Value::Map(map) = self {
126            map.get(&value.clone().into())
127                .map(|val| val.clone())
128                .ok_or(StdError::generic_err(format!(
129                    "map key not found: {:?}",
130                    value.into()
131                )))
132        } else {
133            Err(StdError::generic_err(format!(
134                "Value is not a Map: {:?}",
135                self
136            )))
137        }
138    }
139}
140
141pub trait SerdeMapSerializer<V> {
142    fn into_json_ser_map(self) -> HashMap<String, V>;
143}
144
145impl<K, V> SerdeMapSerializer<V> for HashMap<K, V>
146where
147    K: Into<String> + Clone,
148    V: Clone,
149{
150    fn into_json_ser_map(self) -> HashMap<String, V> {
151        let mut map: HashMap<String, V> = HashMap::new();
152
153        for (k, v) in self {
154            map.insert(Into::<String>::into(k.clone()), v.clone());
155        }
156
157        map
158    }
159}
160
161#[allow(clippy::wrong_self_convention)]
162pub trait SerdeMapDeserialize<V, K: TryFrom<String>> {
163    fn from_json_ser_map(self) -> Result<HashMap<K, V>, K::Error>;
164}
165
166impl<K, V> SerdeMapDeserialize<V, K> for HashMap<String, V>
167where
168    K: TryFrom<String> + Eq + PartialEq + Hash + Debug,
169    V: Clone,
170{
171    fn from_json_ser_map(self) -> Result<HashMap<K, V>, K::Error> {
172        let mut map: HashMap<K, V> = HashMap::new();
173
174        for (k, v) in self {
175            let b = K::try_from(Into::<String>::into(k.clone()))?;
176            map.insert(b, v.clone());
177        }
178
179        Ok(map)
180    }
181}
182
183pub trait ToCwJson {
184    fn into_cw(&self) -> StdResult<Value>;
185}
186
187impl ToCwJson for StdValue {
188    fn into_cw(&self) -> StdResult<Value> {
189        std_to_sjw_value(self.clone())
190    }
191}
192
193pub trait DoubleDeserialize {
194    fn double_deserialize<'de, F: Deserialize<'de>, S: Deserialize<'de>>(
195        &self,
196    ) -> StdResult<DoubleValueDeserializeResult<F, S>>;
197}
198
199impl DoubleDeserialize for Value {
200    fn double_deserialize<'de, F: Deserialize<'de>, S: Deserialize<'de>>(
201        &self,
202    ) -> StdResult<DoubleValueDeserializeResult<F, S>> {
203        if let Ok(res) = self.clone().deserialize_into() {
204            return Ok(DoubleValueDeserializeResult::First(res));
205        }
206
207        if let Ok(res) = self.clone().deserialize_into() {
208            return Ok(DoubleValueDeserializeResult::Second(res));
209        }
210
211        Err(StdError::generic_err("Deserialize failed"))
212    }
213}
214
215#[cw_serde]
216pub enum DoubleValueDeserializeResult<F, S> {
217    First(F),
218    Second(S),
219}
220
221impl<'de, F, S> DoubleValueDeserializeResult<F, S>
222where
223    F: Deserialize<'de>,
224    S: Deserialize<'de>,
225{
226}
227
228#[allow(clippy::wrong_self_convention)]
229pub trait IntoSerdeJsonString: Serialize {
230    fn into_json_string(&self) -> StdResult<String> {
231        serde_json_wasm::to_string(self).into_std_result()
232    }
233}
234
235impl<T: Serialize> IntoSerdeJsonString for Option<T> {}