@@ -296,7 +296,7 @@ pub fn refine_theme_family(theme_family_content: ThemeFamilyContent) -> ThemeFam
fn make_colors_unique<T, F>(colors: &mut T, color_to_count: &mut collections::HashMap<Hsla, u32>)
where
F: Copy + strum::IntoEnumIterator,
- T: util::FieldAccessByEnum<Field = F, FieldValue = Hsla>,
+ T: util::FieldAccessByEnum<Hsla, Field = F>,
{
for field in F::iter() {
let mut color = *colors.get_field_by_enum(field);
@@ -35,50 +35,6 @@ pub use util_macros::FieldAccessByEnum;
#[cfg(any(test, feature = "test-support"))]
pub use util_macros::{line_endings, path, uri};
-// todo! dedupe docs
-
-/// Trait for types that can access their fields via an enum.
-///
-/// This trait provides a way to dynamically access and modify fields of a struct
-/// using an enum that represents the field names. It's particularly useful for
-/// implementing generic field access patterns, such as theme color management
-/// or configuration field manipulation.
-///
-/// # Example
-///
-/// ```rust
-/// use util::FieldAccessByEnum;
-///
-/// #[derive(util_macros::FieldAccessByEnum)]
-/// #[field_access_by_enum(enum_name = "ColorField", field_type = "String")]
-/// struct Theme {
-/// background: String,
-/// foreground: String,
-/// border: String,
-/// }
-///
-/// let mut theme = Theme {
-/// background: "white".to_string(),
-/// foreground: "black".to_string(),
-/// border: "gray".to_string(),
-/// };
-///
-/// // Access field via enum
-/// let bg = theme.get(ColorField::Background);
-/// theme.set(ColorField::Foreground, "blue".to_string());
-/// ```
-pub trait FieldAccessByEnum {
- /// The enum type representing the available fields
- type Field;
- /// The type of values stored in the fields
- type FieldValue;
-
- /// Get a reference to the value of the specified field
- fn get_field_by_enum(&self, field: Self::Field) -> &Self::FieldValue;
- /// Set the value of the specified field
- fn set_field_by_enum(&mut self, field: Self::Field, value: Self::FieldValue);
-}
-
#[macro_export]
macro_rules! debug_panic {
( $($fmt_arg:tt)* ) => {
@@ -1149,6 +1105,53 @@ pub fn some_or_debug_panic<T>(option: Option<T>) -> Option<T> {
option
}
+/// Trait that provides field access specified by enum.
+///
+/// The derive macro only supports structs with named fields that all have the same type.
+///
+/// # Example
+///
+/// ```rust
+/// #[derive(FieldAccessByEnum)]
+/// #[field_access_by_enum(
+/// enum_name = "ColorField",
+/// enum_attrs = [
+/// derive(Debug, Clone, Copy, EnumIter, AsRefStr),
+/// strum(serialize_all = "snake_case")
+/// ],
+/// )]
+/// struct Theme {
+/// background: Hsla,
+/// foreground: Hsla,
+/// border_color: Hsla,
+/// }
+/// ```
+///
+/// This generates:
+/// ```rust
+/// #[derive(Debug, Clone, Copy, EnumIter, AsRefStr)]
+/// #[strum(serialize_all = "snake_case")]
+/// enum ColorField {
+/// Background,
+/// Foreground,
+/// BorderColor,
+/// }
+///
+/// impl FieldAccessByEnum<Hsla> for Theme {
+/// type Field = ColorField;
+/// // ... get and set methods
+/// }
+/// ```
+pub trait FieldAccessByEnum<V> {
+ /// The enum type representing the available fields
+ type Field;
+
+ /// Get a reference to the value of the specified field
+ fn get_field_by_enum(&self, field: Self::Field) -> &V;
+ /// Set the value of the specified field
+ fn set_field_by_enum(&mut self, field: Self::Field, value: V);
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -91,43 +91,6 @@ pub fn line_endings(input: TokenStream) -> TokenStream {
})
}
-/// Derive macro that generates an enum and implements `FieldAccessByEnum`. Only works for structs
-/// with named fields where every field has the same type.
-///
-/// # Example
-///
-/// ```rust
-/// #[derive(FieldAccessByEnum)]
-/// #[field_access_by_enum(
-/// enum_name = "ColorField",
-/// enum_attrs = [
-/// derive(Debug, Clone, Copy, EnumIter, AsRefStr),
-/// strum(serialize_all = "snake_case")
-/// ],
-/// )]
-/// struct Theme {
-/// background: Hsla,
-/// foreground: Hsla,
-/// border_color: Hsla,
-/// }
-/// ```
-///
-/// This generates:
-/// ```rust
-/// #[derive(Debug, Clone, Copy, EnumIter, AsRefStr)]
-/// #[strum(serialize_all = "snake_case")]
-/// enum ColorField {
-/// Background,
-/// Foreground,
-/// BorderColor,
-/// }
-///
-/// impl FieldAccessByEnum for Theme {
-/// type Field = ColorField;
-/// type FieldValue = Hsla;
-/// // ... get and set methods
-/// }
-/// ```
#[proc_macro_derive(FieldAccessByEnum, attributes(field_access_by_enum))]
pub fn derive_field_access_by_enum(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
@@ -161,6 +124,12 @@ pub fn derive_field_access_by_enum(input: TokenStream) -> TokenStream {
}
_ => panic!("Expected array literal in enum_attr attribute"),
}
+ } else {
+ if let Some(ident) = name_value.path.get_ident() {
+ panic!("Unrecognized argument name {}", ident);
+ } else {
+ panic!("Unrecognized argument {:?}", name_value.path);
+ }
}
}
}
@@ -220,17 +189,16 @@ pub fn derive_field_access_by_enum(input: TokenStream) -> TokenStream {
#(#enum_variants),*
}
- impl util::FieldAccessByEnum for #struct_name {
+ impl util::FieldAccessByEnum<#field_value_type> for #struct_name {
type Field = #enum_ident;
- type FieldValue = #field_value_type;
- fn get_field_by_enum(&self, field: Self::Field) -> &Self::FieldValue {
+ fn get_field_by_enum(&self, field: Self::Field) -> &#field_value_type {
match field {
#(#get_match_arms)*
}
}
- fn set_field_by_enum(&mut self, field: Self::Field, value: Self::FieldValue) {
+ fn set_field_by_enum(&mut self, field: Self::Field, value: #field_value_type) {
match field {
#(#set_match_arms)*
}