bytestream_rs/
logiclong.rs

1use rand::{self, Rng};
2use regex::Regex;
3use std::fmt;
4
5#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord)]
6pub struct LogicLong {
7    pub low: u32,
8    pub high: u32,
9    pub tag: String,
10}
11
12#[derive(Clone, Debug, PartialEq)]
13pub enum LogicLongError {
14    InvalidTag(String),
15}
16
17impl LogicLong {
18    pub fn new(low: u32, high: u32) -> LogicLong {
19        let mut logic_long = LogicLong {
20            low,
21            high,
22            tag: String::new(),
23        };
24        logic_long.tag = logic_long.to_tag();
25        logic_long
26    }
27
28    pub fn new_from_tag(tag: String) -> Result<LogicLong, LogicLongError> {
29        return LogicLong::from_tag(tag);
30    }
31
32    pub fn from_tag(tag: String) -> Result<LogicLong, LogicLongError> {
33        let arr: Vec<char> = vec![
34            '0', '2', '8', '9', 'P', 'Y', 'L', 'Q', 'G', 'R', 'J', 'C', 'U', 'V',
35        ];
36        let tag = LogicLong::fix_tag(tag);
37        let mut total: u64 = 0;
38        let base: u64 = 14;
39
40        // iterate backwards
41        for (i, c) in tag.replace("#", "").chars().rev().enumerate() {
42            // get index of c in arr
43            let index = arr
44                .iter()
45                .position(|&x| x == c)
46                .ok_or_else(|| LogicLongError::InvalidTag(tag.clone()))?;
47            // total += index times 14 to the power of i
48            total += index as u64 * base.pow(i as u32);
49        }
50        Ok(LogicLong {
51            low: ((total % 256) as u32),
52            high: ((total / 256) as u32),
53            tag,
54        })
55    }
56
57    pub fn fix_tag(tag: String) -> String {
58        let re = Regex::new("[^A-Z0-9]+").unwrap();
59        "#".to_owned()
60            + &re
61                .replace_all(tag.to_uppercase().as_str(), "")
62                .replace("O", "0")
63    }
64
65    pub fn random() -> LogicLong {
66        let mut rng = rand::thread_rng();
67        let low = rng.gen_range(0..100);
68        let high = rng.gen::<u32>();
69        LogicLong::new(low, high)
70    }
71
72    pub fn to_tag(&self) -> String {
73        let arr: Vec<char> = vec![
74            '0', '2', '8', '9', 'P', 'Y', 'L', 'Q', 'G', 'R', 'J', 'C', 'U', 'V',
75        ];
76        let mut tag = String::new();
77        let mut total = self.low as i64 + self.high as i64 * 0x100;
78        let mut b14;
79
80        while total != 0 {
81            b14 = total % 14;
82            total /= 14;
83            tag.insert(0, arr[b14 as usize]);
84        }
85        LogicLong::fix_tag(tag)
86    }
87
88    // fn digit_to_char(digit: i32) -> String {
89    //     if digit < 10 {
90    //         return format!("{}", digit);
91    //     }
92    //     return format!("{}", (b'a' + digit as u8 - 10) as char);
93    // }
94
95    // fn str_base(number: i32, base: i32) -> String {
96    //     if number < 0 {
97    //         return format!("-{}", LogicLong::str_base(-number, base));
98    //     }
99    //     let (d, m) = (number / base, number % base);
100    //     if d > 0 {
101    //         LogicLong::str_base(d, base) + &LogicLong::digit_to_char(m)
102    //     } else {
103    //         LogicLong::digit_to_char(m)
104    //     }
105    // }
106
107    // fn dec2rdx(mut num: i32) -> String {
108    //     let mut rv = String::new();
109    //     for _ in 0..4 {
110    //         rv = format!("{},", num & 0xFF) + &rv;
111    //         num >>= 8;
112    //     }
113    //     rv
114    // }
115}
116
117impl fmt::Display for LogicLong {
118    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119        write!(f, "{} ({}, {})", self.to_tag(), self.low, self.high)
120    }
121}