extern crate alloc;
use alloc::vec::Vec;
use crate::{Btrit, RawEncoding, RawEncodingBuf, TritBuf, Trits, Tryte};
const TRYTES_PER_BYTE: usize = 2;
const TRITS_PER_TRYTE: usize = 3;
const TRITS_PER_BYTE: usize = TRYTES_PER_BYTE * TRITS_PER_TRYTE;
#[derive(Debug)]
pub enum DecodeError {
InvalidTrytes([Tryte; 2]),
}
pub fn decode(src: &Trits) -> Result<Vec<u8>, DecodeError> {
assert!(src.len() % TRITS_PER_BYTE == 0);
src.iter_trytes()
.step_by(TRYTES_PER_BYTE)
.zip(src[TRITS_PER_TRYTE..].iter_trytes().step_by(TRYTES_PER_BYTE))
.map(|(a, b)| decode_group(a, b).ok_or(DecodeError::InvalidTrytes([a, b])))
.collect()
}
fn decode_group(t1: Tryte, t2: Tryte) -> Option<u8> {
Some(i8::try_from(t1 as isize + t2 as isize * 27).ok()? as u8)
}
pub fn encode<T: RawEncodingBuf>(bytes: &[u8]) -> TritBuf<T>
where
T::Slice: RawEncoding<Trit = Btrit>,
{
let mut trits = TritBuf::with_capacity(bytes.len() * TRITS_PER_BYTE);
for byte in bytes {
let (t1, t2) = encode_group(*byte);
[t1, t2]
.iter()
.for_each(|b| trits.append(Tryte::try_from(*b).unwrap().as_trits()));
}
trits
}
fn encode_group(byte: u8) -> (i8, i8) {
let v = (byte as i8) as i16 + (27 / 2) * 27 + 27 / 2;
let quo = (v / 27) as i8;
let rem = (v % 27) as i8;
(rem + Tryte::MIN_VALUE as i8, quo + Tryte::MIN_VALUE as i8)
}