rhaki_cw_plus/
traits.rs

1use {
2    cosmwasm_std::{from_json, to_json_binary, Addr, Api, Binary, StdError, StdResult},
3    serde::{de::DeserializeOwned, Serialize},
4    std::{cmp::min, error::Error},
5};
6
7pub trait IntoAddr: Into<String> + Clone {
8    fn into_addr(self, api: &dyn Api) -> StdResult<Addr> {
9        api.addr_validate(&self.into())
10    }
11    fn into_unchecked_addr(&self) -> Addr {
12        Addr::unchecked(self.clone())
13    }
14}
15
16impl<T> IntoAddr for T where T: Into<String> + Clone {}
17
18pub trait IntoBinaryResult {
19    /// `Serialize` into `Binary`
20    fn into_binary(self) -> StdResult<Binary>;
21}
22
23impl<T> IntoBinaryResult for StdResult<T>
24where
25    T: Serialize,
26{
27    fn into_binary(self) -> StdResult<Binary> {
28        to_json_binary(&self?)
29    }
30}
31
32pub trait IntoBinary {
33    /// `Serialize` into `Binary`
34    fn into_binary(self) -> StdResult<Binary>;
35}
36
37impl<T> IntoBinary for T
38where
39    T: Serialize,
40{
41    fn into_binary(self) -> StdResult<Binary> {
42        to_json_binary(&self)
43    }
44}
45
46pub trait FromBinaryResult {
47    /// `Deserialize` `StdResult<Binary>` into specified `Struct`/`Enum`. It must to implement `DeserializeOwned`
48    fn des_into<T: DeserializeOwned>(self) -> StdResult<T>;
49}
50
51impl FromBinaryResult for StdResult<Binary> {
52    fn des_into<T: DeserializeOwned>(self) -> StdResult<T> {
53        from_json(&self?)
54    }
55}
56
57pub trait FromBinary {
58    /// `Deserialize` `Binary` into specified `Struct`/`Enum`. It must to implement `DeserializeOwned`
59    fn des_into<T: DeserializeOwned>(self) -> StdResult<T>;
60}
61
62impl FromBinary for Binary {
63    fn des_into<T: DeserializeOwned>(self) -> StdResult<T> {
64        from_json(&self)
65    }
66}
67
68pub trait IntoStdResult<T> {
69    fn into_std_result(self) -> StdResult<T>;
70}
71impl<T, E> IntoStdResult<T> for Result<T, E>
72where
73    E: std::error::Error,
74{
75    fn into_std_result(self) -> StdResult<T> {
76        self.map_err(|err| StdError::generic_err(err.to_string()))
77    }
78}
79
80pub trait MapMin {
81    type Output;
82    type Input;
83    fn map_min(&self, with: Self::Input) -> Self::Output;
84}
85
86impl<T: Ord + Copy> MapMin for Option<T> {
87    type Output = Option<T>;
88    type Input = T;
89
90    fn map_min(&self, with: Self::Input) -> Self::Output {
91        self.map(|val| min(val, with))
92    }
93}
94
95pub trait AssertOwner {
96    fn get_admin(&self) -> Addr;
97
98    fn assert_admin(&self, address: Addr) -> StdResult<()> {
99        if self.get_admin() != address {
100            return Err(StdError::generic_err("Unauthorized"));
101        }
102
103        Ok(())
104    }
105}
106
107pub trait Unclone {
108    type Output;
109    fn unclone(&self) -> Self::Output;
110}
111
112impl<T> Unclone for Option<T>
113where
114    T: Clone,
115{
116    type Output = T;
117
118    fn unclone(&self) -> Self::Output {
119        self.clone().unwrap()
120    }
121}
122
123pub trait Wrapper: Sized {
124    /// Wrap `self` into `Ok(self)`
125    fn wrap_ok<E: Error>(self) -> Result<Self, E> {
126        Ok(self)
127    }
128
129    fn wrap_some(self) -> Option<Self> {
130        Some(self)
131    }
132}
133
134impl<T> Wrapper for T {}
135
136#[cfg(test)]
137mod test {
138    use cosmwasm_std::{testing::mock_dependencies, Addr, Coin, StdError};
139
140    use crate::traits::{FromBinary, FromBinaryResult, IntoAddr, IntoBinary, IntoBinaryResult};
141
142    #[test]
143    fn test() {
144        let coin = Coin::new(1, "asd");
145
146        let coin_binary = coin.clone().into_binary().unwrap();
147
148        let res_binary = Ok::<_, StdError>(coin.clone()).into_binary().unwrap();
149
150        let coin_std: Coin = coin_binary.des_into().unwrap();
151        let coin_res = Ok(res_binary).des_into::<Coin>().unwrap();
152
153        assert_eq!(coin_std, coin);
154        assert_eq!(coin_res, coin);
155
156        assert_eq!(
157            Addr::unchecked("terra123"),
158            "terra123".into_unchecked_addr()
159        );
160        assert_eq!(
161            Addr::unchecked("terra123"),
162            "terra123".to_string().into_unchecked_addr()
163        );
164
165        let deps = mock_dependencies();
166
167        assert_eq!(
168            Addr::unchecked("terra123"),
169            "terra123".into_addr(&deps.api).unwrap()
170        );
171        assert_eq!(
172            Addr::unchecked("terra123"),
173            "terra123".to_string().into_addr(&deps.api).unwrap()
174        );
175    }
176}