use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Property {
pub category: &'static str,
pub name: &'static str,
pub value: String,
}
impl Property {
#[must_use]
#[inline]
pub fn new(category: &'static str, name: &'static str, value: impl Into<String>) -> Self {
Self {
category,
name,
value: value.into(),
}
}
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct PropertySheet {
pub properties: Vec<Property>,
}
impl PropertySheet {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self {
properties: Vec::with_capacity(capacity),
}
}
pub fn push(&mut self, property: Property) {
self.properties.push(property);
}
#[must_use]
#[inline]
pub fn len(&self) -> usize {
self.properties.len()
}
#[must_use]
#[inline]
pub fn is_empty(&self) -> bool {
self.properties.is_empty()
}
#[must_use]
#[inline]
pub fn by_category(&self, category: &str) -> Vec<&Property> {
self.properties
.iter()
.filter(|p| p.category == category)
.collect()
}
#[must_use]
pub fn categories(&self) -> Vec<&'static str> {
let mut seen_set = std::collections::HashSet::new();
let mut seen = Vec::new();
for p in &self.properties {
if seen_set.insert(p.category) {
seen.push(p.category);
}
}
seen
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn property_new() {
let p = Property::new("Transform", "position", "(1, 2, 3)");
assert_eq!(p.category, "Transform");
assert_eq!(p.name, "position");
assert_eq!(p.value, "(1, 2, 3)");
}
#[test]
fn property_sheet_empty() {
let sheet = PropertySheet::new();
assert!(sheet.is_empty());
assert_eq!(sheet.len(), 0);
}
#[test]
fn property_sheet_push_and_query() {
let mut sheet = PropertySheet::new();
sheet.push(Property::new("Transform", "position", "(0, 0, 0)"));
sheet.push(Property::new("Transform", "rotation", "(0, 0, 0)"));
sheet.push(Property::new("Material", "color", "red"));
assert_eq!(sheet.len(), 3);
assert_eq!(sheet.by_category("Transform").len(), 2);
assert_eq!(sheet.by_category("Material").len(), 1);
assert_eq!(sheet.by_category("Audio").len(), 0);
}
#[test]
fn categories_ordered() {
let mut sheet = PropertySheet::new();
sheet.push(Property::new("B", "x", "1"));
sheet.push(Property::new("A", "y", "2"));
sheet.push(Property::new("B", "z", "3"));
let cats = sheet.categories();
assert_eq!(cats, vec!["B", "A"]);
}
#[test]
fn property_equality() {
let a = Property::new("T", "x", "1");
let b = Property::new("T", "x", "1");
assert_eq!(a, b);
}
#[test]
fn property_sheet_serialize() {
let mut sheet = PropertySheet::new();
sheet.push(Property::new("Transform", "x", "1.0"));
sheet.push(Property::new("Material", "color", "red"));
let json = serde_json::to_string(&sheet).unwrap();
assert!(json.contains("Transform"));
assert!(json.contains("Material"));
assert!(json.contains("red"));
}
#[test]
fn property_serde_serialize() {
let p = Property::new("Transform", "pos", "(1,2,3)");
let json = serde_json::to_string(&p).unwrap();
assert!(json.contains("Transform"));
assert!(json.contains("pos"));
assert!(json.contains("(1,2,3)"));
}
}