use alloc::{string::String, vec::Vec};
use crate::shared::{
StyleClass,
style_class::{StyleClassError, StyleProperty},
};
#[derive(Default, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct StyleClassBuilder {
name: Option<String>,
properties: Vec<StyleProperty>,
}
impl TryFrom<StyleClassBuilder> for StyleClass {
type Error = StyleClassError;
fn try_from(builder: StyleClassBuilder) -> Result<Self, Self::Error> {
if builder.properties.is_empty() {
return Err(StyleClassError::MissingProperties);
}
Ok(StyleClass {
name: builder.name.ok_or(StyleClassError::MissingName)?,
properties: builder.properties,
})
}
}
impl StyleClassBuilder {
pub fn name(mut self, name: impl Into<String>) -> Result<Self, StyleClassError> {
let name = name.into();
if name.is_empty() {
return Err(StyleClassError::EmptyName);
}
self.name = Some(name);
Ok(self)
}
pub fn property(mut self, property: StyleProperty) -> Result<Self, StyleClassError> {
if self.properties.contains(&property) {
return Err(StyleClassError::DuplicateProperty(property));
}
self.properties.push(property);
Ok(self)
}
pub fn build(self) -> Result<StyleClass, StyleClassError> {
self.try_into()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::shared::style_class::color::Color;
#[test]
fn test_style_class_builder() -> Result<(), StyleClassError> {
let style_class = StyleClassBuilder::default()
.name("myClass")?
.property(StyleProperty::Fill(Color::from((255, 0, 0))))?
.property(StyleProperty::Stroke(Color::from((0, 0, 255))))?
.build()?;
assert_eq!(style_class.name, "myClass");
assert_eq!(style_class.properties.len(), 2);
assert!(style_class.properties.contains(&StyleProperty::Fill(Color::from((255, 0, 0)))));
assert!(style_class.properties.contains(&StyleProperty::Stroke(Color::from((0, 0, 255)))));
Ok(())
}
#[test]
fn test_style_class_builder_errors() -> Result<(), alloc::boxed::Box<dyn core::error::Error>> {
let builder = StyleClassBuilder::default();
assert!(matches!(builder.name(""), Err(StyleClassError::EmptyName)));
let builder = StyleClassBuilder::default().name("myClass")?;
assert!(matches!(builder.build(), Err(StyleClassError::MissingProperties)));
let builder = StyleClassBuilder::default()
.name("myClass")?
.property(StyleProperty::Fill(Color::from((255, 0, 0))))?;
assert!(matches!(
builder.property(StyleProperty::Fill(Color::from((255, 0, 0)))),
Err(StyleClassError::DuplicateProperty(_))
));
Ok(())
}
}