eosio_core/
symbol_code.rs1use crate::{ScopeName, Symbol};
4use eosio_bytes::{NumBytes, Read, Write};
5use eosio_numstr::{symbol_from_str, symbol_to_string, symbol_to_utf8};
6use std::convert::TryFrom;
7use std::fmt;
8use std::str::FromStr;
9
10pub use eosio_numstr::ParseSymbolError;
11
12#[derive(
14 Debug,
15 PartialEq,
16 Eq,
17 Clone,
18 Copy,
19 Default,
20 Read,
21 Write,
22 NumBytes,
23 Hash,
24 PartialOrd,
25 Ord,
26)]
27#[eosio_bytes_root_path = "::eosio_bytes"]
28pub struct SymbolCode(u64);
29
30impl From<u64> for SymbolCode {
31 #[inline]
32 fn from(n: u64) -> Self {
33 Self(n)
34 }
35}
36
37impl From<SymbolCode> for u64 {
38 #[inline]
39 fn from(s: SymbolCode) -> Self {
40 s.0
41 }
42}
43
44impl From<SymbolCode> for [u8; 7] {
45 #[inline]
46 fn from(s: SymbolCode) -> Self {
47 symbol_to_utf8(s.0)
48 }
49}
50
51impl From<SymbolCode> for ScopeName {
52 #[inline]
53 fn from(symbol: SymbolCode) -> Self {
54 let value: u64 = symbol.into();
55 value.into()
56 }
57}
58
59impl From<ScopeName> for SymbolCode {
60 #[inline]
61 fn from(scope: ScopeName) -> Self {
62 let value: u64 = scope.into();
63 value.into()
64 }
65}
66
67impl fmt::Display for SymbolCode {
68 #[inline]
69 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
70 write!(f, "{}", symbol_to_string(self.0 << 8))
71 }
72}
73
74impl SymbolCode {
75 #[inline]
77 pub fn is_valid(&self) -> bool {
78 let chars = symbol_to_utf8(self.0);
79 for &c in &chars {
80 if c == b' ' {
81 continue;
82 }
83 if !(b'A' <= c && c <= b'Z') {
84 return false;
85 }
86 }
87 true
88 }
89
90 #[inline]
92 pub const fn as_u64(&self) -> u64 {
93 self.0
94 }
95}
96
97impl TryFrom<&str> for SymbolCode {
98 type Error = ParseSymbolError;
99 #[inline]
100 fn try_from(value: &str) -> Result<Self, Self::Error> {
101 let symbol: Symbol = symbol_from_str(0, value)?.into();
102 Ok(symbol.code())
103 }
104}
105
106impl TryFrom<String> for SymbolCode {
107 type Error = ParseSymbolError;
108 #[inline]
109 fn try_from(value: String) -> Result<Self, Self::Error> {
110 Self::try_from(value.as_str())
111 }
112}
113
114impl FromStr for SymbolCode {
115 type Err = ParseSymbolError;
116 #[inline]
117 fn from_str(s: &str) -> Result<Self, Self::Err> {
118 Self::try_from(s)
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125 use eosio_numstr::symbol_code;
126 use eosio_numstr_macros::s;
127
128 macro_rules! test_to_string {
129 ($($name:ident, $value:expr, $expected:expr)*) => ($(
130 #[test]
131 fn $name() {
132 assert_eq!(
133 SymbolCode::from(symbol_code($value)).to_string(),
134 $expected
135 );
136 }
137 )*)
138 }
139
140 test_to_string! {
141 to_string, s!(4, EOS), "EOS"
142 to_string_zero_precision, s!(0, TGFT), "TGFT"
143 to_string_nine_precision, s!(9, SYS), "SYS"
144 }
145
146 macro_rules! test_from_str_ok {
147 ($($name:ident, $input:expr, $expected:expr)*) => ($(
148 #[test]
149 fn $name() {
150 let ok = Ok(Symbol::from($expected).code());
151 assert_eq!(SymbolCode::from_str($input), ok);
152 assert_eq!(SymbolCode::try_from($input), ok);
153 }
154 )*)
155 }
156
157 test_from_str_ok! {
158 from_str_ok1, "TST", s!(0, TST)
159 from_str_ok2, "EOS", s!(4, EOS)
160 from_str_ok3, "TGFT", s!(0, TGFT)
161 }
162
163 macro_rules! test_from_str_err {
164 ($($name:ident, $input:expr, $expected:expr)*) => ($(
165 #[test]
166 fn $name() {
167 let err = Err($expected);
168 assert_eq!(SymbolCode::from_str($input), err);
169 assert_eq!(SymbolCode::try_from($input), err);
170 }
171 )*)
172 }
173
174 test_from_str_err! {
175 from_str_bad_char,
176 "tst",
177 ParseSymbolError::BadChar('t')
178 }
179
180}