use heapless::{String, Vec};
use crate::{crc::checksum, error::DecodeError};
pub const fn binary_len(payload_len: usize) -> usize {
1 + payload_len + 2
}
pub const fn encode_len(binary_len: usize) -> usize {
(binary_len * 8 + 4) / 5
}
pub fn encode<const P: usize, const B: usize, const E: usize>(
ver: u8,
payload: &[u8],
) -> String<E> {
const {
assert!(B == binary_len(P), "B must be exactly binary_len(P)");
assert!(E == encode_len(B), "E must be exactly encode_len(B)");
}
let mut d: Vec<u8, B> = Vec::new();
d.push(ver).unwrap();
d.extend_from_slice(payload).unwrap();
d.extend_from_slice(&checksum(&d)).unwrap();
let mut encoded: Vec<u8, E> = Vec::new();
let encoded_len = data_encoding::BASE32_NOPAD.encode_len(d.len());
encoded.resize_default(encoded_len).unwrap();
data_encoding::BASE32_NOPAD.encode_mut(&d, &mut encoded);
unsafe { String::from_utf8_unchecked(encoded) }
}
pub fn decode<const P: usize, const B: usize>(s: &[u8]) -> Result<(u8, Vec<u8, P>), DecodeError> {
const {
assert!(B == binary_len(P), "B must be exactly binary_len(P)");
}
let mut data: Vec<u8, B> = Vec::new();
let data_len = data_encoding::BASE32_NOPAD
.decode_len(s.len())
.map_err(|_| DecodeError::Invalid)?;
if data_len < 3 {
return Err(DecodeError::Invalid);
}
data.resize_default(data_len)
.map_err(|_| DecodeError::Invalid)?;
data_encoding::BASE32_NOPAD
.decode_mut(s, &mut data)
.map_err(|_| DecodeError::Invalid)?;
let ver = data[0];
let data_len = data.len();
let (data_without_crc, crc_actual) = data.split_at(data_len - 2);
let crc_expect = checksum(data_without_crc);
if crc_actual != crc_expect {
return Err(DecodeError::Invalid);
}
let payload_data = &data_without_crc[1..];
let payload: Vec<u8, P> = Vec::from_slice(payload_data).unwrap();
Ok((ver, payload))
}
#[cfg(test)]
mod tests {
use super::{binary_len, decode, encode, encode_len, DecodeError};
#[test]
fn test_binary_len() {
for payload_len in 0..=100 {
let expected = 1 + payload_len + 2;
let actual = binary_len(payload_len);
assert_eq!(actual, expected);
}
}
#[test]
fn test_encode_len() {
for payload_len in 0..=100 {
let bin_len = binary_len(payload_len);
let expected = data_encoding::BASE32_NOPAD.encode_len(bin_len);
let actual = encode_len(bin_len);
assert_eq!(actual, expected);
let payload = [0u8; 100];
let encoded = encode::<100, 103, 165>(0x00, &payload[..payload_len]);
assert_eq!(encoded.len(), expected);
}
}
#[test]
fn test_decode_minimum_length() {
assert_eq!(decode::<0, 3>(b""), Err(DecodeError::Invalid));
assert_eq!(decode::<0, 3>(b"AA"), Err(DecodeError::Invalid)); assert_eq!(decode::<0, 3>(b"AAAA"), Err(DecodeError::Invalid));
let result = decode::<0, 3>(b"AAAAA");
assert!(
result.is_ok(),
"decode should accept 3 binary bytes (empty payload)"
);
let (ver, payload) = result.unwrap();
assert_eq!(ver, 0x00);
assert!(payload.is_empty());
}
}