use crate::error::{MeshCodeError, Result};
use crate::types::mesh_level::MeshLevel;
use core::fmt;
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct MeshCode {
value: u64,
}
impl MeshCode {
pub fn new(level: MeshLevel, code: u64) -> Result<Self> {
let level_bits = (level.as_u8() as u64) << 56;
let value = level_bits | (code & 0x00FF_FFFF_FFFF_FFFF);
Ok(MeshCode { value })
}
#[allow(clippy::should_implement_trait)]
pub fn from_str(s: &str) -> Result<Self> {
if s.is_empty() {
return Err(MeshCodeError::InvalidFormat("Empty string".to_string()));
}
for (i, c) in s.chars().enumerate() {
if !c.is_ascii_digit() {
return Err(MeshCodeError::InvalidDigit {
position: i,
digit: c,
});
}
}
let level = MeshLevel::from_code_string(s)?;
let code = s.parse::<u64>().map_err(|_| {
MeshCodeError::InvalidFormat("Failed to parse numeric code".to_string())
})?;
Self::new(level, code)
}
pub fn level(&self) -> MeshLevel {
let level_byte = (self.value >> 56) as u8;
MeshLevel::from_u8(level_byte).expect("Invalid level stored in MeshCode")
}
pub fn code(&self) -> u64 {
self.value & 0x00FF_FFFF_FFFF_FFFF
}
pub fn as_string(&self) -> String {
let level = self.level();
let code = self.code();
let width = level.code_length();
format!("{code:0width$}")
}
}
impl fmt::Debug for MeshCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MeshCode")
.field("level", &self.level())
.field("code", &self.as_string())
.finish()
}
}
impl fmt::Display for MeshCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mesh_code_creation() {
let mesh = MeshCode::new(MeshLevel::First, 5339).unwrap();
assert_eq!(mesh.level(), MeshLevel::First);
assert_eq!(mesh.code(), 5339);
assert_eq!(mesh.as_string(), "5339");
}
#[test]
fn test_mesh_code_from_str() {
let mesh = MeshCode::from_str("5339").unwrap();
assert_eq!(mesh.level(), MeshLevel::First);
assert_eq!(mesh.code(), 5339);
let mesh = MeshCode::from_str("53393599").unwrap();
assert_eq!(mesh.level(), MeshLevel::Third);
assert_eq!(mesh.code(), 53393599);
}
#[test]
fn test_invalid_mesh_code() {
assert!(MeshCode::from_str("").is_err());
assert!(MeshCode::from_str("abc").is_err());
assert!(MeshCode::from_str("12345").is_err());
}
#[test]
fn test_mesh_code_display() {
let mesh = MeshCode::from_str("0001").unwrap();
assert_eq!(mesh.as_string(), "0001");
assert_eq!(format!("{}", mesh), "0001");
}
}