pub use derive_refineable::Refineable; /// A trait for types that can be refined with partial updates. /// /// The `Refineable` trait enables hierarchical configuration patterns where a base configuration /// can be selectively overridden by refinements. This is particularly useful for styling and /// settings, and theme hierarchies. /// /// # Derive Macro /// /// The `#[derive(Refineable)]` macro automatically generates a companion refinement type and /// implements this trait. For a struct `Style`, it creates `StyleRefinement` where each field is /// wrapped appropriately: /// /// - **Refineable fields** (marked with `#[refineable]`): Become the corresponding refinement type /// (e.g., `Bar` becomes `BarRefinement`) /// - **Optional fields** (`Option`): Remain as `Option` /// - **Regular fields**: Become `Option` /// /// ## Example /// /// ```rust /// #[derive(Refineable, Clone, Default)] /// struct Example { /// color: String, /// font_size: Option, /// #[refineable] /// margin: Margin, /// } /// /// #[derive(Refineable, Clone, Default)] /// struct Margin { /// top: u32, /// left: u32, /// } /// /// /// fn example() { /// let mut example = Example::default(); /// let refinement = ExampleRefinement { /// color: Some("red".to_string()), /// font_size: None, /// margin: MarginRefinement { /// top: Some(10), /// left: None, /// }, /// }; /// /// base_style.refine(&refinement); /// } /// ``` /// /// This generates `ExampleRefinement` with: /// - `color: Option` /// - `font_size: Option` (unchanged) /// - `margin: MarginRefinement` /// /// ## Attributes /// /// The derive macro supports these attributes on the struct: /// - `#[refineable(Debug)]`: Implements `Debug` for the refinement type /// - `#[refineable(Serialize)]`: Derives `Serialize` which skips serializing `None` /// - `#[refineable(OtherTrait)]`: Derives additional traits on the refinement type /// /// Fields can be marked with: /// - `#[refineable]`: Field is itself refineable (uses nested refinement type) pub trait Refineable: Clone { type Refinement: Refineable + IsEmpty + Default; /// Applies the given refinement to this instance, modifying it in place. /// /// Only non-empty values in the refinement are applied. /// /// * For refineable fields, this recursively calls `refine`. /// * For other fields, the value is replaced if present in the refinement. fn refine(&mut self, refinement: &Self::Refinement); /// Returns a new instance with the refinement applied, equivalent to cloning `self` and calling /// `refine` on it. fn refined(self, refinement: Self::Refinement) -> Self; /// Creates an instance from a cascade by merging all refinements atop the default value. fn from_cascade(cascade: &Cascade) -> Self where Self: Default + Sized, { Self::default().refined(cascade.merged()) } /// Returns `true` if this instance would contain all values from the refinement. /// /// For refineable fields, this recursively checks `is_superset_of`. For other fields, this /// checks if the refinement's `Some` values match this instance's values. fn is_superset_of(&self, refinement: &Self::Refinement) -> bool; /// Returns a refinement that represents the difference between this instance and the given /// refinement. /// /// For refineable fields, this recursively calls `subtract`. For other fields, the field is /// `None` if the field's value is equal to the refinement. fn subtract(&self, refinement: &Self::Refinement) -> Self::Refinement; } pub trait IsEmpty { /// Returns `true` if applying this refinement would have no effect. fn is_empty(&self) -> bool; } /// A cascade of refinements that can be merged in priority order. /// /// A cascade maintains a sequence of optional refinements where later entries /// take precedence over earlier ones. The first slot (index 0) is always the /// base refinement and is guaranteed to be present. /// /// This is useful for implementing configuration hierarchies like CSS cascading, /// where styles from different sources (user agent, user, author) are combined /// with specific precedence rules. pub struct Cascade(Vec>); impl Default for Cascade { fn default() -> Self { Self(vec![Some(Default::default())]) } } /// A handle to a specific slot in a cascade. /// /// Slots are used to identify specific positions in the cascade where /// refinements can be set or updated. #[derive(Copy, Clone)] pub struct CascadeSlot(usize); impl Cascade { /// Reserves a new slot in the cascade and returns a handle to it. /// /// The new slot is initially empty (`None`) and can be populated later /// using `set()`. pub fn reserve(&mut self) -> CascadeSlot { self.0.push(None); CascadeSlot(self.0.len() - 1) } /// Returns a mutable reference to the base refinement (slot 0). /// /// The base refinement is always present and serves as the foundation /// for the cascade. pub fn base(&mut self) -> &mut S::Refinement { self.0[0].as_mut().unwrap() } /// Sets the refinement for a specific slot in the cascade. /// /// Setting a slot to `None` effectively removes it from consideration /// during merging. pub fn set(&mut self, slot: CascadeSlot, refinement: Option) { self.0[slot.0] = refinement } /// Merges all refinements in the cascade into a single refinement. /// /// Refinements are applied in order, with later slots taking precedence. /// Empty slots (`None`) are skipped during merging. pub fn merged(&self) -> S::Refinement { let mut merged = self.0[0].clone().unwrap(); for refinement in self.0.iter().skip(1).flatten() { merged.refine(refinement); } merged } }