crypto/encoding/ternary/
t4b1.rs1extern crate alloc;
5
6use alloc::vec::Vec;
7use core::ops::Range;
8
9use crate::encoding::ternary::{Btrit, RawEncoding, RawEncodingBuf, ShiftTernary, Utrit};
10
11const TRITS_PER_BYTE: usize = 4;
12const BALANCE_DIFF: i8 = 40;
14
15#[repr(transparent)]
17pub struct T4B1([()]);
18
19impl T4B1 {
20 unsafe fn make(ptr: *const i8, offset: usize, len: usize) -> *const Self {
21 let len = (len << 2) | (offset % TRITS_PER_BYTE);
22 core::mem::transmute((ptr.add(offset / TRITS_PER_BYTE), len))
23 }
24
25 unsafe fn ptr(&self, index: usize) -> *const i8 {
26 let byte_offset = (self.len_offset().1 + index) / TRITS_PER_BYTE;
27 (self.0.as_ptr() as *const i8).add(byte_offset)
28 }
29
30 fn len_offset(&self) -> (usize, usize) {
31 (self.0.len() >> 2, self.0.len() & 0b11)
32 }
33}
34
35fn extract(x: i8, elem: usize) -> Btrit {
36 debug_assert!(
37 elem < TRITS_PER_BYTE,
38 "Attempted to extract invalid element {} from balanced T4B1 trit",
39 elem
40 );
41 Utrit::from_u8((((x + BALANCE_DIFF) / 3i8.pow(elem as u32)) % 3) as u8).shift()
42}
43
44fn insert(x: i8, elem: usize, trit: Btrit) -> i8 {
45 debug_assert!(
46 elem < TRITS_PER_BYTE,
47 "Attempted to insert invalid element {} into balanced T4B1 trit",
48 elem
49 );
50 let utrit = trit.shift();
51 let ux = x + BALANCE_DIFF;
52 let ux = ux + (utrit.into_u8() as i8 - (ux / 3i8.pow(elem as u32)) % 3) * 3i8.pow(elem as u32);
53 ux - BALANCE_DIFF
54}
55
56impl RawEncoding for T4B1 {
57 type Trit = Btrit;
58 type Buf = T4B1Buf;
59
60 const TRITS_PER_BYTE: usize = TRITS_PER_BYTE;
61
62 fn empty() -> &'static Self {
63 unsafe { &*Self::make(&[] as *const _, 0, 0) }
64 }
65
66 fn len(&self) -> usize {
67 self.len_offset().0
68 }
69
70 fn as_i8_slice(&self) -> &[i8] {
71 assert!(self.len_offset().1 == 0);
72 unsafe {
73 core::slice::from_raw_parts(
74 self as *const _ as *const _,
75 (self.len() + TRITS_PER_BYTE - 1) / TRITS_PER_BYTE,
76 )
77 }
78 }
79
80 unsafe fn as_i8_slice_mut(&mut self) -> &mut [i8] {
81 assert!(self.len_offset().1 == 0);
82 core::slice::from_raw_parts_mut(
83 self as *mut _ as *mut _,
84 (self.len() + TRITS_PER_BYTE - 1) / TRITS_PER_BYTE,
85 )
86 }
87
88 unsafe fn get_unchecked(&self, index: usize) -> Self::Trit {
89 let b = self.ptr(index).read();
90 extract(b, (self.len_offset().1 + index) % TRITS_PER_BYTE)
91 }
92
93 unsafe fn set_unchecked(&mut self, index: usize, trit: Self::Trit) {
94 let b = self.ptr(index).read();
95 let b = insert(b, (self.len_offset().1 + index) % TRITS_PER_BYTE, trit);
96 (self.ptr(index) as *mut i8).write(b);
97 }
98
99 unsafe fn slice_unchecked(&self, range: Range<usize>) -> &Self {
100 &*Self::make(
101 self.ptr(range.start),
102 (self.len_offset().1 + range.start) % TRITS_PER_BYTE,
103 range.end - range.start,
104 )
105 }
106
107 unsafe fn slice_unchecked_mut(&mut self, range: Range<usize>) -> &mut Self {
108 &mut *(Self::make(
109 self.ptr(range.start),
110 (self.len_offset().1 + range.start) % TRITS_PER_BYTE,
111 range.end - range.start,
112 ) as *mut Self)
113 }
114
115 fn is_valid(b: i8) -> bool {
116 (-BALANCE_DIFF..=BALANCE_DIFF).contains(&b)
117 }
118
119 unsafe fn from_raw_unchecked(b: &[i8], num_trits: usize) -> &Self {
120 assert!(num_trits <= b.len() * TRITS_PER_BYTE);
121 &*Self::make(b.as_ptr() as *const _, 0, num_trits)
122 }
123
124 unsafe fn from_raw_unchecked_mut(b: &mut [i8], num_trits: usize) -> &mut Self {
125 assert!(num_trits <= b.len() * TRITS_PER_BYTE);
126 &mut *(Self::make(b.as_ptr() as *const _, 0, num_trits) as *mut _)
127 }
128}
129
130#[derive(Clone)]
132pub struct T4B1Buf(Vec<i8>, usize);
133
134impl RawEncodingBuf for T4B1Buf {
135 type Slice = T4B1;
136
137 fn new() -> Self {
138 Self(Vec::new(), 0)
139 }
140
141 fn with_capacity(cap: usize) -> Self {
142 let cap = (cap / TRITS_PER_BYTE) + (cap % TRITS_PER_BYTE != 0) as usize;
143 Self(Vec::with_capacity(cap), 0)
144 }
145
146 fn clear(&mut self) {
147 self.0.clear();
148 self.1 = 0;
149 }
150
151 fn push(&mut self, trit: <Self::Slice as RawEncoding>::Trit) {
152 if self.1 % TRITS_PER_BYTE == 0 {
153 self.0.push(insert(0, 0, trit));
154 } else {
155 let last_index = self.0.len() - 1;
156 let b = unsafe { self.0.get_unchecked_mut(last_index) };
157 *b = insert(*b, self.1 % TRITS_PER_BYTE, trit);
158 }
159 self.1 += 1;
160 }
161
162 fn pop(&mut self) -> Option<<Self::Slice as RawEncoding>::Trit> {
163 let val = if self.1 == 0 {
164 return None;
165 } else if self.1 % TRITS_PER_BYTE == 1 {
166 self.0.pop().map(|b| extract(b, 0))
167 } else {
168 let last_index = self.0.len() - 1;
169 unsafe {
170 Some(extract(
171 *self.0.get_unchecked(last_index),
172 (self.1 + TRITS_PER_BYTE - 1) % TRITS_PER_BYTE,
173 ))
174 }
175 };
176 self.1 -= 1;
177 val
178 }
179
180 fn as_slice(&self) -> &Self::Slice {
181 unsafe { &*Self::Slice::make(self.0.as_ptr() as _, 0, self.1) }
182 }
183
184 fn as_slice_mut(&mut self) -> &mut Self::Slice {
185 unsafe { &mut *(Self::Slice::make(self.0.as_ptr() as _, 0, self.1) as *mut _) }
186 }
187
188 fn capacity(&self) -> usize {
189 self.0.capacity() * TRITS_PER_BYTE
190 }
191}