svd_rs/
lib.rs

1#![deny(missing_docs)]
2//! SVD objects.
3//! This module defines components of an SVD along with parse and encode implementations
4
5/// Common things for structures which can be collected in arrays
6pub mod array;
7pub use array::MaybeArray;
8
9/// Endian objects
10pub mod endian;
11pub use self::endian::Endian;
12
13/// Cpu objects
14pub mod cpu;
15pub use self::cpu::{Cpu, CpuBuilder};
16
17/// Interrupt objects
18pub mod interrupt;
19pub use self::interrupt::Interrupt;
20
21/// Access objects
22pub mod access;
23pub use self::access::Access;
24
25/// Bitrange objects
26pub mod bitrange;
27pub use self::bitrange::{BitRange, BitRangeType};
28
29/// Write constraint objects
30pub mod writeconstraint;
31pub use self::writeconstraint::{WriteConstraint, WriteConstraintRange};
32
33/// Usage objects
34pub mod usage;
35pub use self::usage::Usage;
36
37/// Enumerated Value objects
38pub mod enumeratedvalue;
39pub use self::enumeratedvalue::{EnumeratedValue, EnumeratedValueBuilder};
40
41/// Enumerated Values objects
42pub mod enumeratedvalues;
43pub use self::enumeratedvalues::{EnumeratedValues, EnumeratedValuesBuilder};
44
45/// Field objects
46pub mod field;
47pub use self::field::{Field, FieldInfo, FieldInfoBuilder};
48
49/// Register Properties objects
50pub mod registerproperties;
51pub use self::registerproperties::RegisterProperties;
52
53/// Address Block objects
54pub mod addressblock;
55pub use self::addressblock::{AddressBlock, AddressBlockUsage};
56
57/// Cluster objects
58pub mod cluster;
59pub use self::cluster::{Cluster, ClusterInfo, ClusterInfoBuilder};
60
61/// Register objects
62pub mod register;
63pub use self::register::{Register, RegisterInfo, RegisterInfoBuilder};
64
65/// Register Cluster objects
66pub mod registercluster;
67pub use self::registercluster::RegisterCluster;
68
69/// Dimelement objects
70pub mod dimelement;
71pub use self::dimelement::{DimArrayIndex, DimElement, DimElementBuilder};
72
73/// Peripheral objects
74pub mod peripheral;
75pub use self::peripheral::{Peripheral, PeripheralInfo, PeripheralInfoBuilder};
76
77/// Device objects
78pub mod device;
79pub use self::device::{Device, DeviceBuilder};
80
81/// Modified Write Values objects
82pub mod modifiedwritevalues;
83pub use self::modifiedwritevalues::ModifiedWriteValues;
84
85/// Read Action objects
86pub mod readaction;
87pub use self::readaction::ReadAction;
88
89/// Protection objects
90pub mod protection;
91pub use self::protection::Protection;
92
93/// DataType objects
94pub mod datatype;
95pub use self::datatype::DataType;
96
97/// Level of validation
98#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
99pub enum ValidateLevel {
100    /// No validation.
101    Disabled,
102    /// Weak validation.
103    #[default]
104    Weak,
105    /// Strict validation.
106    Strict,
107}
108
109impl ValidateLevel {
110    /// Returns true if validation is disabled.
111    pub fn is_disabled(self) -> bool {
112        self == ValidateLevel::Disabled
113    }
114    /// Returns true if validation is considered to be weakly checked.
115    pub fn is_weak(self) -> bool {
116        self != ValidateLevel::Disabled
117    }
118    /// Returns true if validation is considered to be strictly checked.
119    pub fn is_strict(self) -> bool {
120        self == ValidateLevel::Strict
121    }
122}
123
124#[cfg(feature = "derive-from")]
125pub mod derive_from;
126#[cfg(feature = "derive-from")]
127pub use derive_from::DeriveFrom;
128
129use once_cell::sync::Lazy;
130use regex::Regex;
131
132/// Errors that can occur during building.
133#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
134pub enum SvdError {
135    /// Error related to a builder
136    #[error("`Build error: {0}")]
137    Build(#[from] BuildError),
138    /// Name check error
139    #[error("`Name check error: {0}")]
140    Name(#[from] NameError),
141    /// Device error
142    #[error("`Device error: {0}")]
143    Device(#[from] device::Error),
144    /// Peripheral error
145    #[error("`Peripheral error: {0}")]
146    Peripheral(#[from] peripheral::Error),
147    /// Cluster error
148    #[error("`Cluster error: {0}")]
149    Cluster(#[from] cluster::Error),
150    /// Register error
151    #[error("`Register error: {0}")]
152    Register(#[from] register::Error),
153    /// Field error
154    #[error("`Field error: {0}")]
155    Field(#[from] field::Error),
156    /// BitRange error
157    #[error("`BitRange error: {0}")]
158    BitRange(#[from] bitrange::Error),
159    /// EnumeratedValue error
160    #[error("`EnumeratedValue error: {0}")]
161    EnumeratedValue(#[from] enumeratedvalue::Error),
162    /// EnumeratedValues error
163    #[error("`EnumeratedValues error: {0}")]
164    EnumeratedValues(#[from] enumeratedvalues::Error),
165    /// RegisterProperties error
166    #[error("`RegisterProperties error: {0}")]
167    RegisterProperties(#[from] registerproperties::Error),
168    /// WriteConstraint error
169    #[error("`WriteConstraint error: {0}")]
170    WriteConstraint(#[from] writeconstraint::Error),
171}
172
173/// Errors from a builder
174#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
175pub enum BuildError {
176    /// Field was not set when building it.
177    #[error("`{0}` must be initialized")]
178    Uninitialized(String),
179}
180
181/// Invalid error
182#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
183pub enum NameError {
184    /// Name is invalid
185    #[error("Name `{0}` contains unexpected symbol")]
186    Invalid(String, String),
187}
188
189pub(crate) fn check_name(name: &str, tag: &str) -> Result<(), NameError> {
190    static PATTERN: Lazy<Regex> = Lazy::new(|| Regex::new("^[_A-Za-z0-9]*$").unwrap());
191    if PATTERN.is_match(name) {
192        Ok(())
193    } else {
194        Err(NameError::Invalid(name.to_string(), tag.to_string()))
195    }
196}
197
198pub(crate) fn check_dimable_name(name: &str, tag: &str) -> Result<(), NameError> {
199    static PATTERN: Lazy<Regex> = Lazy::new(|| {
200        Regex::new("^(((%s)|(%s)[_A-Za-z]{1}[_A-Za-z0-9]*)|([_A-Za-z]{1}[_A-Za-z0-9]*(\\[%s\\])?)|([_A-Za-z]{1}[_A-Za-z0-9]*(%s)?[_A-Za-z0-9]*))$").unwrap()
201    });
202    if PATTERN.is_match(name) {
203        Ok(())
204    } else {
205        Err(NameError::Invalid(name.to_string(), tag.to_string()))
206    }
207}
208
209pub(crate) fn check_derived_name(name: &str, tag: &str) -> Result<(), NameError> {
210    for x in name.split('.') {
211        check_dimable_name(x, tag)?
212    }
213    Ok(())
214}
215
216trait EmptyToNone {
217    fn empty_to_none(self) -> Self;
218}
219
220impl EmptyToNone for Option<String> {
221    fn empty_to_none(self) -> Self {
222        self.and_then(|s| if s.is_empty() { None } else { Some(s) })
223    }
224}
225
226impl<T> EmptyToNone for Option<Vec<T>> {
227    fn empty_to_none(self) -> Self {
228        self.and_then(|v| if v.is_empty() { None } else { Some(v) })
229    }
230}
231
232/// Get SVD element name
233pub trait Name {
234    /// Get name
235    fn name(&self) -> &str;
236}
237
238impl<T> Name for &T
239where
240    T: Name,
241{
242    fn name(&self) -> &str {
243        T::name(*self)
244    }
245}
246
247impl<T> Name for &mut T
248where
249    T: Name,
250{
251    fn name(&self) -> &str {
252        T::name(*self)
253    }
254}
255
256/// Get SVD element description
257pub trait Description {
258    /// Get description
259    fn description(&self) -> Option<&str>;
260}
261
262impl<T> Description for &T
263where
264    T: Description,
265{
266    fn description(&self) -> Option<&str> {
267        T::description(*self)
268    }
269}
270
271impl<T> Description for &mut T
272where
273    T: Description,
274{
275    fn description(&self) -> Option<&str> {
276        T::description(*self)
277    }
278}