Skip to main content

dpp_aas/
property.rs

1use super::model::{AasCollection, AasDataType, AasProperty, AasSemId, AasSubmodelElement};
2
3/// The serde wire string for `value` — factors out the
4/// `serde_json::to_value(...).ok().and_then(|v| v.as_str().map(String::from)).unwrap_or_default()`
5/// idiom repeated across the sector builders to read an enum's serde-rename
6/// tag as a `String` for embedding in an AAS property.
7pub fn enum_wire_str<T: serde::Serialize>(value: &T) -> String {
8    serde_json::to_value(value)
9        .ok()
10        .and_then(|v| v.as_str().map(String::from))
11        .unwrap_or_default()
12}
13
14/// [`enum_wire_str`] for an `Option<T>` — `None` in, `None` out; a `Some(v)`
15/// that fails to serialize to a JSON string also yields `None` (matches the
16/// `if let Some(v) = ... && let Some(s) = serde_json::to_value(v)...` guards
17/// this replaces).
18pub fn opt_enum_wire_str<T: serde::Serialize>(value: &Option<T>) -> Option<String> {
19    let v = value.as_ref()?;
20    serde_json::to_value(v).ok()?.as_str().map(String::from)
21}
22
23/// The `svhc_{index}` collection shape shared by every sector that reports
24/// SVHC declarations: `casNumber`/`substanceName`/`concentrationPct` plus an
25/// optional `locationInProduct`. Returned as a bare [`AasCollection`] (not yet
26/// wrapped in [`AasSubmodelElement::SubmodelElementCollection`]) so a caller
27/// needing an extra per-substance field (e.g. textile's `scipNotificationId`)
28/// can push it onto `.value` before wrapping.
29pub fn svhc_substance_element(
30    index: usize,
31    cas_number: &str,
32    substance_name: &str,
33    concentration_pct: f64,
34    location_in_product: Option<&str>,
35) -> AasCollection {
36    let mut elems = vec![
37        string_property("casNumber", cas_number, None, None),
38        string_property("substanceName", substance_name, None, None),
39        double_property("concentrationPct", concentration_pct, None, Some("%")),
40    ];
41    if let Some(loc) = location_in_product {
42        elems.push(string_property("locationInProduct", loc, None, None));
43    }
44    AasCollection {
45        id_short: format!("svhc_{index}"),
46        value: elems,
47        semantic_id: None,
48    }
49}
50
51/// Create a string `Property` element.
52pub fn string_property(
53    id_short: &str,
54    value: &str,
55    semantic_id: Option<&str>,
56    unit: Option<&str>,
57) -> AasSubmodelElement {
58    AasSubmodelElement::Property(AasProperty {
59        id_short: id_short.into(),
60        value_type: AasDataType::String,
61        value: value.into(),
62        unit: unit.map(Into::into),
63        semantic_id: semantic_id.map(AasSemId::external),
64        description: None,
65    })
66}
67
68/// Create a double (float) `Property` element.
69pub fn double_property(
70    id_short: &str,
71    value: f64,
72    semantic_id: Option<&str>,
73    unit: Option<&str>,
74) -> AasSubmodelElement {
75    AasSubmodelElement::Property(AasProperty {
76        id_short: id_short.into(),
77        value_type: AasDataType::Double,
78        value: value.to_string(),
79        unit: unit.map(Into::into),
80        semantic_id: semantic_id.map(AasSemId::external),
81        description: None,
82    })
83}
84
85/// Create an integer `Property` element.
86pub fn integer_property(
87    id_short: &str,
88    value: i64,
89    semantic_id: Option<&str>,
90    unit: Option<&str>,
91) -> AasSubmodelElement {
92    AasSubmodelElement::Property(AasProperty {
93        id_short: id_short.into(),
94        value_type: AasDataType::Integer,
95        value: value.to_string(),
96        unit: unit.map(Into::into),
97        semantic_id: semantic_id.map(AasSemId::external),
98        description: None,
99    })
100}
101
102/// Create a boolean `Property` element.
103pub fn boolean_property(
104    id_short: &str,
105    value: bool,
106    semantic_id: Option<&str>,
107    unit: Option<&str>,
108) -> AasSubmodelElement {
109    AasSubmodelElement::Property(AasProperty {
110        id_short: id_short.into(),
111        value_type: AasDataType::Boolean,
112        value: value.to_string(),
113        unit: unit.map(Into::into),
114        semantic_id: semantic_id.map(AasSemId::external),
115        description: None,
116    })
117}