102 lines
2.9 KiB
Rust
102 lines
2.9 KiB
Rust
use std::{fmt, str::FromStr};
|
|
|
|
use deku::{deku_derive, DekuError};
|
|
|
|
use super::{ size_read, map_bytes_to_lossy_string };
|
|
|
|
pub mod ssv_lire_config;
|
|
|
|
/// # Convert a DataField to a specific type
|
|
/// Using this as deku map function to fill a field value from
|
|
/// a DataField
|
|
fn map_from_data_field<T>(data_field: DataField) -> Result<T, DekuError>
|
|
where
|
|
T: FromStr,
|
|
T::Err: std::fmt::Display,
|
|
{
|
|
let text = String::from_utf8(data_field.data)
|
|
.map_err(|e| DekuError::Parse(e.to_string().into()))?;
|
|
T::from_str(&text)
|
|
.map_err(|e| DekuError::Parse(e.to_string().into()))
|
|
}
|
|
|
|
// ------------------- DATA FIELD TYPES -------------------
|
|
|
|
/// # Data field structure
|
|
/// This structure is the core structure to read data fields
|
|
/// It is usually used by other structures implementing the
|
|
/// `#[deku(map = "map_from_data_field")]` attribute
|
|
#[deku_derive(DekuRead)]
|
|
#[derive(Debug, PartialEq)]
|
|
struct DataField {
|
|
#[deku(temp, reader = "size_read(deku::reader)")]
|
|
pub data_size: u64,
|
|
#[deku(bytes_read = "data_size")]
|
|
pub data: Vec<u8>,
|
|
}
|
|
|
|
#[deku_derive(DekuRead)]
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
/// # Numeric string
|
|
/// TODO: check if all the characters are numeric
|
|
pub struct NumericString(
|
|
#[deku(map = "map_from_data_field")]
|
|
String
|
|
);
|
|
|
|
#[deku_derive(DekuRead)]
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AlphaNumericString(
|
|
#[deku(map = "map_from_data_field")]
|
|
String
|
|
);
|
|
impl From<&str> for AlphaNumericString {
|
|
fn from(s: &str) -> Self {
|
|
AlphaNumericString(s.to_string())
|
|
}
|
|
}
|
|
|
|
#[deku_derive(DekuRead)]
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
#[deku(endian = "big")]
|
|
/// # Software version
|
|
/// An almost standard software version structure in FSV
|
|
/// It is composed of a version and a revision, encoded on 2 bytes each
|
|
pub struct SoftwareVersion {
|
|
#[deku(temp, reader = "size_read(deku::reader)", assert_eq = "4")]
|
|
data_size: u64,
|
|
#[deku(bytes= 2, map = "|x: [u8; 2]| map_bytes_to_lossy_string(&x)")]
|
|
pub version: String,
|
|
#[deku(bytes= 2, map = "|x: [u8; 2]| map_bytes_to_lossy_string(&x)")]
|
|
pub revision: String,
|
|
}
|
|
impl fmt::Display for SoftwareVersion {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(f, "{}.{}", self.version, self.revision)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use deku::DekuContainerRead as _;
|
|
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test() {
|
|
let version_bytes: [u8; 2] = [48, 55];
|
|
let version = map_bytes_to_lossy_string(&version_bytes).unwrap();
|
|
assert_eq!(version, "07");
|
|
}
|
|
|
|
#[test]
|
|
fn test_software_version() {
|
|
// env_logger::init(); // Uncomment and run with RUST_LOG=trace for deku debugging
|
|
let data: [u8; 5] = [4, 48, 55, 50, 48];
|
|
|
|
let (_rest, software_version) = SoftwareVersion::from_bytes((&data, 0)).unwrap();
|
|
// assert_eq!(software_version.data_size, 4);
|
|
assert_eq!(software_version.version, "07");
|
|
assert_eq!(software_version.revision, "20");
|
|
}
|
|
} |