astarte_interfaces/interface/
properties.rs1use std::{borrow::Cow, fmt::Display, str::FromStr};
24
25use serde::Serialize;
26
27use crate::{
28 error::Error,
29 mapping::{path::MappingPath, properties::PropertiesMapping, MappingError},
30 schema::{Aggregation, InterfaceJson, InterfaceType, Mapping, Ownership},
31};
32
33use super::{
34 name::InterfaceName, version::InterfaceVersion, AggregationIndividual, MappingVec, Schema,
35};
36
37#[derive(Debug, PartialEq, Eq, Clone)]
41pub struct Properties {
42 name: InterfaceName,
43 version: InterfaceVersion,
44 ownership: Ownership,
45 mappings: MappingVec<PropertiesMapping>,
46 #[cfg(feature = "doc-fields")]
47 #[cfg_attr(docsrs, doc(cfg(feature = "doc-fields")))]
48 description: Option<String>,
49 #[cfg(feature = "doc-fields")]
50 #[cfg_attr(docsrs, doc(cfg(feature = "doc-fields")))]
51 doc: Option<String>,
52}
53
54impl Schema for Properties {
55 type Mapping = PropertiesMapping;
56
57 fn name(&self) -> &str {
58 self.name.as_ref()
59 }
60
61 fn interface_name(&self) -> &InterfaceName {
62 &self.name
63 }
64
65 fn version_major(&self) -> i32 {
66 self.version.version_major()
67 }
68
69 fn version_minor(&self) -> i32 {
70 self.version.version_minor()
71 }
72
73 fn version(&self) -> InterfaceVersion {
74 self.version
75 }
76
77 fn interface_type(&self) -> InterfaceType {
78 InterfaceType::Properties
79 }
80
81 fn ownership(&self) -> Ownership {
82 self.ownership
83 }
84
85 fn aggregation(&self) -> Aggregation {
86 Aggregation::Individual
87 }
88
89 #[cfg(feature = "doc-fields")]
90 #[cfg_attr(docsrs, doc(cfg(feature = "doc-fields")))]
91 fn description(&self) -> Option<&str> {
92 self.description.as_deref()
93 }
94
95 #[cfg(feature = "doc-fields")]
96 #[cfg_attr(docsrs, doc(cfg(feature = "doc-fields")))]
97 fn doc(&self) -> Option<&str> {
98 self.doc.as_deref()
99 }
100
101 fn iter_mappings(&self) -> impl Iterator<Item = &Self::Mapping> {
102 self.mappings.iter()
103 }
104
105 fn mappings_len(&self) -> usize {
106 self.mappings.len()
107 }
108
109 fn iter_interface_mappings(&self) -> impl Iterator<Item = Mapping<Cow<'_, str>>> {
110 self.mappings.iter().map(Mapping::from)
111 }
112}
113
114impl AggregationIndividual for Properties {
115 fn mapping(&self, path: &MappingPath) -> Option<&Self::Mapping> {
116 self.mappings.get(path)
117 }
118}
119
120impl Display for Properties {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 write!(f, "{}:{}", self.name, self.version)
123 }
124}
125
126impl<T> TryFrom<InterfaceJson<T>> for Properties
127where
128 T: AsRef<str> + Into<String>,
129{
130 type Error = Error;
131
132 fn try_from(value: InterfaceJson<T>) -> Result<Self, Self::Error> {
133 if value.interface_type != InterfaceType::Properties
134 || value.aggregation.unwrap_or_default() != Aggregation::Individual
135 {
136 return Err(Error::InterfaceConversion {
137 exp_type: InterfaceType::Properties,
138 exp_aggregation: Aggregation::Individual,
139 got_type: value.interface_type,
140 got_aggregation: value.aggregation.unwrap_or_default(),
141 });
142 }
143
144 let name = InterfaceName::from_str_ref(value.interface_name)?;
145 let version = InterfaceVersion::try_new(value.version_major, value.version_minor)?;
146
147 let mappings = value
148 .mappings
149 .into_iter()
150 .map(PropertiesMapping::try_from)
151 .collect::<Result<Vec<_>, MappingError>>()
152 .and_then(MappingVec::try_from)?;
153
154 Ok(Self {
155 name: name.into_string(),
156 version,
157 ownership: value.ownership,
158 mappings,
159 #[cfg(feature = "doc-fields")]
160 description: value.description.as_ref().map(|v| v.as_ref().to_string()),
161 #[cfg(feature = "doc-fields")]
162 doc: value.doc.as_ref().map(|v| v.as_ref().to_string()),
163 })
164 }
165}
166
167impl Serialize for Properties {
168 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
169 where
170 S: serde::Serializer,
171 {
172 InterfaceJson::from(self).serialize(serializer)
173 }
174}
175
176impl FromStr for Properties {
177 type Err = Error;
178
179 fn from_str(s: &str) -> Result<Self, Self::Err> {
180 let interface: InterfaceJson<Cow<str>> = serde_json::from_str(s)?;
181
182 Self::try_from(interface)
183 }
184}