Skip to main content

uvb_core/
factor.rs

1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4/// Type-safe factor identifier wrapper
5///
6/// This newtype provides compile-time guarantees that:
7/// 1. Factor IDs cannot be accidentally mixed with other string types
8/// 2. All factor-scoped operations explicitly require a FactorId
9/// 3. Cross-factor operations are caught at compile time
10#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
11#[serde(transparent)]
12pub struct FactorId(String);
13
14impl FactorId {
15    /// Create a new FactorId from a string
16    pub fn new(id: impl Into<String>) -> Self {
17        Self(id.into())
18    }
19
20    /// Get the factor ID as a string slice
21    pub fn as_str(&self) -> &str {
22        &self.0
23    }
24
25    /// Consume the FactorId and return the inner String
26    pub fn into_inner(self) -> String {
27        self.0
28    }
29
30    /// Validate that the factor ID is well-formed
31    pub fn is_valid(&self) -> bool {
32        !self.0.is_empty()
33            && self.0.len() <= 64
34            && self.0.chars().all(|c| c.is_alphanumeric() || c == '_')
35    }
36}
37
38impl fmt::Display for FactorId {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        write!(f, "{}", self.0)
41    }
42}
43
44impl AsRef<str> for FactorId {
45    fn as_ref(&self) -> &str {
46        &self.0
47    }
48}
49
50impl From<String> for FactorId {
51    fn from(s: String) -> Self {
52        Self(s)
53    }
54}
55
56impl From<&str> for FactorId {
57    fn from(s: &str) -> Self {
58        Self(s.to_string())
59    }
60}
61
62impl From<FactorId> for String {
63    fn from(factor_id: FactorId) -> Self {
64        factor_id.0
65    }
66}
67
68impl PartialEq<str> for FactorId {
69    fn eq(&self, other: &str) -> bool {
70        self.0 == other
71    }
72}
73
74impl PartialEq<&str> for FactorId {
75    fn eq(&self, other: &&str) -> bool {
76        self.0 == *other
77    }
78}
79
80impl PartialEq<String> for FactorId {
81    fn eq(&self, other: &String) -> bool {
82        &self.0 == other
83    }
84}