#![allow(dead_code, unused)]
use core::str;
use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
use std::convert::From;
use std::fmt;
use std::str::FromStr;
use crate::{check, ParseError};
pub const NAME_CHARS: [u8; 32] = *b".12345abcdefghijklmnopqrstuvwxyz";
pub const NAME_MAX_LEN: usize = 13;
#[derive(Eq, Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Default)]
pub struct Name {
pub value: u64,
}
impl Name {
#[must_use]
#[inline]
pub fn new() -> Self {
Self { value: 0 }
}
#[must_use]
#[inline]
pub fn raw(&self) -> u64 {
self.value
}
#[must_use]
#[inline]
pub fn length(&self) -> u8 {
let mask: u64 = 0xF800000000000000;
if (self.value == 0) {
return 0;
}
let mut l: u8 = 0;
let mut i: u8 = 0;
let mut v = self.value;
while i < 13 {
if ((v & mask) > 0) {
l = i;
}
v <<= 5;
i += 1;
}
l + 1
}
pub fn char_to_value(c: char) -> Option<u8> {
match c {
'.' => Some(0),
'1'..='5' => Some(c as u8 - b'1' + 1),
'a'..='z' => Some(c as u8 - b'a' + 6),
_ => None,
}
}
#[must_use]
pub fn prefix(&self) -> Name {
let mut result: u64 = self.value;
let mut not_dot_character_seen: bool = false;
let mut mask: u64 = 0xF;
let mut offset: i32 = 0;
while (offset <= 59) {
let c = (self.value >> offset) & mask;
if (c == 0) {
if (not_dot_character_seen) {
result = (self.value >> offset) << offset;
break;
}
} else {
not_dot_character_seen = true;
}
if (offset == 0) {
offset += 4;
mask = 0x1F;
} else {
offset += 5;
}
}
Name::from(result)
}
#[must_use]
pub fn suffix(&self) -> Name {
let mut remaining_bits_after_last_actual_dot: u32 = 0;
let mut tmp: u32 = 0;
let mut remaining_bits = 59;
while (remaining_bits >= 4) {
let c = (self.value >> remaining_bits) & 0x1F;
if (c == 0) {
tmp = remaining_bits as u32;
} else {
remaining_bits_after_last_actual_dot = tmp;
}
remaining_bits -= 5;
}
let mut thirteenth_character: u64 = self.value & 0x0F;
if thirteenth_character != 0 {
remaining_bits_after_last_actual_dot = tmp;
}
if (remaining_bits_after_last_actual_dot == 0) {
return Name::from(self.value);
}
let mask: u64 = (1 << remaining_bits_after_last_actual_dot) - 16;
let shift: u32 = 64 - remaining_bits_after_last_actual_dot;
Name::from(((self.value & mask) << shift) + (thirteenth_character << (shift - 1)))
}
}
#[must_use]
pub fn name_to_bytes(value: u64) -> [u8; NAME_MAX_LEN] {
let mut chars = [b'.'; NAME_MAX_LEN];
if value == 0 {
return chars;
}
let mask = 0xF800_0000_0000_0000;
let mut v = value;
for (i, c) in chars.iter_mut().enumerate() {
let index = (v & mask) >> (if i == 12 { 60 } else { 59 });
let index = usize::try_from(index).unwrap_or_default();
if let Some(v) = NAME_CHARS.get(index) {
*c = *v;
}
v <<= 5;
}
chars
}
impl fmt::Display for Name {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let bytes = name_to_bytes(self.value);
let value = str::from_utf8(&bytes).map(|s| s.trim_end_matches('.')).map_err(|_| fmt::Error)?;
write!(f, "{value}")
}
}
impl FromStr for Name {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut value = 0_u64;
if s.len() > 13 {
return Err(ParseError::BadName(s.to_string()));
}
if s.is_empty() {
return Ok(Self { value });
}
let n = std::cmp::min(s.len(), 12);
for i in 0..n {
value <<= 5;
let c = Name::char_to_value(s.chars().nth(i).unwrap()).ok_or(ParseError::BadName(s.to_string()))?;
value |= c as u64;
}
value <<= (4 + 5 * (12 - n));
if s.len() == 13 {
let v = Name::char_to_value(s.chars().nth(12).unwrap()).ok_or(ParseError::BadName(s.to_string()))?;
if v > 0x0F {
return Err(ParseError::BadName(s.to_string()));
}
value |= v as u64;
}
Ok(Self { value })
}
}
impl From<&str> for Name {
fn from(str: &str) -> Self {
Self::from_str(str).unwrap_or_else(|e| panic!("failed to parse name: {}", e))
}
}
impl From<u64> for Name {
#[inline]
fn from(value: u64) -> Self {
Name { value }
}
}
impl From<Name> for u64 {
#[inline]
fn from(name: Name) -> Self {
name.value
}
}
impl AsRef<Name> for Name {
#[inline]
fn as_ref(&self) -> &Name {
self
}
}
impl From<Name> for bool {
#[inline]
fn from(name: Name) -> Self {
name.raw() != 0
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ParseError;
use proptest::prelude::*;
#[test]
fn test_cdt_1() {
assert_eq!(Name::new().value, 0);
assert_eq!(Name::from(0).value, 0);
assert_eq!(Name::from(1).value, 1);
assert_eq!(Name::from(u64::MAX).value, u64::MAX);
assert_eq!(Name::from(0).raw(), 0);
assert_eq!(Name::from(1).raw(), 1);
assert_eq!(Name::from(u64::MAX).raw(), u64::MAX);
assert_eq!(Name::from(0).value == 0, true);
assert_eq!(Name::from(Name::from(1)).value == 1, true);
}
#[test]
fn test_cdt_2() {
assert_eq!(Name::from("1").value, 576460752303423488);
assert_eq!(Name::from("5").value, 2882303761517117440);
assert_eq!(Name::from("a").value, 3458764513820540928);
assert_eq!(Name::from("z").value, 17870283321406128128);
assert_eq!(Name::from("abc").value, 3589368903014285312);
assert_eq!(Name::from("123").value, 614178399182651392);
assert_eq!(Name::from(".abc").value, 112167778219196416);
assert_eq!(Name::from(".........abc").value, 102016);
assert_eq!(Name::from("123.").value, 614178399182651392);
assert_eq!(Name::from("123.........").value, 614178399182651392);
assert_eq!(Name::from(".a.b.c.1.2.3.").value, 108209673814966320);
assert_eq!(Name::from("abc.123").value, 3589369488740450304);
assert_eq!(Name::from("123.abc").value, 614181822271586304);
assert_eq!(Name::from("12345abcdefgj").value, 614251623682315983);
assert_eq!(Name::from("hijklmnopqrsj").value, 7754926748989239183);
assert_eq!(Name::from("tuvwxyz.1234j").value, 14895601873741973071);
assert_eq!(Name::from("111111111111j").value, 595056260442243615);
assert_eq!(Name::from("555555555555j").value, 2975281302211218015);
assert_eq!(Name::from("aaaaaaaaaaaaj").value, 3570337562653461615);
assert_eq!(Name::from("zzzzzzzzzzzzj").value, u64::MAX);
assert_eq!(Name::from("1").value == 576460752303423488, true);
}
#[test]
fn test_cdt_3() {
assert_eq!(Name::from("").length(), 0);
assert_eq!(Name::from("e").length(), 1);
assert_eq!(Name::from("eo").length(), 2);
assert_eq!(Name::from("eos").length(), 3);
assert_eq!(Name::from("eosi").length(), 4);
assert_eq!(Name::from("eosio").length(), 5);
assert_eq!(Name::from("eosioa").length(), 6);
assert_eq!(Name::from("eosioac").length(), 7);
assert_eq!(Name::from("eosioacc").length(), 8);
assert_eq!(Name::from("eosioacco").length(), 9);
assert_eq!(Name::from("eosioaccou").length(), 10);
assert_eq!(Name::from("eosioaccoun").length(), 11);
assert_eq!(Name::from("eosioaccount").length(), 12);
assert_eq!(Name::from("eosioaccountj").length(), 13);
}
#[test]
fn test_cdt_4() {
assert_eq!(Name::from(".eosioaccounj").suffix(), Name::from("eosioaccounj"));
assert_eq!(Name::from("e.osioaccounj").suffix(), Name::from("osioaccounj"));
assert_eq!(Name::from("eo.sioaccounj").suffix(), Name::from("sioaccounj"));
assert_eq!(Name::from("eos.ioaccounj").suffix(), Name::from("ioaccounj"));
assert_eq!(Name::from("eosi.oaccounj").suffix(), Name::from("oaccounj"));
assert_eq!(Name::from("eosio.accounj").suffix(), Name::from("accounj"));
assert_eq!(Name::from("eosioa.ccounj").suffix(), Name::from("ccounj"));
assert_eq!(Name::from("eosioac.counj").suffix(), Name::from("counj"));
assert_eq!(Name::from("eosioacc.ounj").suffix(), Name::from("ounj"));
assert_eq!(Name::from("eosioacco.unj").suffix(), Name::from("unj"));
assert_eq!(Name::from("eosioaccou.nj").suffix(), Name::from("nj"));
assert_eq!(Name::from("eosioaccoun.j").suffix(), Name::from("j"));
assert_eq!(Name::from("e.o.s.i.o.a.c").suffix(), Name::from("c"));
assert_eq!(Name::from("eos.ioa.cco").suffix(), Name::from("cco"));
}
#[test]
fn test_cdt_5() {
assert_eq!(Name::from(".eosioaccounj").prefix(), Name::new());
assert_eq!(Name::from("e.osioaccounj").prefix(), Name::from("e"));
assert_eq!(Name::from("eo.sioaccounj").prefix(), Name::from("eo"));
assert_eq!(Name::from("eos.ioaccounj").prefix(), Name::from("eos"));
assert_eq!(Name::from("eosi.oaccounj").prefix(), Name::from("eosi"));
assert_eq!(Name::from("eosio.accounj").prefix(), Name::from("eosio"));
assert_eq!(Name::from("eosioa.ccounj").prefix(), Name::from("eosioa"));
assert_eq!(Name::from("eosioac.counj").prefix(), Name::from("eosioac"));
assert_eq!(Name::from("eosioacc.ounj").prefix(), Name::from("eosioacc"));
assert_eq!(Name::from("eosioacco.unj").prefix(), Name::from("eosioacco"));
assert_eq!(Name::from("eosioaccou.nj").prefix(), Name::from("eosioaccou"));
assert_eq!(Name::from("eosioaccoun.j").prefix(), Name::from("eosioaccoun"));
assert_eq!(Name::from("eosioaccounj.").prefix(), Name::from("eosioaccounj"));
assert_eq!(Name::from("eosioaccountj").prefix(), Name::from("eosioaccountj"));
assert_eq!(Name::from("e.o.s.i.o.a.c").prefix(), Name::from("e.o.s.i.o.a"));
assert_eq!(Name::from("eos.ioa.cco").prefix(), Name::from("eos.ioa"));
assert_eq!(Name::from("a.my.account").prefix(), Name::from("a.my"));
assert_eq!(Name::from("a.my.account").prefix().prefix(), Name::from("a"));
assert_eq!(Name::from("e.osioaccounj").prefix() == Name::from("e"), true);
}
#[test]
fn test_cdt_6() {
assert_eq!(false, Name::from(0).into());
assert_eq!(true, Name::from(1).into());
assert_eq!(false, Name::from("").into());
assert_eq!(true, Name::from("1").into());
assert_eq!(true, false == Name::from(0).into());
}
#[test]
fn test_cdt_8() {
assert_eq!(Name::from("1").to_string(), "1");
assert_eq!(Name::from("5").to_string(), "5");
assert_eq!(Name::from("a").to_string(), "a");
assert_eq!(Name::from("z").to_string(), "z");
assert_eq!(Name::from("abc").to_string(), "abc");
assert_eq!(Name::from("123").to_string(), "123");
assert_eq!(Name::from(".abc").to_string(), ".abc");
assert_eq!(Name::from(".........abc").to_string(), ".........abc");
assert_eq!(Name::from("123.").to_string(), "123");
assert_eq!(Name::from("123.........").to_string(), "123");
assert_eq!(Name::from(".a.b.c.1.2.3.").to_string(), ".a.b.c.1.2.3");
assert_eq!(Name::from("abc.123").to_string(), "abc.123");
assert_eq!(Name::from("123.abc").to_string(), "123.abc");
assert_eq!(Name::from("12345abcdefgj").to_string(), "12345abcdefgj");
assert_eq!(Name::from("hijklmnopqrsj").to_string(), "hijklmnopqrsj");
assert_eq!(Name::from("tuvwxyz.1234j").to_string(), "tuvwxyz.1234j");
assert_eq!(Name::from("111111111111j").to_string(), "111111111111j");
assert_eq!(Name::from("555555555555j").to_string(), "555555555555j");
assert_eq!(Name::from("aaaaaaaaaaaaj").to_string(), "aaaaaaaaaaaaj");
assert_eq!(Name::from("zzzzzzzzzzzzj").to_string(), "zzzzzzzzzzzzj");
assert_eq!(Name::from("1") == Name::from("1"), true);
}
#[test]
fn test_cdt_9() {
assert_eq!(Name::from("1") == Name::from("1"), true);
assert_eq!(Name::from("5") == Name::from("5"), true);
assert_eq!(Name::from("a") == Name::from("a"), true);
assert_eq!(Name::from("z") == Name::from("z"), true);
assert_eq!(Name::from("abc") == Name::from("abc"), true);
assert_eq!(Name::from("123") == Name::from("123"), true);
assert_eq!(Name::from(".abc") == Name::from(".abc"), true);
assert_eq!(Name::from(".........abc") == Name::from(".........abc"), true);
assert_eq!(Name::from("123.") == Name::from("123"), true);
assert_eq!(Name::from("123.........") == Name::from("123"), true);
assert_eq!(Name::from(".a.b.c.1.2.3.") == Name::from(".a.b.c.1.2.3"), true);
assert_eq!(Name::from("abc.123") == Name::from("abc.123"), true);
assert_eq!(Name::from("123.abc") == Name::from("123.abc"), true);
assert_eq!(Name::from("12345abcdefgj") == Name::from("12345abcdefgj"), true);
assert_eq!(Name::from("hijklmnopqrsj") == Name::from("hijklmnopqrsj"), true);
assert_eq!(Name::from("tuvwxyz.1234j") == Name::from("tuvwxyz.1234j"), true);
assert_eq!(Name::from("111111111111j") == Name::from("111111111111j"), true);
assert_eq!(Name::from("555555555555j") == Name::from("555555555555j"), true);
assert_eq!(Name::from("aaaaaaaaaaaaj") == Name::from("aaaaaaaaaaaaj"), true);
assert_eq!(Name::from("zzzzzzzzzzzzj") == Name::from("zzzzzzzzzzzzj"), true);
assert_eq!(Name::from("1") == Name::from("1"), true);
}
#[test]
fn test_cdt_10() {
assert_eq!(Name::from("1") != Name::new(), true);
assert_eq!(Name::from("5") != Name::new(), true);
assert_eq!(Name::from("a") != Name::new(), true);
assert_eq!(Name::from("z") != Name::new(), true);
assert_eq!(Name::from("abc") != Name::new(), true);
assert_eq!(Name::from("123") != Name::new(), true);
assert_eq!(Name::from(".abc") != Name::new(), true);
assert_eq!(Name::from(".........abc") != Name::new(), true);
assert_eq!(Name::from("123.") != Name::new(), true);
assert_eq!(Name::from("123.........") != Name::new(), true);
assert_eq!(Name::from(".a.b.c.1.2.3.") != Name::new(), true);
assert_eq!(Name::from("abc.123") != Name::new(), true);
assert_eq!(Name::from("123.abc") != Name::new(), true);
assert_eq!(Name::from("12345abcdefgj") != Name::new(), true);
assert_eq!(Name::from("hijklmnopqrsj") != Name::new(), true);
assert_eq!(Name::from("tuvwxyz.1234j") != Name::new(), true);
assert_eq!(Name::from("111111111111j") != Name::new(), true);
assert_eq!(Name::from("555555555555j") != Name::new(), true);
assert_eq!(Name::from("aaaaaaaaaaaaj") != Name::new(), true);
assert_eq!(Name::from("zzzzzzzzzzzzj") != Name::new(), true);
assert_eq!(Name::from("1") != Name::from("2"), true);
}
#[test]
fn test_cdt_11() {
assert_eq!(Name::new() < Name::from("1"), true);
assert_eq!(Name::new() < Name::from("5"), true);
assert_eq!(Name::new() < Name::from("a"), true);
assert_eq!(Name::new() < Name::from("z"), true);
assert_eq!(Name::new() < Name::from("abc"), true);
assert_eq!(Name::new() < Name::from("123"), true);
assert_eq!(Name::new() < Name::from(".abc"), true);
assert_eq!(Name::new() < Name::from(".........abc"), true);
assert_eq!(Name::new() < Name::from("123."), true);
assert_eq!(Name::new() < Name::from("123........."), true);
assert_eq!(Name::new() < Name::from(".a.b.c.1.2.3."), true);
assert_eq!(Name::new() < Name::from("abc.123"), true);
assert_eq!(Name::new() < Name::from("123.abc"), true);
assert_eq!(Name::new() < Name::from("12345abcdefgj"), true);
assert_eq!(Name::new() < Name::from("hijklmnopqrsj"), true);
assert_eq!(Name::new() < Name::from("tuvwxyz.1234j"), true);
assert_eq!(Name::new() < Name::from("111111111111j"), true);
assert_eq!(Name::new() < Name::from("555555555555j"), true);
assert_eq!(Name::new() < Name::from("aaaaaaaaaaaaj"), true);
assert_eq!(Name::new() < Name::from("zzzzzzzzzzzzj"), true);
assert_eq!(Name::new() < Name::from("1"), true);
}
#[test]
#[allow(unused)]
fn test_cdt_panic_1() {
assert_eq!(Name::from_str("0"), Err(ParseError::BadName("0".to_string())));
assert_eq!(
Name::from_str("111111111111k"),
Err(ParseError::BadName("111111111111k".to_string()))
);
assert_eq!(
Name::from_str("12345abcdefghj"),
Err(ParseError::BadName("12345abcdefghj".to_string()))
);
assert_eq!(Name::from_str("0"), Err(ParseError::BadName("0".to_string())));
assert_eq!(Name::from_str("0"), Err(ParseError::BadName("0".to_string())));
assert_eq!(Name::from_str("0"), Err(ParseError::BadName("0".to_string())));
}
#[test]
fn char_to_value() {
assert_eq!(Name::char_to_value('-'), None);
assert_eq!(Name::char_to_value('/'), None);
assert_eq!(Name::char_to_value('A'), None);
assert_eq!(Name::char_to_value('6'), None);
assert_eq!(Name::char_to_value('{'), None);
assert_eq!(Name::char_to_value('`'), None);
}
#[test]
fn test_copy() {
let name = Name::from("aaaaaaaaaaaa");
let copied_name = name;
assert_eq!(name, copied_name);
}
#[test]
fn test_clone() {
let name = Name::from("aaaaaaaaaaaa");
let cloned_name = name.clone();
assert_eq!(name, cloned_name);
}
#[test]
fn test_default() {
let default_name = Name::default();
assert_eq!(default_name.value, 0);
}
#[test]
fn test_as_ref() {
let name = Name::from("aaaaaaaaaaaa");
let name_ref = name.as_ref();
assert_eq!(name_ref.to_string(), "aaaaaaaaaaaa");
}
#[test]
fn test_from_self() {
let name = Name::from("aaaaaaaaaaaa");
assert_eq!(Name::from(name), name);
}
proptest! {
#[test]
fn random_names(input in "[[1-5][a-z]]{0,12}[a-j]{0,1}") {
let name = Name::from(input.as_str());
prop_assert_eq!(name.to_string(), input);
}
#[test]
fn random_names_with_dot(input in "[[1-5][a-z]]{1,5}[.]{0,1}[1-5][a-z]{1,5}") {
let name = Name::from(input.as_str());
prop_assert_eq!(name.to_string(), input);
}
#[test]
fn bad_chars(input in "[[A-Z][6-9][!@#$%^&*()💔]]{1}") {
prop_assert_eq!(Name::from_str(input.as_str()), Err(ParseError::BadName(input.to_string())));
}
}
}