1#[cfg(feature = "std")]
8use eosio_scale_info::TypeInfo;
9
10use crate::{
11 string::String,
12};
13
14use crate::serializer::{
15 Packer,
16 Encoder,
17};
18
19use crate::vmapi::eosio::{
20 check,
21 eosio_memcpy,
22};
23
24const INVALID_NAME_CHAR: u8 = 0xffu8;
25
26pub const fn char_to_index(c: u8) -> u8 {
30 match c as char {
31 'a'..='z' => {
32 return (c - 'a' as u8) + 6;
33 }
34 '1'..='5' => {
35 return (c - '1' as u8) + 1;
36 }
37 '.' => {
38 return 0;
39 }
40 _ => {
41 return INVALID_NAME_CHAR;
42 }
43 }
44}
45
46const INVALID_NAME: u64 = 0xFFFF_FFFF_FFFF_FFFFu64;
47
48
49pub const fn static_str_to_name(s: &'static str) -> u64 {
51 let mut value: u64 = 0;
52 let _s = s.as_bytes();
53
54 if _s.len() > 13 {
55 return INVALID_NAME;
56 }
57
58 if _s.len() == 0 {
59 return 0;
60 }
61
62 let mut n = _s.len();
63 if n == 13 {
64 n = 12;
65 }
66
67 let mut i = 0usize;
68
69 loop {
70 if i >= n {
71 break;
72 }
73 let tmp = char_to_index(_s[i]) as u64;
74 if tmp == INVALID_NAME_CHAR as u64 {
75 return INVALID_NAME;
76 }
77 value <<= 5;
78 value |= tmp;
79
80 i += 1;
81 }
82 value <<= 4 + 5*(12 - n);
83
84 if _s.len() == 13 {
85 let tmp = char_to_index(_s[12]) as u64;
86 if tmp == INVALID_NAME_CHAR as u64 {
87 return INVALID_NAME;
88 }
89 if tmp > 0x0f {
90 return INVALID_NAME;
91 }
92 value |= tmp;
93 }
94
95 return value;
96}
97
98
99pub fn static_str_to_name_checked(s: &'static str) -> u64 {
102 let n = static_str_to_name(s);
103 check(n != INVALID_NAME, "bad name");
104 return n;
105}
106
107
108pub fn s2n(s: &'static str) -> u64 {
110 return static_str_to_name_checked(s);
111}
112
113pub const CHAR_MAP: [u8; 32] = [46,49,50,51,52,53,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122];
115
116pub fn n2s(value: u64) -> String {
118 let mut s: [u8; 13] = [46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46]; let mut tmp = value;
121 for i in 0..13 {
122 let c: u8;
123 if i == 0 {
124 c = CHAR_MAP[(tmp&0x0f) as usize];
125 } else {
126 c = CHAR_MAP[(tmp&0x1f) as usize];
127 }
128 s[12-i] = c;
129 if i == 0 {
130 tmp >>= 4
131 } else {
132 tmp >>= 5
133 }
134 }
135
136 let mut i = s.len() - 1;
137 while i != 0 {
138 if s[i] != '.' as u8 {
139 break
140 }
141 i -= 1;
142 }
143 return String::from_utf8(s[0..i+1].to_vec()).unwrap();
144}
145
146
147fn str_to_name(s: &str) -> u64 {
149 let mut value: u64 = 0;
150 let _s = s.as_bytes();
151
152 if _s.len() > 13 {
153 return INVALID_NAME;
154 }
155
156 if _s.len() == 0 {
157 return 0;
158 }
159
160 let mut n = _s.len();
161 if n == 13 {
162 n = 12;
163 }
164
165 let mut i = 0usize;
166
167 loop {
168 if i >= n {
169 break;
170 }
171 let tmp = char_to_index(_s[i]) as u64;
172 if tmp == 0xff {
173 return INVALID_NAME;
174 }
175 value <<= 5;
176 value |= tmp;
177
178 i += 1;
179 }
180 value <<= 4 + 5*(12 - n);
181
182 if _s.len() == 13 {
183 let tmp = char_to_index(_s[12]) as u64;
184 if tmp == 0xff {
185 return INVALID_NAME;
186 }
187 if tmp > 0x0f {
188 return INVALID_NAME;
189 }
190 value |= tmp;
191 }
192
193 return value;
194}
195
196fn str_to_name_checked(s: &str) -> u64 {
197 let n = str_to_name(s);
198 check(n != INVALID_NAME, "bad name string");
199 return n;
200}
201
202#[repr(C, align(8))]
204#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
205#[cfg_attr(feature = "std", derive(TypeInfo))]
206pub struct Name {
207 pub n: u64,
209}
210
211impl Name {
212 pub fn new(s: &'static str) -> Self {
214 Name { n: s2n(s) }
215 }
216
217 pub fn value(&self) -> u64 {
218 return self.n
219 }
220
221 pub fn from_u64(n: u64) -> Self {
223 check(n != INVALID_NAME, "bad name value");
224 Name { n: n }
225 }
226
227 pub fn from_str(s: &str) -> Self {
229 return Name{ n: str_to_name_checked(s) };
230 }
231
232 pub fn to_string(&self) -> String {
234 n2s(self.n)
235 }
236}
237
238impl Packer for Name {
239 fn size(&self) -> usize {
240 return 8;
241 }
242
243 fn pack(&self, enc: &mut Encoder) -> usize {
244 self.n.pack(enc)
245 }
246
247 fn unpack(&mut self, raw: &[u8]) -> usize {
248 check(raw.len() >= 8, "Name.unpack: buffer overflow!");
249 self.n = 0;
250 eosio_memcpy(&self.n as *const u64 as *mut u8, raw.as_ptr(), 8);
251 return 8;
252 }
253}
254
255pub const SAME_PAYER: Name = Name{n: 0};
256pub const ACTIVE: Name = Name{n: static_str_to_name("active")};
257pub const OWNER: Name = Name{n: static_str_to_name("owner")};
258pub const CODE: Name = Name{n: static_str_to_name("eosio.code")};
259
260
261#[macro_export]
263macro_rules! name {
264 ( $head:expr ) => {
265 {
266 const n: u64 = $crate::name::static_str_to_name($head);
267 $crate::name::Name::from_u64(n)
268 }
269 };
270}