use super::{
array::{descriptions, names},
registercluster::{
AllRegistersIter, AllRegistersIterMut, ClusterIter, ClusterIterMut, RegisterIter,
RegisterIterMut,
},
BuildError, Description, DimElement, EmptyToNone, MaybeArray, Name, Register, RegisterCluster,
RegisterProperties, SvdError, ValidateLevel,
};
use std::ops::Deref;
pub type Cluster = MaybeArray<ClusterInfo>;
#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
pub enum Error {
#[error("Cluster must contain at least one Register or Cluster")]
EmptyCluster,
}
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(rename_all = "camelCase")
)]
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub struct ClusterInfo {
pub name: String,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub description: Option<String>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub alternate_cluster: Option<String>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub header_struct_name: Option<String>,
pub address_offset: u32,
#[cfg_attr(feature = "serde", serde(flatten))]
pub default_register_properties: RegisterProperties,
pub children: Vec<RegisterCluster>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub derived_from: Option<String>,
}
pub fn address_offsets<'a>(
info: &'a ClusterInfo,
dim: &'a DimElement,
) -> impl Iterator<Item = u32> + 'a {
(0..dim.dim).map(move |i| info.address_offset + i * dim.dim_increment)
}
pub fn expand<'a>(
info: &'a ClusterInfo,
dim: &'a DimElement,
) -> impl Iterator<Item = ClusterInfo> + 'a {
names(info, dim)
.zip(descriptions(info, dim))
.zip(address_offsets(info, dim))
.map(|((name, description), address_offset)| {
let mut info = info.clone();
info.name = name;
info.description = description;
info.address_offset = address_offset;
info
})
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct ClusterInfoBuilder {
name: Option<String>,
description: Option<String>,
alternate_cluster: Option<String>,
header_struct_name: Option<String>,
address_offset: Option<u32>,
default_register_properties: RegisterProperties,
children: Option<Vec<RegisterCluster>>,
derived_from: Option<String>,
}
impl From<ClusterInfo> for ClusterInfoBuilder {
fn from(c: ClusterInfo) -> Self {
Self {
name: Some(c.name),
description: c.description,
alternate_cluster: c.alternate_cluster,
header_struct_name: c.header_struct_name,
address_offset: Some(c.address_offset),
default_register_properties: c.default_register_properties,
children: Some(c.children),
derived_from: c.derived_from,
}
}
}
impl ClusterInfoBuilder {
pub fn name(mut self, value: String) -> Self {
self.name = Some(value);
self
}
pub fn description(mut self, value: Option<String>) -> Self {
self.description = value;
self
}
pub fn alternate_cluster(mut self, value: Option<String>) -> Self {
self.alternate_cluster = value;
self
}
pub fn header_struct_name(mut self, value: Option<String>) -> Self {
self.header_struct_name = value;
self
}
pub fn address_offset(mut self, value: u32) -> Self {
self.address_offset = Some(value);
self
}
pub fn default_register_properties(mut self, value: RegisterProperties) -> Self {
self.default_register_properties = value;
self
}
pub fn children(mut self, value: Vec<RegisterCluster>) -> Self {
self.children = Some(value);
self
}
pub fn derived_from(mut self, value: Option<String>) -> Self {
self.derived_from = value;
self
}
pub fn build(self, lvl: ValidateLevel) -> Result<ClusterInfo, SvdError> {
let cluster = ClusterInfo {
name: self
.name
.ok_or_else(|| BuildError::Uninitialized("name".to_string()))?,
description: self.description.empty_to_none(),
alternate_cluster: self.alternate_cluster.empty_to_none(),
header_struct_name: self.header_struct_name.empty_to_none(),
address_offset: self
.address_offset
.ok_or_else(|| BuildError::Uninitialized("address_offset".to_string()))?,
default_register_properties: self.default_register_properties.build(lvl)?,
children: self
.children
.ok_or_else(|| BuildError::Uninitialized("children".to_string()))?,
derived_from: self.derived_from,
};
cluster.validate(lvl)?;
Ok(cluster)
}
}
impl ClusterInfo {
pub fn builder() -> ClusterInfoBuilder {
ClusterInfoBuilder::default()
}
pub const fn single(self) -> Cluster {
Cluster::Single(self)
}
pub const fn array(self, dim: DimElement) -> Cluster {
Cluster::Array(self, dim)
}
pub fn modify_from(
&mut self,
builder: ClusterInfoBuilder,
lvl: ValidateLevel,
) -> Result<(), SvdError> {
if let Some(name) = builder.name {
self.name = name;
}
if builder.description.is_some() {
self.description = builder.description.empty_to_none();
}
if builder.alternate_cluster.is_some() {
self.alternate_cluster = builder.alternate_cluster.empty_to_none();
}
if builder.header_struct_name.is_some() {
self.header_struct_name = builder.header_struct_name.empty_to_none();
}
if let Some(address_offset) = builder.address_offset {
self.address_offset = address_offset;
}
if builder.derived_from.is_some() {
self.derived_from = builder.derived_from;
self.children = Vec::new();
self.default_register_properties = RegisterProperties::default();
} else {
self.default_register_properties
.modify_from(builder.default_register_properties, lvl)?;
if let Some(children) = builder.children {
self.children = children;
}
}
self.validate(lvl)
}
pub fn validate(&self, lvl: ValidateLevel) -> Result<(), SvdError> {
if !lvl.is_disabled() {
if lvl.is_strict() {
super::check_dimable_name(&self.name, "name")?;
}
if let Some(name) = self.derived_from.as_ref() {
if lvl.is_strict() {
super::check_derived_name(name, "derivedFrom")?;
}
} else if self.children.is_empty() && lvl.is_strict() {
return Err(Error::EmptyCluster.into());
}
}
Ok(())
}
pub fn validate_all(&self, lvl: ValidateLevel) -> Result<(), SvdError> {
self.default_register_properties.validate(lvl)?;
for r in self.registers() {
r.validate_all(lvl)?;
}
for c in self.clusters() {
c.validate_all(lvl)?;
}
self.validate(lvl)
}
#[deprecated(since = "0.12.1", note = "Please use `all_registers` instead")]
pub fn reg_iter(&self) -> AllRegistersIter {
self.all_registers()
}
pub fn all_registers(&self) -> AllRegistersIter {
AllRegistersIter {
rem: self.children.iter().rev().collect(),
}
}
#[deprecated(since = "0.12.1", note = "Please use `all_registers_mut` instead")]
pub fn reg_iter_mut(&mut self) -> AllRegistersIterMut {
self.all_registers_mut()
}
pub fn all_registers_mut(&mut self) -> AllRegistersIterMut {
AllRegistersIterMut {
rem: self.children.iter_mut().rev().collect(),
}
}
pub fn registers(&self) -> RegisterIter {
RegisterIter {
all: self.children.iter(),
}
}
pub fn registers_mut(&mut self) -> RegisterIterMut {
RegisterIterMut {
all: self.children.iter_mut(),
}
}
pub fn clusters(&self) -> ClusterIter {
ClusterIter {
all: self.children.iter(),
}
}
pub fn clusters_mut(&mut self) -> ClusterIterMut {
ClusterIterMut {
all: self.children.iter_mut(),
}
}
pub fn get_register(&self, name: &str) -> Option<&Register> {
self.registers().find(|f| f.name == name)
}
pub fn get_mut_register(&mut self, name: &str) -> Option<&mut Register> {
self.registers_mut().find(|f| f.name == name)
}
pub fn get_cluster(&self, name: &str) -> Option<&Cluster> {
self.clusters().find(|f| f.name == name)
}
pub fn get_mut_cluster(&mut self, name: &str) -> Option<&mut Cluster> {
self.clusters_mut().find(|f| f.name == name)
}
}
impl Cluster {
pub fn validate_all(&self, lvl: ValidateLevel) -> Result<(), SvdError> {
if let Self::Array(_, dim) = self {
dim.validate(lvl)?;
}
self.deref().validate_all(lvl)
}
}
impl Name for ClusterInfo {
fn name(&self) -> &str {
&self.name
}
}
impl Description for ClusterInfo {
fn description(&self) -> Option<&str> {
self.description.as_deref()
}
}