Skip to main content

component_shape/
metadata.rs

1use crate::ComponentSuffix;
2
3/// Whether a component shape publishes render-component metadata.
4#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5pub enum RenderCapability {
6    /// No render component is published.
7    None,
8    /// A render component is published.
9    Component,
10}
11
12impl RenderCapability {
13    /// Returns whether rendering is enabled.
14    pub const fn enabled(self) -> bool {
15        matches!(self, Self::Component)
16    }
17}
18
19/// Whether a component shape publishes value-binding metadata.
20#[derive(Clone, Copy, Debug, Eq, PartialEq)]
21pub enum ValueBindingCapability {
22    /// No value binding is published.
23    None,
24    /// Value binding is inherited from a backing component state contract.
25    Inherited,
26}
27
28impl ValueBindingCapability {
29    /// Returns whether value binding is enabled.
30    pub const fn enabled(self) -> bool {
31        matches!(self, Self::Inherited)
32    }
33}
34
35/// Shape-owned capability flags consumed by generators and integrations.
36#[derive(Clone, Copy, Debug, Eq, PartialEq)]
37pub struct ComponentCapabilities {
38    render: RenderCapability,
39    value_binding: ValueBindingCapability,
40}
41
42impl ComponentCapabilities {
43    /// Creates capability metadata with no optional capabilities enabled.
44    pub const fn new() -> Self {
45        Self {
46            render: RenderCapability::None,
47            value_binding: ValueBindingCapability::None,
48        }
49    }
50
51    /// Replaces the render capability.
52    pub const fn with_render(mut self, render: RenderCapability) -> Self {
53        self.render = render;
54        self
55    }
56
57    /// Replaces the value-binding capability.
58    pub const fn with_value_binding(mut self, value_binding: ValueBindingCapability) -> Self {
59        self.value_binding = value_binding;
60        self
61    }
62
63    /// Returns the render capability.
64    pub const fn render(self) -> RenderCapability {
65        self.render
66    }
67
68    /// Returns the value-binding capability.
69    pub const fn value_binding(self) -> ValueBindingCapability {
70        self.value_binding
71    }
72
73    /// Returns whether a render component is published.
74    pub const fn render_component(self) -> bool {
75        self.render.enabled()
76    }
77
78    /// Returns whether value binding is enabled.
79    pub const fn value_binding_enabled(self) -> bool {
80        self.value_binding.enabled()
81    }
82}
83
84impl Default for ComponentCapabilities {
85    fn default() -> Self {
86        Self::new()
87    }
88}
89
90/// Shape-owned metadata for prototyping generators.
91#[derive(Clone, Copy, Debug, Eq, PartialEq)]
92pub struct ComponentPrototyping {
93    /// Preferred generated prototyping helper suffix, such as `"input"` or `"select"`.
94    pub field_suffix: Option<ComponentSuffix>,
95}
96
97impl ComponentPrototyping {
98    /// Creates prototyping metadata with no preferred field suffix.
99    pub const fn new() -> Self {
100        Self { field_suffix: None }
101    }
102
103    /// Sets the preferred generated prototyping helper suffix.
104    ///
105    /// # Panics
106    ///
107    /// Panics when `suffix` is not a valid component suffix.
108    pub const fn field_suffix(mut self, suffix: &'static str) -> Self {
109        self.field_suffix = Some(ComponentSuffix::new(suffix));
110        self
111    }
112}
113
114impl Default for ComponentPrototyping {
115    fn default() -> Self {
116        Self::new()
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::{
123        ComponentCapabilities, ComponentPrototyping, RenderCapability, ValueBindingCapability,
124    };
125
126    #[test]
127    fn component_capabilities_default_to_no_runtime_features() {
128        let capabilities = ComponentCapabilities::new();
129
130        assert_eq!(capabilities.render(), RenderCapability::None);
131        assert_eq!(capabilities.value_binding(), ValueBindingCapability::None);
132        assert!(!capabilities.render_component());
133        assert!(!capabilities.value_binding_enabled());
134        assert_eq!(ComponentCapabilities::default(), capabilities);
135    }
136
137    #[test]
138    fn component_capabilities_builders_set_independent_features() {
139        let capabilities = ComponentCapabilities::new()
140            .with_render(RenderCapability::Component)
141            .with_value_binding(ValueBindingCapability::Inherited);
142
143        assert_eq!(capabilities.render(), RenderCapability::Component);
144        assert_eq!(
145            capabilities.value_binding(),
146            ValueBindingCapability::Inherited
147        );
148        assert!(capabilities.render_component());
149        assert!(capabilities.value_binding_enabled());
150    }
151
152    #[test]
153    fn component_prototyping_field_suffix_records_suffix() {
154        let prototyping = ComponentPrototyping::new().field_suffix("input");
155
156        assert_eq!(
157            prototyping.field_suffix.map(crate::ComponentSuffix::as_str),
158            Some("input")
159        );
160        assert_eq!(ComponentPrototyping::default(), ComponentPrototyping::new());
161    }
162}