use std::{fmt::Display, num::NonZeroU32, str::FromStr};
use crate::{
identifier::{IdentifierRef, Type},
span::{Span, Spanned},
};
pub trait VariantNames {
const VARIANTS: &'static [&'static str];
fn name(&self) -> &'static str;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum Integer {
U8,
U16,
U32,
U64,
I8,
I16,
#[default]
I32,
I64,
}
impl VariantNames for Integer {
const VARIANTS: &[&'static str] = &["u8", "u16", "u32", "u64", "i8", "i16", "i32", "i64"];
fn name(&self) -> &'static str {
Self::VARIANTS[*self as usize]
}
}
impl Display for Integer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", Self::VARIANTS[*self as usize])
}
}
impl FromStr for Integer {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"u8" => Ok(Self::U8),
"u16" => Ok(Self::U16),
"u32" => Ok(Self::U32),
"u64" => Ok(Self::U64),
"i8" => Ok(Self::I8),
"i16" => Ok(Self::I16),
"i32" => Ok(Self::I32),
"i64" => Ok(Self::I64),
_ => Err(()),
}
}
}
impl Integer {
#[must_use]
pub const fn is_signed(&self) -> bool {
self.min_value() != 0
}
#[must_use]
pub const fn min_value(&self) -> i128 {
match self {
Integer::U8 => u8::MIN as i128,
Integer::U16 => u16::MIN as i128,
Integer::U32 => u32::MIN as i128,
Integer::U64 => u64::MIN as i128,
Integer::I8 => i8::MIN as i128,
Integer::I16 => i16::MIN as i128,
Integer::I32 => i32::MIN as i128,
Integer::I64 => i64::MIN as i128,
}
}
#[must_use]
pub const fn max_value(&self) -> i128 {
match self {
Integer::U8 => u8::MAX as i128,
Integer::U16 => u16::MAX as i128,
Integer::U32 => u32::MAX as i128,
Integer::U64 => u64::MAX as i128,
Integer::I8 => i8::MAX as i128,
Integer::I16 => i16::MAX as i128,
Integer::I32 => i32::MAX as i128,
Integer::I64 => i64::MAX as i128,
}
}
#[must_use]
pub const fn size_bits(&self) -> u32 {
match self {
Integer::U8 => 8,
Integer::U16 => 16,
Integer::U32 => 32,
Integer::U64 => 64,
Integer::I8 => 8,
Integer::I16 => 16,
Integer::I32 => 32,
Integer::I64 => 64,
}
}
#[must_use]
pub const fn find_smallest(min: i128, max: i128, size_bits: u64) -> Option<Integer> {
Some(match (min, max, size_bits) {
(0.., ..0x1_00, ..=8) => Integer::U8,
(0.., ..0x1_0000, ..=16) => Integer::U16,
(0.., ..0x1_0000_0000, ..=32) => Integer::U32,
(0.., ..0x1_0000_0000_0000_0000, ..=64) => Integer::U64,
(-0x80.., ..0x80, ..=8) => Integer::I8,
(-0x8000.., ..0x8000, ..=16) => Integer::I16,
(-0x8000_00000.., ..0x8000_0000, ..=32) => Integer::I32,
(-0x8000_0000_0000_0000.., ..0x8000_0000_0000_0000, ..=64) => Integer::I64,
_ => return None,
})
}
#[must_use]
pub const fn bits_required(&self, min: i128, max: i128) -> u32 {
assert!(max >= min);
if self.is_signed() {
let min_bits = if min.is_negative() {
i128::BITS - (min.abs() - 1).leading_zeros() + 1
} else {
0
};
let max_bits = if max.is_positive() {
i128::BITS - max.leading_zeros() + 1
} else {
0
};
if min_bits > max_bits {
min_bits
} else {
max_bits
}
} else {
assert!(min >= 0);
i128::BITS - max.leading_zeros()
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum Access {
#[default]
RW,
RO,
WO,
}
impl Access {
#[must_use]
pub fn is_readable(&self) -> bool {
match self {
Access::RW => true,
Access::RO => true,
Access::WO => false,
}
}
#[must_use]
pub fn is_writable(&self) -> bool {
match self {
Access::RW => true,
Access::RO => false,
Access::WO => true,
}
}
}
impl VariantNames for Access {
const VARIANTS: &[&'static str] = &["RW", "RO", "WO"];
fn name(&self) -> &'static str {
Self::VARIANTS[*self as usize]
}
}
impl Display for Access {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", Self::VARIANTS[*self as usize])
}
}
impl FromStr for Access {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"RW" => Ok(Self::RW),
"RO" => Ok(Self::RO),
"WO" => Ok(Self::WO),
_ => Err(()),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum ByteOrder {
#[default]
LE,
BE,
}
impl VariantNames for ByteOrder {
const VARIANTS: &[&'static str] = &["LE", "BE"];
fn name(&self) -> &'static str {
Self::VARIANTS[*self as usize]
}
}
impl Display for ByteOrder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", Self::VARIANTS[*self as usize])
}
}
impl FromStr for ByteOrder {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"LE" => Ok(Self::LE),
"BE" => Ok(Self::BE),
_ => Err(()),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum BaseType {
#[default]
Unspecified,
Bool,
Uint,
Int,
FixedSize(Integer),
}
impl BaseType {
#[must_use]
pub fn is_unspecified(&self) -> bool {
matches!(self, Self::Unspecified)
}
#[must_use]
pub fn is_fixed_size(&self) -> bool {
matches!(self, Self::FixedSize(..))
}
pub fn as_fixed_size(&self) -> Option<Integer> {
if let Self::FixedSize(v) = self {
Some(*v)
} else {
None
}
}
}
impl Display for BaseType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BaseType::Unspecified => write!(f, "_"),
BaseType::Bool => write!(f, "bool"),
BaseType::Uint => write!(f, "uint"),
BaseType::Int => write!(f, "int"),
BaseType::FixedSize(integer) => write!(f, "{integer}"),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TypeConversion {
pub type_name: Spanned<IdentifierRef<Type>>,
pub fallible: bool,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Repeat {
pub source: Spanned<RepeatSource>,
pub stride: Spanned<i128>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub enum RepeatSource {
Count(NonZeroU32),
Enum(IdentifierRef<Type>),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ResetValue {
Integer(u128),
Array(Vec<u8>),
}
impl ResetValue {
#[must_use]
pub fn as_array(&self) -> Option<&Vec<u8>> {
if let Self::Array(v) = self {
Some(v)
} else {
None
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NodeType {
Manifest,
Device,
Block,
Register,
Command,
Buffer,
FieldSet,
Enum,
Extern,
Field,
}
impl FromStr for NodeType {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"manifest" => Ok(Self::Manifest),
"device" => Ok(Self::Device),
"block" => Ok(Self::Block),
"register" => Ok(Self::Register),
"command" => Ok(Self::Command),
"buffer" => Ok(Self::Buffer),
"fieldset" => Ok(Self::FieldSet),
"enum" => Ok(Self::Enum),
"extern" => Ok(Self::Extern),
"field" => Ok(Self::Field),
_ => Err(()),
}
}
}
impl VariantNames for NodeType {
const VARIANTS: &'static [&'static str] = &[
"manifest", "device", "block", "register", "command", "buffer", "fieldset", "enum",
"extern", "field",
];
fn name(&self) -> &'static str {
Self::VARIANTS[*self as usize]
}
}
impl Display for NodeType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", Self::VARIANTS[*self as usize])
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)]
pub struct AddressRange {
pub start: u32,
pub end: u32,
}
impl AddressRange {
#[allow(clippy::len_without_is_empty, reason = "Range can never be empty")]
pub fn len(&self) -> u64 {
self.end as u64 - self.start as u64 + 1
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum AddressMode {
Mapped,
Indexed,
}
impl VariantNames for AddressMode {
const VARIANTS: &[&'static str] = &["mapped", "indexed"];
fn name(&self) -> &'static str {
Self::VARIANTS[*self as usize]
}
}
impl Display for AddressMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", Self::VARIANTS[*self as usize])
}
}
impl FromStr for AddressMode {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"mapped" => Ok(Self::Mapped),
"indexed" => Ok(Self::Indexed),
_ => Err(()),
}
}
}