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 TypeConversion {
296 pub type_name: Spanned<IdentifierRef<Type>>,
298 pub fallible: bool,
300}
301
302#[derive(Debug, Clone, PartialEq)]
303pub struct Repeat {
304 pub source: Spanned<RepeatSource>,
305 pub stride: Spanned<i128>,
306 pub span: Span,
307}
308
309#[derive(Debug, Clone, PartialEq)]
310pub enum RepeatSource {
311 Count(NonZeroU32),
312 Enum(IdentifierRef<Type>),
313}
314
315#[derive(Debug, Clone, PartialEq, Eq, Hash)]
316pub enum ResetValue {
317 Integer(u128),
318 Array(Vec<u8>),
319}
320
321impl ResetValue {
322 #[must_use]
323 pub fn as_array(&self) -> Option<&Vec<u8>> {
324 if let Self::Array(v) = self {
325 Some(v)
326 } else {
327 None
328 }
329 }
330}
331
332#[derive(Debug, Clone, Copy, PartialEq, Eq)]
333pub enum NodeType {
334 Manifest,
335 Device,
336 Block,
337 Register,
338 Command,
339 Buffer,
340 FieldSet,
341 Enum,
342 Extern,
343 Field,
344}
345
346impl FromStr for NodeType {
347 type Err = ();
348
349 fn from_str(s: &str) -> Result<Self, Self::Err> {
350 match s {
351 "manifest" => Ok(Self::Manifest),
352 "device" => Ok(Self::Device),
353 "block" => Ok(Self::Block),
354 "register" => Ok(Self::Register),
355 "command" => Ok(Self::Command),
356 "buffer" => Ok(Self::Buffer),
357 "fieldset" => Ok(Self::FieldSet),
358 "enum" => Ok(Self::Enum),
359 "extern" => Ok(Self::Extern),
360 "field" => Ok(Self::Field),
361 _ => Err(()),
362 }
363 }
364}
365
366impl VariantNames for NodeType {
367 const VARIANTS: &'static [&'static str] = &[
368 "manifest", "device", "block", "register", "command", "buffer", "fieldset", "enum",
369 "extern", "field",
370 ];
371 fn name(&self) -> &'static str {
372 Self::VARIANTS[*self as usize]
373 }
374}
375
376impl Display for NodeType {
377 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
378 write!(f, "{}", Self::VARIANTS[*self as usize])
379 }
380}
381
382#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)]
383pub struct AddressRange {
384 pub start: u32,
385 pub end: u32,
387}
388
389impl AddressRange {
390 #[allow(clippy::len_without_is_empty, reason = "Range can never be empty")]
391 pub fn len(&self) -> u64 {
393 self.end as u64 - self.start as u64 + 1
394 }
395}
396
397#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
399#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
400pub enum AddressMode {
401 Mapped,
405 Indexed,
409}
410
411impl VariantNames for AddressMode {
412 const VARIANTS: &[&'static str] = &["mapped", "indexed"];
413 fn name(&self) -> &'static str {
414 Self::VARIANTS[*self as usize]
415 }
416}
417
418impl Display for AddressMode {
419 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
420 write!(f, "{}", Self::VARIANTS[*self as usize])
421 }
422}
423
424impl FromStr for AddressMode {
425 type Err = ();
426
427 fn from_str(s: &str) -> Result<Self, Self::Err> {
428 match s {
429 "mapped" => Ok(Self::Mapped),
430 "indexed" => Ok(Self::Indexed),
431 _ => Err(()),
432 }
433 }
434}