1 | use crate::parser::errors::ParserError; |
2 | use std::str::FromStr; |
3 | use tinystr::TinyStr8; |
4 | |
5 | #[derive (Debug, PartialEq, Eq, Clone, Hash, PartialOrd, Ord, Copy)] |
6 | pub struct Variant(TinyStr8); |
7 | |
8 | impl Variant { |
9 | pub fn from_bytes(v: &[u8]) -> Result<Self, ParserError> { |
10 | let slen = v.len(); |
11 | |
12 | if !(4..=8).contains(&slen) { |
13 | return Err(ParserError::InvalidSubtag); |
14 | } |
15 | |
16 | let s = TinyStr8::from_bytes(v).map_err(|_| ParserError::InvalidSubtag)?; |
17 | |
18 | if (slen >= 5 && !s.is_ascii_alphanumeric()) |
19 | || (slen == 4 |
20 | && !v[0].is_ascii_digit() |
21 | && v[1..].iter().any(|c: &u8| !c.is_ascii_alphanumeric())) |
22 | { |
23 | return Err(ParserError::InvalidSubtag); |
24 | } |
25 | |
26 | Ok(Self(s.to_ascii_lowercase())) |
27 | } |
28 | |
29 | pub fn as_str(&self) -> &str { |
30 | self.0.as_str() |
31 | } |
32 | |
33 | /// # Safety |
34 | /// |
35 | /// This function accepts any u64 that is exected to be a valid |
36 | /// `TinyStr8` and a valid `Variant` subtag. |
37 | pub const unsafe fn from_raw_unchecked(v: u64) -> Self { |
38 | Self(TinyStr8::from_bytes_unchecked(v.to_le_bytes())) |
39 | } |
40 | } |
41 | |
42 | impl From<Variant> for u64 { |
43 | fn from(input: Variant) -> Self { |
44 | u64::from_le_bytes(*input.0.all_bytes()) |
45 | } |
46 | } |
47 | |
48 | impl From<&Variant> for u64 { |
49 | fn from(input: &Variant) -> Self { |
50 | u64::from_le_bytes(*input.0.all_bytes()) |
51 | } |
52 | } |
53 | |
54 | impl FromStr for Variant { |
55 | type Err = ParserError; |
56 | |
57 | fn from_str(source: &str) -> Result<Self, Self::Err> { |
58 | Self::from_bytes(source.as_bytes()) |
59 | } |
60 | } |
61 | |
62 | impl std::fmt::Display for Variant { |
63 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
64 | f.write_str(&self.0) |
65 | } |
66 | } |
67 | |
68 | impl PartialEq<&str> for Variant { |
69 | fn eq(&self, other: &&str) -> bool { |
70 | self.as_str() == *other |
71 | } |
72 | } |
73 | |
74 | impl PartialEq<str> for Variant { |
75 | fn eq(&self, other: &str) -> bool { |
76 | self.as_str() == other |
77 | } |
78 | } |
79 | |