use std::str::FromStr;
use convert_case::{Boundary, Case, Casing};
use crate::svd::BitRangeType;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum IdentifierFormat {
Camel,
Pascal,
Snake,
Constant,
}
impl FromStr for IdentifierFormat {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"Camel" => Ok(IdentifierFormat::Camel),
"Pascal" => Ok(IdentifierFormat::Pascal),
"Snake" => Ok(IdentifierFormat::Snake),
"Constant" => Ok(IdentifierFormat::Constant),
_ => Err(()),
}
}
}
pub fn change_case(s: &str, case: Option<IdentifierFormat>) -> String {
match case {
None => s.to_string(),
Some(case) => {
let boundary = [
Boundary::Underscore,
Boundary::Hyphen,
Boundary::Space,
Boundary::LowerUpper,
Boundary::UpperLower,
Boundary::Acronym,
];
s.with_boundaries(&boundary)
.to_case(match case {
IdentifierFormat::Camel => Case::Camel,
IdentifierFormat::Pascal => Case::Pascal,
IdentifierFormat::Snake => Case::Snake,
IdentifierFormat::Constant => Case::UpperSnake,
})
.replace("%S", "%s")
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NumberFormat {
UpperHex,
UpperHex8,
UpperHex16,
LowerHex,
LowerHex8,
LowerHex16,
Dec,
Bin,
}
impl FromStr for NumberFormat {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"UpperHex" => Ok(NumberFormat::UpperHex),
"UpperHex8" => Ok(NumberFormat::UpperHex8),
"UpperHex16" => Ok(NumberFormat::UpperHex16),
"LowerHex" => Ok(NumberFormat::LowerHex),
"LowerHex8" => Ok(NumberFormat::LowerHex8),
"LowerHex16" => Ok(NumberFormat::LowerHex16),
"Dec" => Ok(NumberFormat::Dec),
"Bin" => Ok(NumberFormat::Bin),
_ => Err(()),
}
}
}
pub fn format_number<T>(value: T, format: NumberFormat) -> String
where
T: std::fmt::UpperHex
+ std::fmt::LowerHex
+ std::fmt::Display
+ std::fmt::Binary
+ Into<u64>
+ Copy,
{
match format {
NumberFormat::UpperHex => format!("{:#X}", value),
NumberFormat::UpperHex8 => format!("{:#010X}", value),
NumberFormat::UpperHex16 => {
if value.into() > std::u32::MAX as u64 {
format!("{:#018X}", value)
} else {
format!("{:#010X}", value)
}
}
NumberFormat::LowerHex => format!("{:#x}", value),
NumberFormat::LowerHex8 => format!("{:#010x}", value),
NumberFormat::LowerHex16 => {
if value.into() > std::u32::MAX as u64 {
format!("{:#018x}", value)
} else {
format!("{:#010x}", value)
}
}
NumberFormat::Dec => format!("{}", value),
NumberFormat::Bin => format!("{:#b}", value),
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct FieldBitRangeFormat(pub BitRangeType);
impl FromStr for FieldBitRangeFormat {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"BitRange" => Ok(FieldBitRangeFormat(BitRangeType::BitRange)),
"OffsetWidth" => Ok(FieldBitRangeFormat(BitRangeType::OffsetWidth)),
"MsbLsb" => Ok(FieldBitRangeFormat(BitRangeType::MsbLsb)),
_ => Err(()),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum Sorting {
Offset,
OffsetReversed,
Name,
}
impl Sorting {
fn from_parts(parts: &[&str]) -> Option<Self> {
if parts.contains(&"Offset") {
Some(Self::Offset)
} else if parts.contains(&"OffsetReserved") {
Some(Self::OffsetReversed)
} else if parts.contains(&"Name") {
Some(Self::Name)
} else {
None
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DerivableSorting {
Unchanged(Option<Sorting>),
DeriveLast(Option<Sorting>),
}
impl DerivableSorting {
fn from_parts(parts: &[&str]) -> Self {
let sorting = Sorting::from_parts(parts);
if parts.contains(&"DerivedLast") {
Self::DeriveLast(sorting)
} else {
Self::Unchanged(sorting)
}
}
}
impl FromStr for DerivableSorting {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts = s.split(',').collect::<Vec<_>>();
Ok(DerivableSorting::from_parts(&parts))
}
}
impl Default for DerivableSorting {
fn default() -> Self {
Self::Unchanged(None)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RcSorting {
Unchanged(DerivableSorting),
RegistersFirst(DerivableSorting),
ClustersFirst(DerivableSorting),
}
impl Default for RcSorting {
fn default() -> Self {
Self::Unchanged(Default::default())
}
}
impl FromStr for RcSorting {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts = s.split(',').collect::<Vec<_>>();
let derivable_sorting = DerivableSorting::from_parts(&parts);
Ok(if parts.contains(&"RegistersFirst") {
Self::RegistersFirst(derivable_sorting)
} else if parts.contains(&"ClustersFirst") {
Self::ClustersFirst(derivable_sorting)
} else {
Self::Unchanged(derivable_sorting)
})
}
}
#[derive(Clone, Copy, Debug)]
#[non_exhaustive]
pub struct Config {
pub peripheral_name: Option<IdentifierFormat>,
pub peripheral_base_address: NumberFormat,
pub peripheral_sorting: DerivableSorting,
pub address_block_offset: NumberFormat,
pub address_block_size: NumberFormat,
pub interrupt_name: Option<IdentifierFormat>,
pub cluster_name: Option<IdentifierFormat>,
pub cluster_address_offset: NumberFormat,
pub register_cluster_sorting: RcSorting,
pub register_name: Option<IdentifierFormat>,
pub register_address_offset: NumberFormat,
pub register_size: NumberFormat,
pub register_reset_value: NumberFormat,
pub register_reset_mask: NumberFormat,
pub field_name: Option<IdentifierFormat>,
pub field_bit_range: Option<FieldBitRangeFormat>,
pub field_sorting: DerivableSorting,
pub enumerated_values_name: Option<IdentifierFormat>,
pub enumerated_value_name: Option<IdentifierFormat>,
pub enumerated_value_value: NumberFormat,
pub dim_dim: NumberFormat,
pub dim_increment: NumberFormat,
pub dim_array_index_header_enum_name: Option<IdentifierFormat>,
}
impl Default for Config {
fn default() -> Self {
Self {
peripheral_name: None,
peripheral_base_address: NumberFormat::UpperHex8,
peripheral_sorting: Default::default(),
address_block_offset: NumberFormat::UpperHex,
address_block_size: NumberFormat::UpperHex,
interrupt_name: None,
cluster_name: None,
cluster_address_offset: NumberFormat::UpperHex,
register_cluster_sorting: Default::default(),
register_name: None,
register_address_offset: NumberFormat::UpperHex,
register_size: NumberFormat::LowerHex,
register_reset_value: NumberFormat::UpperHex16,
register_reset_mask: NumberFormat::UpperHex16,
field_name: None,
field_bit_range: None,
field_sorting: Default::default(),
enumerated_values_name: None,
enumerated_value_name: None,
enumerated_value_value: NumberFormat::Dec,
dim_dim: NumberFormat::Dec,
dim_increment: NumberFormat::UpperHex,
dim_array_index_header_enum_name: None,
}
}
}
impl Config {
pub fn update(&mut self, name: &str, value: &str) {
match name {
"peripheral_name" => self.peripheral_name = Some(value.parse().unwrap()),
"peripheral_base_address" => self.peripheral_base_address = value.parse().unwrap(),
"peripheral_sorting" => self.peripheral_sorting = value.parse().unwrap(),
"address_block_offset" => self.address_block_offset = value.parse().unwrap(),
"address_block_size" => self.address_block_size = value.parse().unwrap(),
"interrupt_name" => self.interrupt_name = Some(value.parse().unwrap()),
"cluster_name" => self.cluster_name = Some(value.parse().unwrap()),
"cluster_address_offset" => self.cluster_address_offset = value.parse().unwrap(),
"register_cluster_sorting" => self.register_cluster_sorting = value.parse().unwrap(),
"register_name" => self.register_name = Some(value.parse().unwrap()),
"register_address_offset" => self.register_address_offset = value.parse().unwrap(),
"register_size" => self.register_size = value.parse().unwrap(),
"register_reset_value" => self.register_reset_value = value.parse().unwrap(),
"register_reset_mask" => self.register_reset_mask = value.parse().unwrap(),
"field_name" => self.field_name = Some(value.parse().unwrap()),
"field_bit_range" => self.field_bit_range = Some(value.parse().unwrap()),
"field_sorting" => self.field_sorting = value.parse().unwrap(),
"enumerated_values_name" => self.enumerated_values_name = Some(value.parse().unwrap()),
"enumerated_value_name" => self.enumerated_value_name = Some(value.parse().unwrap()),
"enumerated_value_value" => self.enumerated_value_value = value.parse().unwrap(),
"dim_dim" => self.dim_dim = value.parse().unwrap(),
"dim_increment" => self.dim_increment = value.parse().unwrap(),
"dim_array_index_header_enum_name" => {
self.dim_array_index_header_enum_name = Some(value.parse().unwrap())
}
_ => {
eprintln!("Unknown config key: {}", name);
}
}
}
pub fn peripheral_name(mut self, val: Option<IdentifierFormat>) -> Self {
self.peripheral_name = val;
self
}
pub fn peripheral_base_address(mut self, val: NumberFormat) -> Self {
self.peripheral_base_address = val;
self
}
pub fn peripheral_sorting(mut self, val: DerivableSorting) -> Self {
self.peripheral_sorting = val;
self
}
pub fn address_block_offset(mut self, val: NumberFormat) -> Self {
self.address_block_offset = val;
self
}
pub fn address_block_size(mut self, val: NumberFormat) -> Self {
self.address_block_size = val;
self
}
pub fn interrupt_name(mut self, val: Option<IdentifierFormat>) -> Self {
self.interrupt_name = val;
self
}
pub fn cluster_name(mut self, val: Option<IdentifierFormat>) -> Self {
self.cluster_name = val;
self
}
pub fn cluster_address_offset(mut self, val: NumberFormat) -> Self {
self.cluster_address_offset = val;
self
}
pub fn register_cluster_sorting(mut self, val: RcSorting) -> Self {
self.register_cluster_sorting = val;
self
}
pub fn register_name(mut self, val: Option<IdentifierFormat>) -> Self {
self.register_name = val;
self
}
pub fn register_address_offset(mut self, val: NumberFormat) -> Self {
self.register_address_offset = val;
self
}
pub fn register_size(mut self, val: NumberFormat) -> Self {
self.register_size = val;
self
}
pub fn register_reset_value(mut self, val: NumberFormat) -> Self {
self.register_reset_value = val;
self
}
pub fn register_reset_mask(mut self, val: NumberFormat) -> Self {
self.register_reset_mask = val;
self
}
pub fn field_name(mut self, val: Option<IdentifierFormat>) -> Self {
self.field_name = val;
self
}
pub fn field_bit_range(mut self, val: Option<FieldBitRangeFormat>) -> Self {
self.field_bit_range = val;
self
}
pub fn field_sorting(mut self, val: DerivableSorting) -> Self {
self.field_sorting = val;
self
}
pub fn enumerated_values_name(mut self, val: Option<IdentifierFormat>) -> Self {
self.enumerated_values_name = val;
self
}
pub fn enumerated_value_name(mut self, val: Option<IdentifierFormat>) -> Self {
self.enumerated_value_name = val;
self
}
pub fn enumerated_value_value(mut self, val: NumberFormat) -> Self {
self.enumerated_value_value = val;
self
}
pub fn dim_dim(mut self, val: NumberFormat) -> Self {
self.dim_dim = val;
self
}
pub fn dim_increment(mut self, val: NumberFormat) -> Self {
self.dim_increment = val;
self
}
}