#[cfg(feature = "uom")]
use crate::information::Information;
#[cfg(feature = "serde")]
use crate::information::{deser_information, deser_vec_information};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use thiserror::Error;
#[cfg(feature = "uom")]
use uom::si::information::byte;
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct Chip {
#[cfg_attr(feature = "serde", serde(default))]
start_address: u64,
pub(crate) page_size: PageSize,
#[cfg_attr(feature = "serde", serde(deserialize_with = "deser_information"))]
total_size: u64,
}
#[derive(Error, Debug, PartialEq)]
pub enum ChipError {
#[error("total size not a multiple of the page size")]
TotalSizePageSizeMismatch,
}
impl Chip {
pub fn new(page_size: u64, start_address: u64, total_size: u64) -> Result<Self, ChipError> {
if !total_size.is_multiple_of(page_size) {
return Err(ChipError::TotalSizePageSizeMismatch);
}
Ok(Self {
start_address,
page_size: PageSize::Uniform(page_size),
total_size,
})
}
#[cfg(feature = "uom")]
pub fn new_bytes(
page_size: impl Into<Information>,
start_address: u64,
total_size: impl Into<Information>,
) -> Result<Self, ChipError> {
Self::new(
page_size.into().get::<byte>(),
start_address,
total_size.into().get::<byte>(),
)
}
#[must_use]
pub fn start_address(&self) -> u64 {
self.start_address
}
#[must_use]
pub fn end_address(&self) -> u64 {
self.start_address + self.total_size
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(untagged))]
pub enum PageSize {
#[cfg_attr(feature = "serde", serde(deserialize_with = "deser_information"))]
Uniform(u64),
#[cfg_attr(feature = "serde", serde(deserialize_with = "deser_vec_information"))]
Heterogeneous(Vec<u64>),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(feature = "serde")]
fn deser_uniform() {
let input = r#"{ "page_size": 4 KiB, "total_size": 16 KiB}"#;
let chip: Chip = yaml_serde::from_str(input).unwrap();
assert_eq!(chip.page_size, PageSize::Uniform(4 * 1024));
}
#[test]
#[cfg(feature = "serde")]
fn deser_heterogeneous() {
let input = r#"{ "page_size": [4 KiB, 4 KiB, 2048 B], total_size: 10 KiB}"#;
let chip: Chip = yaml_serde::from_str(input).unwrap();
assert_eq!(
chip.page_size,
PageSize::Heterogeneous(vec![4 * 1024, 4 * 1024, 2 * 1024,])
);
}
#[test]
fn reject() {
assert_eq!(
Chip::new(2, 0, 3),
Err(ChipError::TotalSizePageSizeMismatch)
);
}
}