use std::fmt::Display;
use gen_utils::{
error::{Error, ParseError},
parser::parse_value,
};
use super::Value;
#[derive(Debug, Clone, PartialEq)]
pub struct Enum {
pub field_chain: Vec<EnumItem>,
}
impl Enum {
pub fn leaf(&self) -> Option<&EnumItem> {
self.field_chain.last()
}
pub fn is_anonymous(&self) -> bool {
self.field_chain.len() == 1
}
pub fn parse_template(s: &str) -> Result<Self, Error> {
Self::parse(s, false)
}
pub fn parse_style(s: &str) -> Result<Self, Error> {
Self::parse(s, true)
}
fn parse(s: &str, is_style: bool) -> Result<Self, Error> {
if s.contains("::") {
let mut field_chain = vec![];
let enum_str = s.split("::").collect::<Vec<&str>>();
for (index, item) in enum_str.iter().enumerate() {
if index == 0 {
field_chain.push(EnumItem::Root(item.to_string()));
} else if index < enum_str.len() - 1 {
field_chain.push(EnumItem::Branch(item.to_string()));
} else {
field_chain.push(Self::parse_leaf(item, is_style)?);
}
}
return Ok(Enum { field_chain });
} else {
let leaf = Self::parse_leaf(s, is_style)?;
return Ok(Enum {
field_chain: vec![leaf],
});
}
}
fn parse_leaf(s: &str, is_style: bool) -> Result<EnumItem, Error> {
let s = s.trim();
match parse_value(s) {
Ok((input, s)) => {
return if input.starts_with("(") && input.ends_with(")") {
let input = input
.strip_prefix('(')
.and_then(|x| x.strip_suffix(')'))
.unwrap_or(input);
Ok(EnumItem::Leaf(
s.to_string(),
Some(if is_style {
Value::parse_style(input)?
} else {
Value::parse_template(input)?
}),
))
} else if input.starts_with("{") && input.ends_with("}") {
Ok(EnumItem::Leaf(
s.to_string(),
Some(if is_style {
Value::parse_style(input)?
} else {
Value::parse_template(input)?
}),
))
} else {
if Value::check_unknown(s) {
return Ok(EnumItem::Leaf(s.to_string(), None));
}
return Err(ParseError::template("style Enum leaf parse failed").into());
};
}
Err(_) => Err(ParseError::template("style Enum leaf parse failed").into()),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum EnumItem {
Root(String),
Branch(String),
Leaf(String, Option<Value>),
}
impl Display for EnumItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
EnumItem::Root(s) => f.write_str(s),
EnumItem::Branch(s) => f.write_str(s),
EnumItem::Leaf(s, v) => {
if let Some(v) = v {
if let Value::Struct(inner) = v {
f.write_fmt(format_args!("{}{}", s, inner))
} else {
f.write_fmt(format_args!("{}({})", s, v))
}
} else {
f.write_str(s)
}
}
}
}
}
impl Display for Enum {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(
&self
.field_chain
.iter()
.map(|x| x.to_string())
.collect::<Vec<String>>()
.join("::"),
)
}
}