Skip to content

hex serde #278

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions svd-encoder/src/config.rs
Original file line number Diff line number Diff line change
@@ -130,7 +130,7 @@ where
NumberFormat::UpperHex => format!("{:#X}", value),
NumberFormat::UpperHex8 => format!("{:#010X}", value),
NumberFormat::UpperHex16 => {
if value.into() > std::u32::MAX as u64 {
if value.into() > u32::MAX as u64 {
format!("{:#018X}", value)
} else {
format!("{:#010X}", value)
@@ -139,7 +139,7 @@ where
NumberFormat::LowerHex => format!("{:#x}", value),
NumberFormat::LowerHex8 => format!("{:#010x}", value),
NumberFormat::LowerHex16 => {
if value.into() > std::u32::MAX as u64 {
if value.into() > u32::MAX as u64 {
format!("{:#018x}", value)
} else {
format!("{:#010x}", value)
2 changes: 1 addition & 1 deletion svd-rs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## Unreleased

- use `hex` format for address when serialize
- Revert the `riscv` elements, as well as the `unstable-riscv` feature.

## [v0.14.9] - 2024-08-20
@@ -143,4 +144,3 @@ Previous versions in common [changelog](../CHANGELOG.md).
[v0.11.2]: https://github.com/rust-embedded/svd/compare/svd-rs-v0.11.1...svd-rs-v0.11.2
[v0.11.1]: https://github.com/rust-embedded/svd/compare/v0.11.0...svd-rs-v0.11.1
[v0.11.0]: https://github.com/rust-embedded/svd/compare/v0.10.2...v0.11.0

2 changes: 2 additions & 0 deletions svd-rs/src/addressblock.rs
Original file line number Diff line number Diff line change
@@ -6,8 +6,10 @@ use super::{BuildError, Protection, SvdError, ValidateLevel};
#[non_exhaustive]
pub struct AddressBlock {
/// Specifies the start address of an address block relative to the peripheral [`baseAddress`](crate::Peripheral::base_address).
#[cfg_attr(feature = "serde", serde(serialize_with = "crate::as_hex"))]
pub offset: u32,
/// Specifies the number of [`addressUnitBits`](crate::Device::address_unit_bits) being covered by this address block.
#[cfg_attr(feature = "serde", serde(serialize_with = "crate::as_hex"))]
pub size: u32,
/// Usage of the address block.
pub usage: AddressBlockUsage,
1 change: 1 addition & 0 deletions svd-rs/src/cluster.rs
Original file line number Diff line number Diff line change
@@ -55,6 +55,7 @@ pub struct ClusterInfo {
pub header_struct_name: Option<String>,

/// Cluster address relative to the `baseAddress` of the peripheral
#[cfg_attr(feature = "serde", serde(serialize_with = "crate::as_hex"))]
pub address_offset: u32,

/// Default properties for all registers
85 changes: 78 additions & 7 deletions svd-rs/src/lib.rs
Original file line number Diff line number Diff line change
@@ -95,22 +95,17 @@ pub mod datatype;
pub use self::datatype::DataType;

/// Level of validation
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum ValidateLevel {
/// No validation.
Disabled,
/// Weak validation.
#[default]
Weak,
/// Strict validation.
Strict,
}

impl Default for ValidateLevel {
fn default() -> Self {
ValidateLevel::Weak
}
}

impl ValidateLevel {
/// Returns true if validation is disabled.
pub fn is_disabled(self) -> bool {
@@ -281,3 +276,79 @@ where
T::description(*self)
}
}

#[cfg(feature = "serde")]
struct Hex<T>(T);

#[cfg(feature = "serde")]
impl serde::Serialize for Hex<u64> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let n = self.0;
let (h4, h3, h2, h1) = (
(n >> 48) & 0xffff,
(n >> 32) & 0xffff,
(n >> 16) & 0xffff,
n & 0xffff,
);
let f = if h4 != 0 {
format!("0x{h4:04x}{h3:04x}{h2:04x}{h1:04x}")
} else if h3 != 0 {
format!("0x{h3:04x}{h2:04x}{h1:04x}")
} else if h2 != 0 {
format!("0x{h2:04x}{h1:04x}")
} else if h1 & 0xff00 != 0 {
format!("0x{h1:04x}")
} else if h1 != 0 {
format!("0x{:02x}", h1 & 0xff)
} else {
"0".to_string()
};
serializer.serialize_str(&f)
Comment on lines +289 to +309
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could be replaced with

let hex_length = ((64 - n.leading_zeros() + 3)/4) as usize;
let width = (4 - (hex_length % 4)) % 4 + hex_length;
format!("0x{:0width$x}", n)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot about this. Thanks.

}
}

#[cfg(feature = "serde")]
impl serde::Serialize for Hex<u32> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let n = self.0;
let (h2, h1) = ((n >> 16) & 0xffff, n & 0xffff);
let f = if h2 != 0 {
format!("0x{h2:04x}{h1:04x}")
} else if h1 & 0xff00 != 0 {
format!("0x{h1:04x}")
} else if h1 != 0 {
format!("0x{:02x}", h1 & 0xff)
} else {
"0".to_string()
};
serializer.serialize_str(&f)
}
}

#[cfg(feature = "serde")]
fn as_hex<T, S>(n: &T, s: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
T: Copy,
Hex<T>: serde::Serialize,
{
use serde::Serialize;
Hex(*n).serialize(s)
}

#[cfg(feature = "serde")]
fn as_opt_hex<T, S>(n: &Option<T>, s: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
T: Copy,
Hex<T>: serde::Serialize,
{
use serde::Serialize;
(*n).map(Hex).serialize(s)
}
1 change: 1 addition & 0 deletions svd-rs/src/peripheral.rs
Original file line number Diff line number Diff line change
@@ -89,6 +89,7 @@ pub struct PeripheralInfo {
pub header_struct_name: Option<String>,

/// Lowest address reserved or used by the peripheral
#[cfg_attr(feature = "serde", serde(serialize_with = "crate::as_hex"))]
pub base_address: u64,

/// Default properties for all registers
1 change: 1 addition & 0 deletions svd-rs/src/register.rs
Original file line number Diff line number Diff line change
@@ -60,6 +60,7 @@ pub struct RegisterInfo {
pub alternate_register: Option<String>,

/// Define the address offset relative to the enclosing element
#[cfg_attr(feature = "serde", serde(serialize_with = "crate::as_hex"))]
pub address_offset: u32,

/// Specifies register size, access permission and reset value
20 changes: 16 additions & 4 deletions svd-rs/src/registerproperties.rs
Original file line number Diff line number Diff line change
@@ -26,7 +26,11 @@ pub struct RegisterProperties {
/// Bit-width of register
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
serde(
default,
skip_serializing_if = "Option::is_none",
serialize_with = "crate::as_opt_hex"
)
)]
pub size: Option<u32>,

@@ -47,14 +51,22 @@ pub struct RegisterProperties {
/// Register value at RESET
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
serde(
default,
skip_serializing_if = "Option::is_none",
serialize_with = "crate::as_opt_hex"
)
)]
pub reset_value: Option<u64>,

/// Define which register bits have a defined reset value
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
serde(
default,
skip_serializing_if = "Option::is_none",
serialize_with = "crate::as_opt_hex"
)
)]
pub reset_mask: Option<u64>,
}
@@ -133,7 +145,7 @@ pub(crate) fn check_reset_value(
mask: Option<u64>,
lvl: ValidateLevel,
) -> Result<(), Error> {
const MAX_BITS: u32 = core::u64::MAX.count_ones();
const MAX_BITS: u32 = u64::MAX.count_ones();

if let (Some(size), Some(value)) = (size, value) {
if MAX_BITS - value.leading_zeros() > size {