qubit_codec/value/
value_codec_id.rs1use core::borrow::Borrow;
10
11use crate::ValueCodecIdError;
12
13#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
24pub struct ValueCodecId(&'static str);
25
26impl ValueCodecId {
27 #[must_use]
33 pub const fn new(value: &'static str) -> Self {
34 match Self::try_new(value) {
35 Ok(id) => id,
36 Err(_) => panic!("invalid value codec ID"),
37 }
38 }
39
40 pub const fn try_new(value: &'static str) -> Result<Self, ValueCodecIdError> {
46 match validate(value) {
47 Ok(()) => Ok(Self(value)),
48 Err(error) => Err(error),
49 }
50 }
51
52 #[must_use]
54 pub const fn as_str(self) -> &'static str {
55 self.0
56 }
57}
58
59impl Borrow<str> for ValueCodecId {
60 fn borrow(&self) -> &str {
62 self.0
63 }
64}
65
66const fn validate(value: &str) -> Result<(), ValueCodecIdError> {
68 let bytes = value.as_bytes();
69 if bytes.is_empty() {
70 return Err(ValueCodecIdError::Empty);
71 }
72 let mut start = 0;
73 let mut index = 0;
74 while index < bytes.len() {
75 if bytes[index] == b'.' {
76 if start == index || index + 1 == bytes.len() {
77 return Err(ValueCodecIdError::EmptySegment);
78 }
79 if let Err(error) = validate_segment(bytes, start, index) {
80 return Err(error);
81 }
82 start = index + 1;
83 }
84 index += 1;
85 }
86 validate_segment(bytes, start, bytes.len())
87}
88
89const fn validate_segment(bytes: &[u8], start: usize, end: usize) -> Result<(), ValueCodecIdError> {
91 if start == end || !bytes[start].is_ascii_alphabetic() {
92 return Err(ValueCodecIdError::InvalidSegment);
93 }
94 let mut index = start + 1;
95 while index < end {
96 let byte = bytes[index];
97 if !(byte.is_ascii_alphanumeric() || byte == b'_') {
98 return Err(ValueCodecIdError::InvalidSegment);
99 }
100 index += 1;
101 }
102 Ok(())
103}