1extern crate alloc;
5
6use alloc::vec::Vec;
7
8use crate::{Btrit, RawEncoding, RawEncodingBuf, TritBuf, Trits, Tryte};
9
10const TRYTES_PER_BYTE: usize = 2;
11const TRITS_PER_TRYTE: usize = 3;
12const TRITS_PER_BYTE: usize = TRYTES_PER_BYTE * TRITS_PER_TRYTE;
13
14#[derive(Debug)]
16pub enum DecodeError {
17 InvalidTrytes([Tryte; 2]),
19}
20
21pub fn decode(src: &Trits) -> Result<Vec<u8>, DecodeError> {
23 assert!(src.len() % TRITS_PER_BYTE == 0);
24 src.iter_trytes()
25 .step_by(TRYTES_PER_BYTE)
26 .zip(src[TRITS_PER_TRYTE..].iter_trytes().step_by(TRYTES_PER_BYTE))
27 .map(|(a, b)| decode_group(a, b).ok_or(DecodeError::InvalidTrytes([a, b])))
28 .collect()
29}
30
31fn decode_group(t1: Tryte, t2: Tryte) -> Option<u8> {
32 Some(i8::try_from(t1 as isize + t2 as isize * 27).ok()? as u8)
33}
34
35pub fn encode<T: RawEncodingBuf>(bytes: &[u8]) -> TritBuf<T>
37where
38 T::Slice: RawEncoding<Trit = Btrit>,
39{
40 let mut trits = TritBuf::with_capacity(bytes.len() * TRITS_PER_BYTE);
41
42 for byte in bytes {
43 let (t1, t2) = encode_group(*byte);
44 [t1, t2]
45 .iter()
46 .for_each(|b| trits.append(Tryte::try_from(*b).unwrap().as_trits()));
48 }
49
50 trits
51}
52
53fn encode_group(byte: u8) -> (i8, i8) {
54 let v = (byte as i8) as i16 + (27 / 2) * 27 + 27 / 2;
55 let quo = (v / 27) as i8;
56 let rem = (v % 27) as i8;
57
58 (rem + Tryte::MIN_VALUE as i8, quo + Tryte::MIN_VALUE as i8)
59}