omf/
element.rs

1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4
5use crate::{
6    Attribute, Color, Geometry, Location,
7    validate::{Validate, Validator},
8};
9
10/// Defines a single "object" or "shape" within the OMF file.
11///
12/// Each shape has a name plus other optional metadata, a "geometry" that describes
13/// a point-set, surface, etc., and a list of attributes that that exist on that geometry.
14#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
15pub struct Element {
16    /// The element name. Names should be non-empty and unique.
17    pub name: String,
18    /// Optional element description.
19    #[serde(default, skip_serializing_if = "String::is_empty")]
20    pub description: String,
21    /// Optional solid color.
22    #[serde(default, skip_serializing_if = "Option::is_none")]
23    pub color: Option<Color>,
24    /// Arbitrary metadata.
25    #[serde(default, skip_serializing_if = "serde_json::Map::is_empty")]
26    pub metadata: serde_json::Map<String, Value>,
27    /// List of attributes, if any.
28    #[serde(default, skip_serializing_if = "Vec::is_empty")]
29    pub attributes: Vec<Attribute>,
30    /// The geometry of the element.
31    pub geometry: Geometry,
32}
33
34impl Element {
35    /// Create a new element with the given name and geometry.
36    ///
37    /// Geometries will be automatically converted from their objects into enum variants.
38    pub fn new(name: impl Into<String>, geometry: impl Into<Geometry>) -> Self {
39        Self {
40            name: name.into(),
41            description: Default::default(),
42            metadata: Default::default(),
43            attributes: Default::default(),
44            geometry: geometry.into(),
45            color: None,
46        }
47    }
48
49    /// Returns the valid locations for attributes on this element.
50    pub fn valid_locations(&self) -> &'static [Location] {
51        self.geometry.valid_locations()
52    }
53
54    /// Returns the number of values needed for the given location.
55    pub fn location_len(&self, location: Location) -> Option<u64> {
56        self.geometry.location_len(location)
57    }
58}
59
60impl Validate for Element {
61    fn validate_inner(&mut self, val: &mut Validator) {
62        val.enter("Element")
63            .name(&self.name)
64            .obj(&mut self.geometry)
65            .objs(&mut self.attributes)
66            .unique(
67                self.attributes.iter().map(|a| &a.name),
68                "attributes[..]::name",
69                false,
70            )
71            .attrs_on_geometry(&self.attributes, &self.geometry);
72    }
73}