1use {super::*, regex::RegexSet};
2
3#[derive(Debug, Copy, Clone)]
4pub(crate) enum Representation {
5 Address,
6 Decimal,
7 Degree,
8 Hash,
9 InscriptionId,
10 Integer,
11 Name,
12 OutPoint,
13 Percentile,
14 Rune,
15 SatPoint,
16}
17
18impl Representation {
19 const fn pattern(self) -> (Self, &'static str) {
20 (
21 self,
22 match self {
23 Self::Address => r"^(bc|BC|tb|TB|bcrt|BCRT)1.*$",
24 Self::Decimal => r"^.*\..*$",
25 Self::Degree => r"^.*°.*′.*″(.*‴)?$",
26 Self::Hash => r"^[[:xdigit:]]{64}$",
27 Self::InscriptionId => r"^[[:xdigit:]]{64}i\d+$",
28 Self::Integer => r"^[0-9]*$",
29 Self::Name => r"^[a-z]{1,11}$",
30 Self::OutPoint => r"^[[:xdigit:]]{64}:\d+$",
31 Self::Percentile => r"^.*%$",
32 Self::Rune => r"^[A-Z•.]+$",
33 Self::SatPoint => r"^[[:xdigit:]]{64}:\d+:\d+$",
34 },
35 )
36 }
37}
38
39impl FromStr for Representation {
40 type Err = SnafuError;
41
42 fn from_str(input: &str) -> Result<Self, Self::Err> {
43 if let Some(i) = REGEX_SET.matches(input).into_iter().next() {
44 Ok(PATTERNS[i].0)
45 } else {
46 Err(error::UnrecognizedRepresentation { input }.build())
47 }
48 }
49}
50
51const PATTERNS: &[(Representation, &str)] = &[
52 Representation::Address.pattern(),
53 Representation::Decimal.pattern(),
54 Representation::Degree.pattern(),
55 Representation::Hash.pattern(),
56 Representation::InscriptionId.pattern(),
57 Representation::Integer.pattern(),
58 Representation::Name.pattern(),
59 Representation::OutPoint.pattern(),
60 Representation::Percentile.pattern(),
61 Representation::Rune.pattern(),
62 Representation::SatPoint.pattern(),
63];
64
65static REGEX_SET: LazyLock<RegexSet> = LazyLock::new(|| {
66 RegexSet::new(PATTERNS.iter().map(|(_representation, pattern)| pattern)).unwrap()
67});
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn all_patterns_are_anchored() {
75 assert!(
76 PATTERNS
77 .iter()
78 .all(|(_representation, pattern)| pattern.starts_with('^') && pattern.ends_with('$'))
79 );
80 }
81}