1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use {super::*, regex::RegexSet};

#[derive(Debug, Copy, Clone)]
pub(crate) enum Representation {
  Address,
  Decimal,
  Degree,
  Hash,
  InscriptionId,
  Integer,
  Name,
  OutPoint,
  Percentile,
  SatPoint,
}

impl Representation {
  const fn pattern(self) -> (Self, &'static str) {
    (
      self,
      match self {
        Self::Address => r"^(bc|BC|tb|TB|bcrt|BCRT)1.*$",
        Self::Decimal => r"^.*\..*$",
        Self::Degree => r"^.*°.*′.*″(.*‴)?$",
        Self::Hash => r"^[[:xdigit:]]{64}$",
        Self::InscriptionId => r"^[[:xdigit:]]{64}i\d+$",
        Self::Integer => r"^[0-9]*$",
        Self::Name => r"^[a-z]{1,11}$",
        Self::OutPoint => r"^[[:xdigit:]]{64}:\d+$",
        Self::Percentile => r"^.*%$",
        Self::SatPoint => r"^[[:xdigit:]]{64}:\d+:\d+$",
      },
    )
  }
}

impl FromStr for Representation {
  type Err = Error;

  fn from_str(s: &str) -> Result<Self> {
    if let Some(i) = REGEX_SET.matches(s).into_iter().next() {
      Ok(PATTERNS[i].0)
    } else {
      Err(anyhow!("unrecognized object"))
    }
  }
}

const PATTERNS: &[(Representation, &str)] = &[
  Representation::Address.pattern(),
  Representation::Decimal.pattern(),
  Representation::Degree.pattern(),
  Representation::Hash.pattern(),
  Representation::InscriptionId.pattern(),
  Representation::Integer.pattern(),
  Representation::Name.pattern(),
  Representation::OutPoint.pattern(),
  Representation::Percentile.pattern(),
  Representation::SatPoint.pattern(),
];

lazy_static! {
  static ref REGEX_SET: RegexSet =
    RegexSet::new(PATTERNS.iter().map(|(_representation, pattern)| pattern),).unwrap();
}

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  fn all_patterns_are_anchored() {
    assert!(PATTERNS
      .iter()
      .all(|(_representation, pattern)| pattern.starts_with('^') && pattern.ends_with('$')));
  }
}