1use super::{BuildError, EmptyToNone, EnumeratedValue, SvdError, ValidateLevel};
2use std::borrow::Cow;
3use std::ops::RangeInclusive;
4
5#[cfg_attr(
7 feature = "serde",
8 derive(serde::Deserialize, serde::Serialize),
9 serde(rename_all = "camelCase")
10)]
11#[derive(Clone, Debug, PartialEq, Eq)]
12#[non_exhaustive]
13pub struct DimElement {
14 pub dim: u32,
16
17 pub dim_increment: u32,
19
20 #[cfg_attr(
23 feature = "serde",
24 serde(
25 deserialize_with = "ser_de::deserialize_dim_index",
26 serialize_with = "ser_de::serialize_dim_index",
27 skip_serializing_if = "Option::is_none"
28 )
29 )]
30 pub dim_index: Option<Vec<String>>,
31
32 #[cfg_attr(
34 feature = "serde",
35 serde(default, skip_serializing_if = "Option::is_none")
36 )]
37 pub dim_name: Option<String>,
38
39 #[cfg_attr(
41 feature = "serde",
42 serde(default, skip_serializing_if = "Option::is_none")
43 )]
44 pub dim_array_index: Option<DimArrayIndex>,
45}
46
47#[cfg_attr(
54 feature = "serde",
55 derive(serde::Deserialize, serde::Serialize),
56 serde(rename_all = "camelCase")
57)]
58#[derive(Clone, Debug, PartialEq, Eq)]
59pub struct DimArrayIndex {
60 #[cfg_attr(
62 feature = "serde",
63 serde(default, skip_serializing_if = "Option::is_none")
64 )]
65 pub header_enum_name: Option<String>,
66
67 pub values: Vec<EnumeratedValue>,
69}
70
71#[derive(Clone, Debug, Default, PartialEq, Eq)]
73pub struct DimElementBuilder {
74 dim: Option<u32>,
75 dim_increment: Option<u32>,
76 dim_index: Option<Vec<String>>,
77 dim_name: Option<String>,
78 dim_array_index: Option<DimArrayIndex>,
79}
80
81impl From<DimElement> for DimElementBuilder {
82 fn from(d: DimElement) -> Self {
83 Self {
84 dim: Some(d.dim),
85 dim_increment: Some(d.dim_increment),
86 dim_index: d.dim_index,
87 dim_name: d.dim_name,
88 dim_array_index: d.dim_array_index,
89 }
90 }
91}
92
93impl DimElementBuilder {
94 pub fn dim(mut self, value: u32) -> Self {
96 self.dim = Some(value);
97 self
98 }
99 pub fn dim_increment(mut self, value: u32) -> Self {
101 self.dim_increment = Some(value);
102 self
103 }
104 pub fn dim_index(mut self, value: Option<Vec<String>>) -> Self {
106 self.dim_index = value;
107 self
108 }
109 pub fn dim_name(mut self, value: Option<String>) -> Self {
111 self.dim_name = value;
112 self
113 }
114 pub fn dim_array_index(mut self, value: Option<DimArrayIndex>) -> Self {
116 self.dim_array_index = value;
117 self
118 }
119 pub fn build(self, lvl: ValidateLevel) -> Result<DimElement, SvdError> {
121 let de = DimElement {
122 dim: self
123 .dim
124 .ok_or_else(|| BuildError::Uninitialized("dim".to_string()))?,
125 dim_increment: self
126 .dim_increment
127 .ok_or_else(|| BuildError::Uninitialized("dim_increment".to_string()))?,
128 dim_index: self.dim_index.empty_to_none(),
129 dim_name: self.dim_name.empty_to_none(),
130 dim_array_index: self.dim_array_index,
131 };
132 de.validate(lvl)?;
133 Ok(de)
134 }
135}
136
137impl DimElement {
138 pub fn builder() -> DimElementBuilder {
140 DimElementBuilder::default()
141 }
142
143 pub fn parse_indexes(text: &str) -> Option<Vec<String>> {
145 (if text.contains('-') {
146 let (start, end) = text.split_once('-')?;
147 if let (Ok(start), Ok(end)) = (start.parse::<u32>(), end.parse::<u32>()) {
148 Some((start..=end).map(|i| i.to_string()).collect::<Vec<_>>())
149 } else {
150 let mut start = start.bytes();
151 let mut end = end.bytes();
152 match (start.next(), start.next(), end.next(), end.next()) {
153 (Some(start), None, Some(end), None)
154 if (start.is_ascii_lowercase() && end.is_ascii_lowercase())
155 || (start.is_ascii_uppercase() && end.is_ascii_uppercase()) =>
156 {
157 Some((start..=end).map(|c| char::from(c).to_string()).collect())
158 }
159 _ => None,
160 }
161 }
162 } else {
163 Some(text.split(',').map(|s| s.to_string()).collect())
164 })
165 .filter(|v| !v.is_empty())
166 }
167 pub fn indexes_as_range(&self) -> Option<RangeInclusive<u32>> {
169 let mut integers = Vec::with_capacity(self.dim as usize);
170 for idx in self.indexes() {
171 let val = idx.parse::<u32>().ok()?;
174 if val.to_string() != idx {
175 return None;
176 }
177 integers.push(val);
178 }
179 let min = *integers.iter().min()?;
180 let max = *integers.iter().max()?;
181 if max - min + 1 != self.dim {
182 return None;
183 }
184 for (&i, r) in integers.iter().zip(min..=max) {
185 if i != r {
186 return None;
187 }
188 }
189 Some(min..=max)
190 }
191 pub fn modify_from(
193 &mut self,
194 builder: DimElementBuilder,
195 lvl: ValidateLevel,
196 ) -> Result<(), SvdError> {
197 if let Some(dim) = builder.dim {
198 self.dim = dim;
199 }
200 if let Some(dim_increment) = builder.dim_increment {
201 self.dim_increment = dim_increment;
202 }
203 if builder.dim_index.is_some() {
204 self.dim_index = builder.dim_index.empty_to_none();
205 }
206 if builder.dim_name.is_some() {
207 self.dim_name = builder.dim_name.empty_to_none();
208 }
209 if builder.dim_array_index.is_some() {
210 self.dim_array_index = builder.dim_array_index;
211 }
212 self.validate(lvl)
213 }
214 pub fn validate(&self, _lvl: ValidateLevel) -> Result<(), SvdError> {
220 Ok(())
222 }
223 pub fn indexes(&self) -> Indexes {
225 Indexes {
226 i: 0,
227 dim: self.dim,
228 dim_index: &self.dim_index,
229 }
230 }
231}
232
233pub struct Indexes<'a> {
235 i: u32,
236 dim: u32,
237 dim_index: &'a Option<Vec<String>>,
238}
239
240impl<'a> Iterator for Indexes<'a> {
241 type Item = Cow<'a, str>;
242 fn next(&mut self) -> Option<Self::Item> {
243 if self.i == self.dim {
244 return None;
245 }
246 let i = self.i;
247 self.i += 1;
248 if let Some(index) = self.dim_index.as_ref() {
249 Some(index[i as usize].as_str().into())
250 } else {
251 Some(i.to_string().into())
252 }
253 }
254}
255
256#[cfg(feature = "serde")]
257mod ser_de {
258 use super::*;
259 use serde::{de, Deserialize, Deserializer, Serializer};
260 #[derive(serde::Serialize, serde::Deserialize)]
261 #[serde(untagged)]
262 enum DimIndex {
263 Array(Vec<String>),
264 String(String),
265 }
266
267 pub fn deserialize_dim_index<'de, D>(deserializer: D) -> Result<Option<Vec<String>>, D::Error>
268 where
269 D: Deserializer<'de>,
270 {
271 Ok(match Option::<DimIndex>::deserialize(deserializer)? {
272 None => None,
273 Some(DimIndex::Array(a)) => Some(a),
274 Some(DimIndex::String(s)) => Some(
275 DimElement::parse_indexes(&s)
276 .ok_or_else(|| de::Error::custom("Failed to deserialize dimIndex"))?,
277 ),
278 })
279 }
280
281 pub fn serialize_dim_index<S>(val: &Option<Vec<String>>, s: S) -> Result<S::Ok, S::Error>
282 where
283 S: Serializer,
284 {
285 s.serialize_str(&val.as_ref().unwrap().join(","))
286 }
287}