crypto/encoding/ternary/
t1b1.rs

1// Copyright 2020-2021 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4extern crate alloc;
5
6use alloc::vec::Vec;
7use core::{convert::TryInto, hash, marker::PhantomData, ops::Range};
8
9use crate::encoding::ternary::{trit::ShiftTernary, Btrit, RawEncoding, RawEncodingBuf, Trit};
10
11const TRITS_PER_BYTE: usize = 1;
12
13/// An encoding scheme slice that uses a single byte to represent one trit.
14#[repr(transparent)]
15pub struct T1B1<T: Trit = Btrit> {
16    _phantom: PhantomData<T>,
17    inner: [()],
18}
19
20impl<T: Trit> T1B1<T> {
21    unsafe fn make(ptr: *const T, offset: usize, len: usize) -> *const Self {
22        core::mem::transmute((ptr.add(offset), len))
23    }
24
25    unsafe fn ptr(&self, index: usize) -> *const T {
26        (self.inner.as_ptr() as *const T).add(index)
27    }
28
29    pub(crate) fn as_raw_slice(&self) -> &[T] {
30        unsafe { &*(Self::make(self.ptr(0), 0, self.len()) as *const _) }
31    }
32
33    pub(crate) fn as_raw_slice_mut(&mut self) -> &mut [T] {
34        unsafe { &mut *(Self::make(self.ptr(0), 0, self.len()) as *mut _) }
35    }
36}
37
38impl<T: Trit> hash::Hash for T1B1<T> {
39    fn hash<H: hash::Hasher>(&self, state: &mut H) {
40        self.as_raw_slice().hash(state);
41    }
42}
43
44impl<T> RawEncoding for T1B1<T>
45where
46    T: Trit,
47{
48    type Trit = T;
49    type Buf = T1B1Buf<T>;
50
51    const TRITS_PER_BYTE: usize = TRITS_PER_BYTE;
52
53    fn empty() -> &'static Self {
54        unsafe { &*Self::make(&[] as *const _, 0, 0) }
55    }
56
57    fn len(&self) -> usize {
58        self.inner.len()
59    }
60
61    fn as_i8_slice(&self) -> &[i8] {
62        unsafe { &*(Self::make(self.ptr(0), 0, self.len()) as *const _) }
63    }
64
65    unsafe fn as_i8_slice_mut(&mut self) -> &mut [i8] {
66        &mut *(Self::make(self.ptr(0), 0, self.len()) as *mut _)
67    }
68
69    unsafe fn get_unchecked(&self, index: usize) -> Self::Trit {
70        self.ptr(index).read()
71    }
72
73    unsafe fn set_unchecked(&mut self, index: usize, trit: Self::Trit) {
74        (self.ptr(index) as *mut T).write(trit);
75    }
76
77    unsafe fn slice_unchecked(&self, range: Range<usize>) -> &Self {
78        &*Self::make(self.ptr(0), range.start, range.end - range.start)
79    }
80
81    unsafe fn slice_unchecked_mut(&mut self, range: Range<usize>) -> &mut Self {
82        &mut *(Self::make(self.ptr(0), range.start, range.end - range.start) as *mut _)
83    }
84
85    fn is_valid(b: i8) -> bool {
86        TryInto::<T>::try_into(b).is_ok()
87    }
88
89    unsafe fn from_raw_unchecked(b: &[i8], num_trits: usize) -> &Self {
90        assert!(num_trits <= b.len());
91        &*Self::make(b.as_ptr() as *const _, 0, num_trits)
92    }
93
94    unsafe fn from_raw_unchecked_mut(b: &mut [i8], num_trits: usize) -> &mut Self {
95        assert!(num_trits <= b.len());
96        &mut *(Self::make(b.as_ptr() as *const _, 0, num_trits) as *mut _)
97    }
98}
99
100/// An encoding scheme buffer that uses a single byte to represent one trit.
101#[derive(Clone)]
102pub struct T1B1Buf<T: Trit = Btrit>(Vec<T>);
103
104impl<T> T1B1Buf<T>
105where
106    T: Trit,
107    <T as ShiftTernary>::Target: Trit,
108{
109    pub(crate) fn into_shifted(self) -> T1B1Buf<T::Target> {
110        // Shift each trit, cast it to i8, and update the inner buffer.
111        // This puts the inner buffer into an incorrect state!
112        let mut trit_buf = self;
113        unsafe {
114            trit_buf.as_slice_mut().as_i8_slice_mut().iter_mut().for_each(|t| {
115                // Unwrapping is safe because the bytes are coming from
116                // within the trit buffer.
117                let trit: T = (*t)
118                    .try_into()
119                    .unwrap_or_else(|_| unreachable!("Unreachable because input bytes are guaranteed to be correct"));
120                let shifted_trit = trit.shift();
121                *t = shifted_trit.into();
122            });
123        }
124
125        // Take ownership of the inner vector and cast it to a `Vec<T::Target>`
126        let raw_trits = core::mem::ManuallyDrop::new(trit_buf.0);
127
128        let p = raw_trits.as_ptr();
129        let len = raw_trits.len();
130        let cap = raw_trits.capacity();
131
132        let raw_shifted_trits = unsafe { Vec::from_raw_parts(p as *const i8 as *mut _, len, cap) };
133
134        T1B1Buf(raw_shifted_trits)
135    }
136}
137
138impl<T> RawEncodingBuf for T1B1Buf<T>
139where
140    T: Trit,
141{
142    type Slice = T1B1<T>;
143
144    fn new() -> Self {
145        Self(Vec::new())
146    }
147
148    fn with_capacity(cap: usize) -> Self {
149        Self(Vec::with_capacity(cap))
150    }
151
152    fn clear(&mut self) {
153        self.0.clear();
154    }
155
156    fn push(&mut self, trit: <Self::Slice as RawEncoding>::Trit) {
157        self.0.push(trit);
158    }
159
160    fn pop(&mut self) -> Option<<Self::Slice as RawEncoding>::Trit> {
161        self.0.pop()
162    }
163
164    fn as_slice(&self) -> &Self::Slice {
165        unsafe { &*Self::Slice::make(self.0.as_ptr() as _, 0, self.0.len()) }
166    }
167
168    fn as_slice_mut(&mut self) -> &mut Self::Slice {
169        unsafe { &mut *(Self::Slice::make(self.0.as_ptr() as _, 0, self.0.len()) as *mut _) }
170    }
171
172    fn capacity(&self) -> usize {
173        self.0.capacity() * Self::Slice::TRITS_PER_BYTE
174    }
175}