Skip to main content

device_driver_common/
specifiers.rs

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    /// Names of the variants of this enum
10    const VARIANTS: &'static [&'static str];
11    /// Get the name of the current instance
12    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    /// Find the smallest integer type that can fully contain the min and max
109    /// and is equal or larger than the given `size_bits`.
110    ///
111    /// This function has a preference for unsigned integers.
112    /// You can force a signed integer by making the min be negative (e.g. -1)
113    #[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    /// Given the min and the max and the sign of the integer,
129    /// how many bits are required to fit the min and max? (inclusive)
130    #[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    /// Returns `true` if the base type is [`Unspecified`].
258    ///
259    /// [`Unspecified`]: BaseType::Unspecified
260    #[must_use]
261    pub fn is_unspecified(&self) -> bool {
262        matches!(self, Self::Unspecified)
263    }
264
265    /// Returns `true` if the base type is [`FixedSize`].
266    ///
267    /// [`FixedSize`]: BaseType::FixedSize
268    #[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    /// The name of the type we're converting to
297    pub type_name: Spanned<IdentifierRef<Type>>,
298    /// True when we want to use the fallible interface (like a Result<type, error>)
299    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    /// Inclusive end
386    pub end: u32,
387}
388
389impl AddressRange {
390    #[allow(clippy::len_without_is_empty, reason = "Range can never be empty")]
391    /// The amount of bits this range covers
392    pub fn len(&self) -> u64 {
393        self.end as u64 - self.start as u64 + 1
394    }
395}
396
397/// Type to specify how addresses work
398#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
399#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
400pub enum AddressMode {
401    /// Objects are memory-mapped.
402    ///
403    /// If object `A` has address `X` and is `Y` bytes big, then object `B` (if it exists) will have the address `X+Y`.
404    Mapped,
405    /// Objects are sequentially indexed.
406    ///
407    /// If object `A` has address `X`, then object `B` (if it exists) will have the address `X+1`.
408    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}