1use std::{fmt::Display, num::NonZeroU32, str::FromStr};
2
3use crate::{
4 identifier::{IdentifierRef, Type},
5 span::{Span, Spanned},
6};
7
8pub trait VariantNames {
9 const VARIANTS: &'static [&'static str];
11 fn name(&self) -> &'static str;
13}
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
16#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
17pub enum Integer {
18 U8,
19 U16,
20 U32,
21 U64,
22 I8,
23 I16,
24 #[default]
25 I32,
26 I64,
27}
28
29impl VariantNames for Integer {
30 const VARIANTS: &[&'static str] = &["u8", "u16", "u32", "u64", "i8", "i16", "i32", "i64"];
31 fn name(&self) -> &'static str {
32 Self::VARIANTS[*self as usize]
33 }
34}
35
36impl Display for Integer {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 write!(f, "{}", Self::VARIANTS[*self as usize])
39 }
40}
41
42impl FromStr for Integer {
43 type Err = ();
44
45 fn from_str(s: &str) -> Result<Self, Self::Err> {
46 match s {
47 "u8" => Ok(Self::U8),
48 "u16" => Ok(Self::U16),
49 "u32" => Ok(Self::U32),
50 "u64" => Ok(Self::U64),
51 "i8" => Ok(Self::I8),
52 "i16" => Ok(Self::I16),
53 "i32" => Ok(Self::I32),
54 "i64" => Ok(Self::I64),
55 _ => Err(()),
56 }
57 }
58}
59
60impl Integer {
61 #[must_use]
62 pub const fn is_signed(&self) -> bool {
63 self.min_value() != 0
64 }
65
66 #[must_use]
67 pub const fn min_value(&self) -> i128 {
68 match self {
69 Integer::U8 => u8::MIN as i128,
70 Integer::U16 => u16::MIN as i128,
71 Integer::U32 => u32::MIN as i128,
72 Integer::U64 => u64::MIN as i128,
73 Integer::I8 => i8::MIN as i128,
74 Integer::I16 => i16::MIN as i128,
75 Integer::I32 => i32::MIN as i128,
76 Integer::I64 => i64::MIN as i128,
77 }
78 }
79
80 #[must_use]
81 pub const fn max_value(&self) -> i128 {
82 match self {
83 Integer::U8 => u8::MAX as i128,
84 Integer::U16 => u16::MAX as i128,
85 Integer::U32 => u32::MAX as i128,
86 Integer::U64 => u64::MAX as i128,
87 Integer::I8 => i8::MAX as i128,
88 Integer::I16 => i16::MAX as i128,
89 Integer::I32 => i32::MAX as i128,
90 Integer::I64 => i64::MAX as i128,
91 }
92 }
93
94 #[must_use]
95 pub const fn size_bits(&self) -> u32 {
96 match self {
97 Integer::U8 => 8,
98 Integer::U16 => 16,
99 Integer::U32 => 32,
100 Integer::U64 => 64,
101 Integer::I8 => 8,
102 Integer::I16 => 16,
103 Integer::I32 => 32,
104 Integer::I64 => 64,
105 }
106 }
107
108 #[must_use]
114 pub const fn find_smallest(min: i128, max: i128, size_bits: u64) -> Option<Integer> {
115 Some(match (min, max, size_bits) {
116 (0.., ..0x1_00, ..=8) => Integer::U8,
117 (0.., ..0x1_0000, ..=16) => Integer::U16,
118 (0.., ..0x1_0000_0000, ..=32) => Integer::U32,
119 (0.., ..0x1_0000_0000_0000_0000, ..=64) => Integer::U64,
120 (-0x80.., ..0x80, ..=8) => Integer::I8,
121 (-0x8000.., ..0x8000, ..=16) => Integer::I16,
122 (-0x8000_00000.., ..0x8000_0000, ..=32) => Integer::I32,
123 (-0x8000_0000_0000_0000.., ..0x8000_0000_0000_0000, ..=64) => Integer::I64,
124 _ => return None,
125 })
126 }
127
128 #[must_use]
131 pub const fn bits_required(&self, min: i128, max: i128) -> u32 {
132 assert!(max >= min);
133
134 if self.is_signed() {
135 let min_bits = if min.is_negative() {
136 i128::BITS - (min.abs() - 1).leading_zeros() + 1
137 } else {
138 0
139 };
140 let max_bits = if max.is_positive() {
141 i128::BITS - max.leading_zeros() + 1
142 } else {
143 0
144 };
145
146 if min_bits > max_bits {
147 min_bits
148 } else {
149 max_bits
150 }
151 } else {
152 assert!(min >= 0);
153 i128::BITS - max.leading_zeros()
154 }
155 }
156}
157
158#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)]
159#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
160pub enum Access {
161 #[default]
162 RW,
163 RO,
164 WO,
165}
166
167impl Access {
168 #[must_use]
169 pub fn is_readable(&self) -> bool {
170 match self {
171 Access::RW => true,
172 Access::RO => true,
173 Access::WO => false,
174 }
175 }
176 #[must_use]
177 pub fn is_writable(&self) -> bool {
178 match self {
179 Access::RW => true,
180 Access::RO => false,
181 Access::WO => true,
182 }
183 }
184}
185
186impl VariantNames for Access {
187 const VARIANTS: &[&'static str] = &["RW", "RO", "WO"];
188 fn name(&self) -> &'static str {
189 Self::VARIANTS[*self as usize]
190 }
191}
192
193impl Display for Access {
194 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
195 write!(f, "{}", Self::VARIANTS[*self as usize])
196 }
197}
198
199impl FromStr for Access {
200 type Err = ();
201
202 fn from_str(s: &str) -> Result<Self, Self::Err> {
203 match s {
204 "RW" => Ok(Self::RW),
205 "RO" => Ok(Self::RO),
206 "WO" => Ok(Self::WO),
207 _ => Err(()),
208 }
209 }
210}
211
212#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
213#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
214pub enum ByteOrder {
215 #[default]
216 LE,
217 BE,
218}
219
220impl VariantNames for ByteOrder {
221 const VARIANTS: &[&'static str] = &["LE", "BE"];
222 fn name(&self) -> &'static str {
223 Self::VARIANTS[*self as usize]
224 }
225}
226
227impl Display for ByteOrder {
228 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
229 write!(f, "{}", Self::VARIANTS[*self as usize])
230 }
231}
232
233impl FromStr for ByteOrder {
234 type Err = ();
235
236 fn from_str(s: &str) -> Result<Self, Self::Err> {
237 match s {
238 "LE" => Ok(Self::LE),
239 "BE" => Ok(Self::BE),
240 _ => Err(()),
241 }
242 }
243}
244
245#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)]
246#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
247pub enum BaseType {
248 #[default]
249 Unspecified,
250 Bool,
251 Uint,
252 Int,
253 FixedSize(Integer),
254}
255
256impl BaseType {
257 #[must_use]
261 pub fn is_unspecified(&self) -> bool {
262 matches!(self, Self::Unspecified)
263 }
264
265 #[must_use]
269 pub fn is_fixed_size(&self) -> bool {
270 matches!(self, Self::FixedSize(..))
271 }
272
273 pub fn as_fixed_size(&self) -> Option<Integer> {
274 if let Self::FixedSize(v) = self {
275 Some(*v)
276 } else {
277 None
278 }
279 }
280}
281
282impl Display for BaseType {
283 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
284 match self {
285 BaseType::Unspecified => write!(f, "_"),
286 BaseType::Bool => write!(f, "bool"),
287 BaseType::Uint => write!(f, "uint"),
288 BaseType::Int => write!(f, "int"),
289 BaseType::FixedSize(integer) => write!(f, "{integer}"),
290 }
291 }
292}
293
294#[derive(Debug, Clone, PartialEq)]
295pub struct Repeat {
296 pub source: Spanned<RepeatSource>,
297 pub stride: Spanned<i128>,
298 pub span: Span,
299}
300
301#[derive(Debug, Clone, PartialEq)]
302pub enum RepeatSource {
303 Count(NonZeroU32),
304 Enum(IdentifierRef<Type>),
305}
306
307#[derive(Debug, Clone, PartialEq, Eq, Hash)]
308pub enum ResetValue {
309 Integer(u128),
310 Array(Vec<u8>),
311}
312
313impl ResetValue {
314 #[must_use]
315 pub fn as_array(&self) -> Option<&Vec<u8>> {
316 if let Self::Array(v) = self {
317 Some(v)
318 } else {
319 None
320 }
321 }
322}
323
324#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
325pub enum NodeType {
326 Manifest,
327 Device,
328 Block,
329 Register,
330 Command,
331 Buffer,
332 FieldSet,
333 Enum,
334 Extern,
335 Field,
336}
337
338impl FromStr for NodeType {
339 type Err = ();
340
341 fn from_str(s: &str) -> Result<Self, Self::Err> {
342 match s {
343 "manifest" => Ok(Self::Manifest),
344 "device" => Ok(Self::Device),
345 "block" => Ok(Self::Block),
346 "register" => Ok(Self::Register),
347 "command" => Ok(Self::Command),
348 "buffer" => Ok(Self::Buffer),
349 "fieldset" => Ok(Self::FieldSet),
350 "enum" => Ok(Self::Enum),
351 "extern" => Ok(Self::Extern),
352 "field" => Ok(Self::Field),
353 _ => Err(()),
354 }
355 }
356}
357
358impl VariantNames for NodeType {
359 const VARIANTS: &'static [&'static str] = &[
360 "manifest", "device", "block", "register", "command", "buffer", "fieldset", "enum",
361 "extern", "field",
362 ];
363 fn name(&self) -> &'static str {
364 Self::VARIANTS[*self as usize]
365 }
366}
367
368impl Display for NodeType {
369 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
370 write!(f, "{}", Self::VARIANTS[*self as usize])
371 }
372}
373
374#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)]
375pub struct AddressRange {
376 pub start: u32,
377 pub end: u32,
379}
380
381impl AddressRange {
382 #[allow(clippy::len_without_is_empty, reason = "Range can never be empty")]
383 pub fn len(&self) -> u64 {
385 self.end as u64 - self.start as u64 + 1
386 }
387}
388
389#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
391#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
392pub enum AddressMode {
393 Mapped,
397 Indexed,
401}
402
403impl VariantNames for AddressMode {
404 const VARIANTS: &[&'static str] = &["mapped", "indexed"];
405 fn name(&self) -> &'static str {
406 Self::VARIANTS[*self as usize]
407 }
408}
409
410impl Display for AddressMode {
411 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
412 write!(f, "{}", Self::VARIANTS[*self as usize])
413 }
414}
415
416impl FromStr for AddressMode {
417 type Err = ();
418
419 fn from_str(s: &str) -> Result<Self, Self::Err> {
420 match s {
421 "mapped" => Ok(Self::Mapped),
422 "indexed" => Ok(Self::Indexed),
423 _ => Err(()),
424 }
425 }
426}
427
428#[cfg(test)]
429mod tests {
430 use super::*;
431
432 #[test]
433 fn correct_integer_size_bits() {
434 assert_eq!(Integer::U8.bits_required(0, 0), 0);
435 assert_eq!(Integer::U8.bits_required(0, 1), 1);
436 assert_eq!(Integer::U8.bits_required(0, 2), 2);
437 assert_eq!(Integer::U8.bits_required(0, 3), 2);
438 assert_eq!(Integer::U8.bits_required(0, 4), 3);
439
440 assert_eq!(Integer::I8.bits_required(0, 0), 0);
441 assert_eq!(Integer::I8.bits_required(-1, 0), 1);
442 assert_eq!(Integer::I8.bits_required(-1, 1), 2);
443 assert_eq!(Integer::I8.bits_required(0, 1), 2);
444 assert_eq!(Integer::I8.bits_required(-2, 1), 2);
445 assert_eq!(Integer::I8.bits_required(0, 2), 3);
446 assert_eq!(Integer::I8.bits_required(-128, 0), 8);
447 assert_eq!(Integer::I8.bits_required(-129, 0), 9);
448 assert_eq!(Integer::I8.bits_required(0, 127), 8);
449 assert_eq!(Integer::I8.bits_required(0, 128), 9);
450 assert_eq!(Integer::I8.bits_required(-16, 15), 5);
451 assert_eq!(Integer::I8.bits_required(-16, 16), 6);
452 assert_eq!(Integer::I8.bits_required(-17, 15), 6);
453 }
454}