1use std::cmp::Ordering;
25use std::fmt::{self, Display, Formatter};
26use std::hash::{Hash, Hasher};
27use std::io;
28
29use crate::{ReadStruct, VariantName, WriteStruct, STRICT_TYPES_LIB};
30
31#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
33#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
34pub struct Sizing {
35 pub min: u64,
36 pub max: u64,
37}
38impl_strict_struct!(Sizing, STRICT_TYPES_LIB; min, max);
39
40impl Sizing {
41 pub const ONE: Sizing = Sizing { min: 1, max: 1 };
43
44 pub const U8: Sizing = Sizing {
45 min: 0,
46 max: u8::MAX as u64,
47 };
48
49 pub const U16: Sizing = Sizing {
50 min: 0,
51 max: u16::MAX as u64,
52 };
53
54 pub const U8_NONEMPTY: Sizing = Sizing {
55 min: 1,
56 max: u8::MAX as u64,
57 };
58
59 pub const U16_NONEMPTY: Sizing = Sizing {
60 min: 1,
61 max: u16::MAX as u64,
62 };
63
64 pub const fn new(min: u64, max: u64) -> Self { Sizing { min, max } }
65
66 pub const fn fixed(len: u64) -> Self { Sizing { min: len, max: len } }
67
68 pub const fn is_fixed(&self) -> bool { self.min == self.max }
69
70 pub const fn check(&self, len: usize) -> bool {
71 let len = len as u64;
72 len >= self.min && len <= self.max
73 }
74}
75
76impl Display for Sizing {
77 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
78 match (self.min, self.max) {
79 (0, 0xFFFF) => Ok(()),
80 (min, max) if min == max => write!(f, " ^ {min}"),
81 (0, max) => write!(f, " ^ ..{max:#x}"),
82 (min, 0xFFFF) => write!(f, " ^ {min}.."),
83 (min, max) => write!(f, " ^ {min}..{max:#x}"),
84 }
85 }
86}
87
88#[derive(Clone, Eq, Debug)]
89pub struct Variant {
90 pub name: VariantName,
91 pub tag: u8,
92}
93impl_strict_struct!(Variant, STRICT_TYPES_LIB; name, tag);
94
95#[cfg(feature = "serde")]
96mod _serde {
101 use std::str::FromStr;
102
103 use serde::ser::SerializeStruct;
104 use serde::{Deserialize, Deserializer, Serialize, Serializer};
105
106 use super::*;
107
108 impl Serialize for Variant {
109 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
110 where S: Serializer {
111 if serializer.is_human_readable() {
112 serializer.serialize_str(&format!("{}:{}", self.name, self.tag))
113 } else {
114 let mut s = serializer.serialize_struct("Variant", 2)?;
115 s.serialize_field("name", &self.name)?;
116 s.serialize_field("tag", &self.tag)?;
117 s.end()
118 }
119 }
120 }
121
122 impl<'de> Deserialize<'de> for Variant {
123 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
124 where D: Deserializer<'de> {
125 if deserializer.is_human_readable() {
126 let s = String::deserialize(deserializer)?;
127 let mut split = s.split(':');
128 let (name, tag) = (split.next(), split.next());
129 if split.next().is_some() {
130 return Err(serde::de::Error::custom(format!(
131 "Invalid variant format: '{}'. Expected 'name:tag'",
132 s
133 )));
134 }
135 match (name, tag) {
136 (Some(name), Some(tag)) => {
137 let name = VariantName::from_str(name).map_err(|e| {
138 serde::de::Error::custom(format!("Invalid variant name: {}", e))
139 })?;
140 let tag = tag.parse::<u8>().map_err(|e| {
141 serde::de::Error::custom(format!("Invalid variant tag: {}", e))
142 })?;
143 Ok(Variant { name, tag })
144 }
145 _ => Err(serde::de::Error::custom(format!(
146 "Invalid variant format: '{}'. Expected 'name:tag'",
147 s
148 ))),
149 }
150 } else {
151 #[cfg_attr(feature = "serde", derive(Deserialize), serde(rename = "Variant"))]
152 struct VariantFields {
153 name: VariantName,
154 tag: u8,
155 }
156 let VariantFields { name, tag } = VariantFields::deserialize(deserializer)?;
157 Ok(Variant { name, tag })
158 }
159 }
160 }
161}
162
163impl Variant {
164 pub fn named(tag: u8, name: VariantName) -> Variant { Variant { name, tag } }
165
166 pub fn none() -> Variant {
167 Variant {
168 name: vname!("none"),
169 tag: 0,
170 }
171 }
172 pub fn some() -> Variant {
173 Variant {
174 name: vname!("some"),
175 tag: 1,
176 }
177 }
178}
179
180impl PartialEq for Variant {
181 fn eq(&self, other: &Self) -> bool { self.tag == other.tag || self.name == other.name }
182}
183
184impl PartialOrd for Variant {
185 fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
186}
187
188impl Hash for Variant {
189 fn hash<H: Hasher>(&self, state: &mut H) {
190 self.tag.hash(state);
191 self.name.hash(state);
192 }
193}
194
195impl Ord for Variant {
196 fn cmp(&self, other: &Self) -> Ordering {
197 if self == other {
198 return Ordering::Equal;
199 }
200 self.tag.cmp(&other.tag)
201 }
202}
203
204impl Display for Variant {
205 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
206 write!(f, "{}", self.name)?;
207 Ok(())
208 }
209}
210
211#[cfg(test)]
212mod test {
213 #![allow(unused)]
214
215 use std::io::Cursor;
216
217 use crate::*;
218
219 #[cfg(feature = "serde")]
220 #[test]
221 fn variant_serde_roundtrip() {
222 let variant_orig = Variant::strict_dumb();
223
224 let mut buf = Vec::new();
226 ciborium::into_writer(&variant_orig, &mut buf).unwrap();
227 let variant_post: Variant = ciborium::from_reader(Cursor::new(&buf)).unwrap();
228 assert_eq!(variant_orig, variant_post);
229
230 let variant_str = serde_json::to_string(&variant_orig).unwrap();
232 let variant_post: Variant = serde_json::from_str(&variant_str).unwrap();
233 assert_eq!(variant_orig, variant_post);
234
235 let variant_str = serde_yaml::to_string(&variant_orig).unwrap();
237 let variant_post: Variant = serde_yaml::from_str(&variant_str).unwrap();
238 assert_eq!(variant_orig, variant_post);
239 }
240}