abstract_os/objects/
asset_entry.rs

1use cosmwasm_std::StdResult;
2use cw_storage_plus::{Key, KeyDeserialize, Prefixer, PrimaryKey};
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5use std::fmt::Display;
6
7pub const CHAIN_DELIMITER: &str = ">";
8
9/// May key to retrieve information on an asset
10#[derive(
11    Deserialize, Serialize, Clone, Debug, PartialEq, Eq, JsonSchema, PartialOrd, Ord, Default,
12)]
13pub struct AssetEntry(pub(crate) String);
14
15impl AssetEntry {
16    pub fn new(entry: &str) -> Self {
17        Self(str::to_ascii_lowercase(entry))
18    }
19    pub fn as_str(&self) -> &str {
20        &self.0
21    }
22    pub fn format(&mut self) {
23        self.0 = self.0.to_ascii_lowercase();
24    }
25
26    /// Retrieve the source chain of the asset
27    /// Example: osmosis>juno>crab returns osmosis
28    /// Returns string to remain consistent with [`Self::asset_name`]
29    pub fn src_chain(&self) -> String {
30        self.0
31            .split(CHAIN_DELIMITER)
32            .next()
33            .unwrap_or("")
34            .to_string()
35    }
36
37    /// Retrieve the asset name without the src chain
38    /// Example: osmosis>juno>crab returns juno>crab
39    pub fn asset_name(&self) -> String {
40        self.0
41            .split(CHAIN_DELIMITER)
42            .skip(1)
43            .collect::<Vec<&str>>()
44            .join(CHAIN_DELIMITER)
45    }
46}
47
48impl From<&str> for AssetEntry {
49    fn from(entry: &str) -> Self {
50        Self::new(entry)
51    }
52}
53
54impl From<String> for AssetEntry {
55    fn from(entry: String) -> Self {
56        Self::new(&entry)
57    }
58}
59
60impl From<&String> for AssetEntry {
61    fn from(entry: &String) -> Self {
62        Self::new(entry)
63    }
64}
65
66impl Display for AssetEntry {
67    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68        write!(f, "{}", self.0)
69    }
70}
71
72impl<'a> PrimaryKey<'a> for &AssetEntry {
73    type Prefix = ();
74
75    type SubPrefix = ();
76
77    type Suffix = Self;
78
79    type SuperSuffix = Self;
80
81    // TODO: make this key implementation use src_chain as prefix
82    fn key(&self) -> Vec<cw_storage_plus::Key> {
83        self.0.key()
84    }
85}
86
87impl<'a> Prefixer<'a> for &AssetEntry {
88    fn prefix(&self) -> Vec<Key> {
89        self.0.prefix()
90    }
91}
92
93impl KeyDeserialize for &AssetEntry {
94    type Output = AssetEntry;
95
96    #[inline(always)]
97    fn from_vec(value: Vec<u8>) -> StdResult<Self::Output> {
98        Ok(AssetEntry(String::from_vec(value)?))
99    }
100}
101
102#[cfg(test)]
103mod test {
104    use super::*;
105    use speculoos::prelude::*;
106
107    #[test]
108    fn test_asset_entry() {
109        let mut entry = AssetEntry::new("CRAB");
110        assert_that!(entry.as_str()).is_equal_to("crab");
111        entry.format();
112        assert_that!(entry.as_str()).is_equal_to("crab");
113    }
114
115    #[test]
116    fn test_from_string() {
117        let entry = AssetEntry::from("CRAB".to_string());
118        assert_that!(entry.as_str()).is_equal_to("crab");
119    }
120
121    #[test]
122    fn test_from_str() {
123        let entry = AssetEntry::from("CRAB");
124        assert_that!(entry.as_str()).is_equal_to("crab");
125    }
126
127    #[test]
128    fn test_from_ref_string() {
129        let entry = AssetEntry::from(&"CRAB".to_string());
130        assert_that!(entry.as_str()).is_equal_to("crab");
131    }
132
133    #[test]
134    fn test_to_string() {
135        let entry = AssetEntry::new("CRAB");
136        assert_that!(entry.to_string()).is_equal_to("crab".to_string());
137    }
138
139    #[test]
140    fn string_key_works() {
141        let k = &AssetEntry::new("CRAB");
142        let path = k.key();
143        assert_eq!(1, path.len());
144        assert_eq!(b"crab", path[0].as_ref());
145
146        let joined = k.joined_key();
147        assert_eq!(joined, b"crab")
148    }
149}