use std::collections::HashSet;
use std::str::FromStr;
use getset::{CloneGetters, CopyGetters, Getters};
use proc_macro2::Span;
use strum::IntoEnumIterator;
use strum_macros::{Display, EnumIter, EnumString};
use syn::parse::{Parse, ParseStream};
use crate::parsing::common::attribute_argument_parser::{
parse_attribute_arguments, parse_boolean_attribute_argument,
};
use crate::parsing::common::compiler_error::create_user_parsing_compiler_error;
use crate::parsing::common::const_expr::ConstExpr;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum FieldAccess {
ReadOnly,
WriteOnly,
ReadWrite,
NoAccess,
}
impl FromStr for FieldAccess {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_ascii_lowercase().as_str() {
"ro" => Ok(Self::ReadOnly),
"wo" => Ok(Self::WriteOnly),
"rw" => Ok(Self::ReadWrite),
"na" => Ok(Self::NoAccess),
_ => Err(format!(
"Invalid field access argument '{s}'. Valid values are 'ro', 'wo', 'rw', or 'na'."
)),
}
}
}
#[derive(Clone, Debug, Getters, CopyGetters, CloneGetters)]
pub struct BitsArguments {
#[getset(get_copy = "pub")]
access: FieldAccess,
#[getset(get_copy = "pub")]
access_span: Option<Span>,
#[getset(get_copy = "pub")]
user_set_access: bool,
#[getset(get_copy = "pub")]
ignored: bool,
#[getset(get_clone = "pub")]
default_value_expr: Option<ConstExpr>,
}
impl Default for BitsArguments {
fn default() -> Self {
Self {
access: FieldAccess::ReadWrite,
access_span: None,
user_set_access: false,
ignored: false,
default_value_expr: None,
}
}
}
#[derive(Display, EnumString, EnumIter)]
enum BitsArgumentKey {
#[strum(serialize = "access")]
Access,
#[strum(serialize = "ignore")]
Ignore,
#[strum(serialize = "default")]
Default,
}
impl Parse for BitsArguments {
fn parse(input: ParseStream) -> syn::Result<Self> {
let valid_keys = BitsArgumentKey::iter().map(|k| k.to_string()).collect();
let attribute_arguments = parse_attribute_arguments(
input,
valid_keys,
HashSet::default(),
)?;
let mut bits_arguments = Self::default();
for argument in attribute_arguments {
match BitsArgumentKey::from_str(argument.key().token().as_str())
.expect("This should be caught by the known keys check")
{
BitsArgumentKey::Access => {
bits_arguments.access =
FieldAccess::from_str(argument.value().token().as_str()).map_err(
|err| create_user_parsing_compiler_error(argument.value().span(), err),
)?;
bits_arguments.user_set_access = true;
bits_arguments.access_span = Some(argument.value().span());
},
BitsArgumentKey::Ignore => {
bits_arguments.ignored = parse_boolean_attribute_argument(argument)?;
},
BitsArgumentKey::Default => {
bits_arguments.default_value_expr = Some(ConstExpr::new(&argument.value())?);
},
}
}
Ok(bits_arguments)
}
}