zed_refineable/
refineable.rs

1pub use derive_refineable::Refineable;
2
3/// A trait for types that can be refined with partial updates.
4///
5/// The `Refineable` trait enables hierarchical configuration patterns where a base configuration
6/// can be selectively overridden by refinements. This is particularly useful for styling and
7/// settings, and theme hierarchies.
8///
9/// # Derive Macro
10///
11/// The `#[derive(Refineable)]` macro automatically generates a companion refinement type and
12/// implements this trait. For a struct `Style`, it creates `StyleRefinement` where each field is
13/// wrapped appropriately:
14///
15/// - **Refineable fields** (marked with `#[refineable]`): Become the corresponding refinement type
16///   (e.g., `Bar` becomes `BarRefinement`)
17/// - **Optional fields** (`Option<T>`): Remain as `Option<T>`
18/// - **Regular fields**: Become `Option<T>`
19///
20/// ## Example
21///
22/// ```
23/// use derive_refineable::Refineable as _;
24/// use refineable::Refineable;
25///
26/// #[derive(Refineable, Clone, Default)]
27/// struct Example {
28///     color: String,
29///     font_size: Option<u32>,
30///     #[refineable]
31///     margin: Margin,
32/// }
33///
34/// #[derive(Refineable, Clone, Default)]
35/// struct Margin {
36///     top: u32,
37///     left: u32,
38/// }
39///
40///
41/// fn example() {
42///     let mut base_style = Example::default();
43///     let refinement = ExampleRefinement {
44///         color: Some("red".to_string()),
45///         font_size: None,
46///         margin: MarginRefinement {
47///             top: Some(10),
48///             left: None,
49///         },
50///     };
51///
52///     base_style.refine(&refinement);
53/// }
54/// ```
55///
56/// This generates `ExampleRefinement` with:
57/// - `color: Option<String>`
58/// - `font_size: Option<u32>` (unchanged)
59/// - `margin: MarginRefinement`
60///
61/// ## Attributes
62///
63/// The derive macro supports these attributes on the struct:
64/// - `#[refineable(Debug)]`: Implements `Debug` for the refinement type
65/// - `#[refineable(Serialize)]`: Derives `Serialize` which skips serializing `None`
66/// - `#[refineable(OtherTrait)]`: Derives additional traits on the refinement type
67///
68/// Fields can be marked with:
69/// - `#[refineable]`: Field is itself refineable (uses nested refinement type)
70pub trait Refineable: Clone {
71    type Refinement: Refineable<Refinement = Self::Refinement> + IsEmpty + Default;
72
73    /// Applies the given refinement to this instance, modifying it in place.
74    ///
75    /// Only non-empty values in the refinement are applied.
76    ///
77    /// * For refineable fields, this recursively calls `refine`.
78    /// * For other fields, the value is replaced if present in the refinement.
79    fn refine(&mut self, refinement: &Self::Refinement);
80
81    /// Returns a new instance with the refinement applied, equivalent to cloning `self` and calling
82    /// `refine` on it.
83    fn refined(self, refinement: Self::Refinement) -> Self;
84
85    /// Creates an instance from a cascade by merging all refinements atop the default value.
86    fn from_cascade(cascade: &Cascade<Self>) -> Self
87    where
88        Self: Default + Sized,
89    {
90        Self::default().refined(cascade.merged())
91    }
92
93    /// Returns `true` if this instance would contain all values from the refinement.
94    ///
95    /// For refineable fields, this recursively checks `is_superset_of`. For other fields, this
96    /// checks if the refinement's `Some` values match this instance's values.
97    fn is_superset_of(&self, refinement: &Self::Refinement) -> bool;
98
99    /// Returns a refinement that represents the difference between this instance and the given
100    /// refinement.
101    ///
102    /// For refineable fields, this recursively calls `subtract`. For other fields, the field is
103    /// `None` if the field's value is equal to the refinement.
104    fn subtract(&self, refinement: &Self::Refinement) -> Self::Refinement;
105}
106
107pub trait IsEmpty {
108    /// Returns `true` if applying this refinement would have no effect.
109    fn is_empty(&self) -> bool;
110}
111
112/// A cascade of refinements that can be merged in priority order.
113///
114/// A cascade maintains a sequence of optional refinements where later entries
115/// take precedence over earlier ones. The first slot (index 0) is always the
116/// base refinement and is guaranteed to be present.
117///
118/// This is useful for implementing configuration hierarchies like CSS cascading,
119/// where styles from different sources (user agent, user, author) are combined
120/// with specific precedence rules.
121pub struct Cascade<S: Refineable>(Vec<Option<S::Refinement>>);
122
123impl<S: Refineable + Default> Default for Cascade<S> {
124    fn default() -> Self {
125        Self(vec![Some(Default::default())])
126    }
127}
128
129/// A handle to a specific slot in a cascade.
130///
131/// Slots are used to identify specific positions in the cascade where
132/// refinements can be set or updated.
133#[derive(Copy, Clone)]
134pub struct CascadeSlot(usize);
135
136impl<S: Refineable + Default> Cascade<S> {
137    /// Reserves a new slot in the cascade and returns a handle to it.
138    ///
139    /// The new slot is initially empty (`None`) and can be populated later
140    /// using `set()`.
141    pub fn reserve(&mut self) -> CascadeSlot {
142        self.0.push(None);
143        CascadeSlot(self.0.len() - 1)
144    }
145
146    /// Returns a mutable reference to the base refinement (slot 0).
147    ///
148    /// The base refinement is always present and serves as the foundation
149    /// for the cascade.
150    pub fn base(&mut self) -> &mut S::Refinement {
151        self.0[0].as_mut().unwrap()
152    }
153
154    /// Sets the refinement for a specific slot in the cascade.
155    ///
156    /// Setting a slot to `None` effectively removes it from consideration
157    /// during merging.
158    pub fn set(&mut self, slot: CascadeSlot, refinement: Option<S::Refinement>) {
159        self.0[slot.0] = refinement
160    }
161
162    /// Merges all refinements in the cascade into a single refinement.
163    ///
164    /// Refinements are applied in order, with later slots taking precedence.
165    /// Empty slots (`None`) are skipped during merging.
166    pub fn merged(&self) -> S::Refinement {
167        let mut merged = self.0[0].clone().unwrap();
168        for refinement in self.0.iter().skip(1).flatten() {
169            merged.refine(refinement);
170        }
171        merged
172    }
173}