use crate::{
error::{EvalError, EvalResult, InterpreterError},
value::{ExceptionValue, Value},
};
pub fn has_function(name: &str) -> bool {
matches!(name, "auto" | "unique")
}
fn enum_unique(state: &crate::state::InterpreterState, args: &[Value]) -> EvalResult {
let Some(cls) = args.first() else {
return Err(InterpreterError::TypeError(
"unique() missing 1 required positional argument".into(),
)
.into());
};
let Value::Class(name) = cls else {
return Err(InterpreterError::TypeError(format!(
"{} is not an enum class",
cls.type_name()
))
.into());
};
if let Some(class) = state.classes.get(name) {
#[allow(clippy::mutable_key_type)]
let mut seen: rustc_hash::FxHashMap<crate::value::ValueKey, String> =
rustc_hash::FxHashMap::default();
let mut dups: Vec<String> = Vec::new();
for member in &class.enum_members {
let value = match class.class_attrs.get(member) {
Some(Value::EnumMember { value, .. }) => (**value).clone(),
Some(v) => v.clone(),
None => continue,
};
let Ok(key) = crate::eval::literals::value_to_key(&value) else { continue };
if let Some(canonical) = seen.get(&key) {
dups.push(format!("{member} -> {canonical}"));
} else {
seen.insert(key, member.clone());
}
}
if !dups.is_empty() {
return Err(EvalError::Exception(ExceptionValue::new(
"ValueError",
format!("duplicate values found in <enum '{name}'>: {}", dups.join(", ")),
)));
}
}
Ok(cls.clone())
}
#[must_use]
pub fn auto_sentinel() -> Value {
Value::ModuleFunction { module: "enum".into(), name: "__auto__".into() }
}
#[must_use]
pub fn is_auto_sentinel(value: &Value) -> bool {
matches!(value, Value::ModuleFunction { module, name } if module == "enum" && name == "__auto__")
}
pub fn call(func: &str, _args: &[Value]) -> EvalResult {
match func {
"auto" => {
Ok(auto_sentinel())
}
_ => Err(InterpreterError::AttributeError(format!(
"module 'enum' has no attribute '{func}'"
))
.into()),
}
}
pub fn constant(name: &str) -> Option<Value> {
match name {
"Enum" | "IntEnum" | "StrEnum" | "Flag" | "IntFlag" => {
Some(Value::Type(format!("enum.{name}")))
}
_ => None,
}
}
pub struct EnumModule;
#[async_trait::async_trait]
impl crate::eval::modules::Module for EnumModule {
fn name(&self) -> &'static str {
"enum"
}
fn constant(&self, name: &str) -> Option<Value> {
constant(name)
}
fn has_function(&self, name: &str) -> bool {
has_function(name)
}
async fn call(
&self,
state: &mut crate::state::InterpreterState,
func: &str,
args: &[Value],
_kwargs: &indexmap::IndexMap<String, Value>,
_tools: &crate::tools::Tools,
) -> EvalResult {
if func == "unique" {
return enum_unique(state, args);
}
call(func, args)
}
}