Skip to main content

iota_ternary_preview/
lib.rs

1use std::{
2    convert::TryFrom,
3    slice,
4};
5
6pub mod bigint;
7pub mod num_conversions;
8pub mod raw;
9pub mod t1b1;
10pub mod t2b1;
11pub mod t3b1;
12pub mod t4b1;
13pub mod t5b1;
14pub mod trit;
15pub mod tryte;
16
17#[cfg(feature = "serde1")]
18mod serde;
19
20use crate::raw::{
21    RawEncoding,
22    RawEncodingBuf,
23};
24use std::{
25    any,
26    borrow::{
27        Borrow,
28        BorrowMut,
29    },
30    cmp::{
31        self,
32        Ordering,
33    },
34    fmt,
35    hash,
36    iter::FromIterator,
37    ops::{
38        Deref,
39        DerefMut,
40        Index,
41        IndexMut,
42        Range,
43    },
44    ptr,
45};
46
47// Reexports
48pub use crate::{
49    t1b1::{
50        T1B1Buf,
51        T1B1,
52    },
53    t2b1::{
54        T2B1Buf,
55        T2B1,
56    },
57    t3b1::{
58        T3B1Buf,
59        T3B1,
60    },
61    t4b1::{
62        T4B1Buf,
63        T4B1,
64    },
65    t5b1::{
66        T5B1Buf,
67        T5B1,
68    },
69    trit::{
70        Btrit,
71        ShiftTernary,
72        Trit,
73        Utrit,
74    },
75    tryte::{
76        Tryte,
77        TryteBuf,
78        MAX_TRYTE_VALUE,
79        MIN_TRYTE_VALUE,
80    },
81};
82
83#[derive(Debug)]
84pub enum Error {
85    InvalidRepr,
86}
87
88#[derive(Hash)]
89#[repr(transparent)]
90pub struct Trits<T: RawEncoding + ?Sized = T1B1<Btrit>>(T);
91
92impl<T> Trits<T>
93where
94    T: RawEncoding + ?Sized,
95{
96    pub fn empty() -> &'static Self {
97        unsafe { &*(T::empty() as *const _ as *const Self) }
98    }
99
100    pub unsafe fn from_raw_unchecked(raw: &[i8], num_trits: usize) -> &Self {
101        debug_assert!(raw.iter().all(T::is_valid));
102        &*(T::from_raw_unchecked(raw, num_trits) as *const _ as *const _)
103    }
104
105    pub unsafe fn from_raw_unchecked_mut(raw: &mut [i8], num_trits: usize) -> &mut Self {
106        debug_assert!(raw.iter().all(T::is_valid));
107        &mut *(T::from_raw_unchecked(raw, num_trits) as *const _ as *mut _)
108    }
109
110    pub fn try_from_raw(raw: &[i8], num_trits: usize) -> Result<&Self, Error> {
111        if raw.iter().all(T::is_valid) {
112            Ok(unsafe { Self::from_raw_unchecked(raw, num_trits) })
113        } else {
114            Err(Error::InvalidRepr)
115        }
116    }
117
118    pub fn try_from_raw_mut(raw: &mut [i8], num_trits: usize) -> Result<&mut Self, Error> {
119        if raw.iter().all(T::is_valid) {
120            Ok(unsafe { Self::from_raw_unchecked_mut(raw, num_trits) })
121        } else {
122            Err(Error::InvalidRepr)
123        }
124    }
125
126    pub fn len(&self) -> usize {
127        self.0.len()
128    }
129
130    /// Will panic if slice is not byte-aligned
131    // TODO: Evaluate whether this API makes sense to be `unsafe`
132    pub fn as_i8_slice(&self) -> &[i8] {
133        self.0.as_i8_slice()
134    }
135
136    /// Will panic if slice is not byte-aligned
137    // TODO: Evaluate whether this API makes sense to be `unsafe`
138    pub unsafe fn as_i8_slice_mut(&mut self) -> &mut [i8] {
139        self.0.as_i8_slice_mut()
140    }
141
142    pub unsafe fn get_unchecked(&self, index: usize) -> T::Trit {
143        debug_assert!(index < self.len());
144        self.0.get_unchecked(index)
145    }
146
147    pub unsafe fn set_unchecked(&mut self, index: usize, trit: T::Trit) {
148        debug_assert!(index < self.len());
149        self.0.set_unchecked(index, trit);
150    }
151
152    pub fn get(&self, index: usize) -> Option<T::Trit> {
153        if index < self.0.len() {
154            unsafe { Some(self.get_unchecked(index)) }
155        } else {
156            None
157        }
158    }
159
160    pub fn set(&mut self, index: usize, trit: T::Trit) {
161        if index < self.0.len() {
162            unsafe { self.set_unchecked(index, trit) };
163        } else {
164            panic!(
165                "Attempt to set trit at index {}, but length of slice is {}",
166                index,
167                self.len()
168            );
169        }
170    }
171
172    pub fn trits(&self) -> impl DoubleEndedIterator<Item = T::Trit> + ExactSizeIterator<Item = T::Trit> + '_ {
173        (0..self.0.len()).map(move |idx| unsafe { self.0.get_unchecked(idx) })
174    }
175
176    pub fn slice(&self, range: Range<usize>) -> &Self {
177        assert!(range.end >= range.start && range.end <= self.len());
178        unsafe { &*(self.0.slice_unchecked(range) as *const _ as *const Self) }
179    }
180
181    pub fn slice_mut(&mut self, range: Range<usize>) -> &mut Self {
182        assert!(range.end >= range.start && range.end <= self.len());
183        unsafe { &mut *(self.0.slice_unchecked_mut(range) as *mut _ as *mut Self) }
184    }
185
186    pub fn copy_from<U: RawEncoding<Trit = T::Trit> + ?Sized>(&mut self, trits: &Trits<U>) {
187        assert!(self.len() == trits.len());
188        for (i, trit) in trits.trits().enumerate() {
189            unsafe {
190                self.set_unchecked(i, trit);
191            }
192        }
193    }
194
195    pub fn fill(&mut self, trit: T::Trit) {
196        for i in 0..self.len() {
197            self.set(i, trit);
198        }
199    }
200
201    pub fn to_buf<U>(&self) -> TritBuf<U>
202    where
203        U: RawEncodingBuf,
204        U::Slice: RawEncoding<Trit = T::Trit>,
205    {
206        self.trits().collect()
207    }
208
209    pub fn chunks(
210        &self,
211        chunk_len: usize,
212    ) -> impl DoubleEndedIterator<Item = &Self> + ExactSizeIterator<Item = &Self> + '_ {
213        assert!(chunk_len > 0);
214        (0..self.len())
215            .step_by(chunk_len)
216            .map(move |i| self.slice(i..(i + chunk_len).min(self.len())))
217    }
218
219    pub fn encode<U>(&self) -> TritBuf<U>
220    where
221        U: RawEncodingBuf,
222        U::Slice: RawEncoding<Trit = T::Trit>,
223    {
224        self.trits().collect()
225    }
226}
227
228impl<T: Trit> Trits<T1B1<T>> {
229    pub fn as_raw_slice(&self) -> &[T] {
230        self.0.as_raw_slice()
231    }
232
233    pub fn as_raw_slice_mut(&mut self) -> &mut [T] {
234        self.0.as_raw_slice_mut()
235    }
236
237    // Q: Why isn't this method on Trits<T>?
238    // A: Because overlapping slice lifetimes make this unsound on squashed encodings
239    pub fn chunks_mut(&mut self, chunk_len: usize) -> impl Iterator<Item = &mut Self> + '_ {
240        assert!(chunk_len > 0);
241        (0..self.len()).step_by(chunk_len).scan(self, move |this, _| {
242            let idx = chunk_len.min(this.len());
243            let (a, b) = Trits::split_at_mut(this, idx);
244            *this = b;
245            Some(a)
246        })
247    }
248
249    pub fn copy_raw_bytes(&mut self, trits: &Trits<T1B1>, offset: usize, count: usize) {
250        assert!(self.len() >= offset + count);
251        unsafe {
252            ptr::copy(
253                trits.as_i8_slice().as_ptr(),
254                self.as_i8_slice_mut().as_mut_ptr().offset(offset as isize),
255                count,
256            );
257        }
258    }
259
260    // Helper
261    // TODO: Make this public? Is it needed?
262    // Q: Why isn't this method on Trits<T>?
263    // A: Because overlapping slice lifetimes make this unsound on squashed encodings
264    fn split_at_mut<'a>(this: &mut &'a mut Self, idx: usize) -> (&'a mut Self, &'a mut Self) {
265        assert!(idx <= this.len());
266        (
267            unsafe { &mut *(this.0.slice_unchecked_mut(0..idx) as *mut _ as *mut Self) },
268            unsafe { &mut *(this.0.slice_unchecked_mut(idx..this.len()) as *mut _ as *mut Self) },
269        )
270    }
271
272    pub fn iter<'a>(&'a self) -> slice::Iter<'a, T> {
273        self.as_raw_slice().iter()
274    }
275
276    pub fn iter_mut<'a>(&'a mut self) -> slice::IterMut<'a, T> {
277        self.as_raw_slice_mut().iter_mut()
278    }
279}
280
281impl Trits<T3B1> {
282    /// Will panic if the trit slice is not a multiple of 3 in length, or if the trit slice is not
283    /// byte-aligned.
284    pub fn as_trytes(&self) -> &[Tryte] {
285        assert!(self.len() % 3 == 0);
286        unsafe { &*(self.as_i8_slice() as *const _ as *const _) }
287    }
288
289    /// Will panic if the trit slice is not a multiple of 3 in length, or if the trit slice is not
290    /// byte-aligned.
291    pub fn as_trytes_mut(&mut self) -> &mut [Tryte] {
292        assert!(self.len() % 3 == 0);
293        unsafe { &mut *(self.as_i8_slice_mut() as *mut _ as *mut _) }
294    }
295}
296
297impl<T, U> cmp::PartialEq<Trits<U>> for Trits<T>
298where
299    T: RawEncoding + ?Sized,
300    U: RawEncoding<Trit = T::Trit> + ?Sized,
301{
302    fn eq(&self, other: &Trits<U>) -> bool {
303        self.len() == other.len() && self.trits().zip(other.trits()).all(|(a, b)| a == b)
304    }
305}
306
307impl<T, U> cmp::PartialOrd<Trits<U>> for Trits<T>
308where
309    T: RawEncoding + ?Sized,
310    U: RawEncoding<Trit = T::Trit> + ?Sized,
311    T::Trit: cmp::PartialOrd,
312{
313    fn partial_cmp(&self, other: &Trits<U>) -> Option<Ordering> {
314        if self.len() != other.len() {
315            return None;
316        }
317
318        for (a, b) in self.trits().zip(other.trits()) {
319            match a.partial_cmp(&b) {
320                Some(Ordering::Equal) => continue,
321                other_order => return other_order,
322            }
323        }
324
325        Some(Ordering::Equal)
326    }
327}
328
329impl<'a, T: RawEncoding + ?Sized> fmt::Debug for &'a Trits<T> {
330    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
331        write!(f, "Trits<{}> [", any::type_name::<T>())?;
332        for (i, trit) in self.trits().enumerate() {
333            if i != 0 {
334                write!(f, ", ")?;
335            }
336            write!(f, "{:?}", trit)?;
337        }
338        write!(f, "]")
339    }
340}
341
342impl<T: RawEncoding + ?Sized> Index<Range<usize>> for Trits<T> {
343    type Output = Self;
344
345    fn index(&self, range: Range<usize>) -> &Self::Output {
346        self.slice(range)
347    }
348}
349
350impl<T: RawEncoding + ?Sized> IndexMut<Range<usize>> for Trits<T> {
351    fn index_mut(&mut self, range: Range<usize>) -> &mut Self::Output {
352        self.slice_mut(range)
353    }
354}
355
356impl<T: RawEncoding + ?Sized> ToOwned for Trits<T> {
357    type Owned = TritBuf<T::Buf>;
358
359    fn to_owned(&self) -> Self::Owned {
360        self.to_buf()
361    }
362}
363
364#[derive(Clone)]
365#[repr(transparent)]
366pub struct TritBuf<T: RawEncodingBuf = T1B1Buf<Btrit>>(T);
367
368impl<T: RawEncodingBuf> TritBuf<T> {
369    pub fn new() -> Self {
370        Self(T::new())
371    }
372
373    // TODO: Make public when original purged
374    fn with_capacity(_cap: usize) -> Self {
375        // TODO: Allocate capacity
376        Self::new()
377    }
378
379    pub fn filled(len: usize, trit: <T::Slice as RawEncoding>::Trit) -> Self {
380        let mut this = Self::with_capacity(len);
381        for _ in 0..len {
382            this.push(trit);
383        }
384        this
385    }
386
387    pub fn zeros(len: usize) -> Self {
388        Self::filled(len, <T::Slice as RawEncoding>::Trit::zero())
389    }
390
391    pub fn from_trits(trits: &[<T::Slice as RawEncoding>::Trit]) -> Self {
392        Self(T::from_trits(trits))
393    }
394
395    // TODO: Is this a good API feature? No, it's not. Kill it with fire.
396    #[deprecated]
397    pub fn from_i8_unchecked(trits: &[i8]) -> Self {
398        trits
399            .iter()
400            .map(|t| <T::Slice as RawEncoding>::Trit::try_from(*t))
401            .collect::<Result<Self, _>>()
402            .unwrap_or_else(|_| panic!("Invalid i8 when converting to trit."))
403    }
404
405    pub fn push(&mut self, trit: <T::Slice as RawEncoding>::Trit) {
406        self.0.push(trit);
407    }
408
409    pub fn pop(&mut self) -> Option<<T::Slice as RawEncoding>::Trit> {
410        self.0.pop()
411    }
412
413    pub fn as_slice(&self) -> &Trits<T::Slice> {
414        unsafe { &*(self.0.as_slice() as *const T::Slice as *const Trits<T::Slice>) }
415    }
416
417    pub fn as_slice_mut(&mut self) -> &mut Trits<T::Slice> {
418        unsafe { &mut *(self.0.as_slice_mut() as *mut T::Slice as *mut Trits<T::Slice>) }
419    }
420}
421
422impl<T> TritBuf<T1B1Buf<T>>
423where
424    T: Trit,
425    T::Target: Trit,
426{
427    pub fn into_shifted(self) -> TritBuf<T1B1Buf<<T as ShiftTernary>::Target>> {
428        TritBuf(self.0.into_shifted())
429    }
430}
431
432impl<T: RawEncodingBuf, U: RawEncodingBuf> PartialEq<TritBuf<U>> for TritBuf<T>
433where
434    T::Slice: RawEncoding,
435    U::Slice: RawEncoding<Trit = <T::Slice as RawEncoding>::Trit>,
436{
437    fn eq(&self, other: &TritBuf<U>) -> bool {
438        self.as_slice() == other.as_slice()
439    }
440}
441
442impl<T: RawEncodingBuf> Deref for TritBuf<T> {
443    type Target = Trits<T::Slice>;
444
445    fn deref(&self) -> &Self::Target {
446        self.as_slice()
447    }
448}
449
450impl<T: RawEncodingBuf> DerefMut for TritBuf<T> {
451    fn deref_mut(&mut self) -> &mut Self::Target {
452        self.as_slice_mut()
453    }
454}
455
456impl<T: RawEncodingBuf> FromIterator<<T::Slice as RawEncoding>::Trit> for TritBuf<T> {
457    fn from_iter<I: IntoIterator<Item = <T::Slice as RawEncoding>::Trit>>(iter: I) -> Self {
458        let iter = iter.into_iter();
459        let mut this = Self::with_capacity(iter.size_hint().0);
460        for trit in iter {
461            this.push(trit);
462        }
463        this
464    }
465}
466
467impl<T> hash::Hash for TritBuf<T>
468where
469    T: RawEncodingBuf,
470    T::Slice: hash::Hash,
471{
472    fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
473        (**self).hash(hasher)
474    }
475}
476
477impl<T: RawEncodingBuf> Index<Range<usize>> for TritBuf<T> {
478    type Output = Trits<T::Slice>;
479
480    fn index(&self, range: Range<usize>) -> &Self::Output {
481        self.slice(range)
482    }
483}
484
485impl<T: RawEncodingBuf> IndexMut<Range<usize>> for TritBuf<T> {
486    fn index_mut(&mut self, range: Range<usize>) -> &mut Self::Output {
487        self.slice_mut(range)
488    }
489}
490
491impl<T: RawEncodingBuf> fmt::Debug for TritBuf<T> {
492    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
493        write!(f, "TritBuf<{}> [", any::type_name::<T>())?;
494        for (i, trit) in self.trits().enumerate() {
495            if i != 0 {
496                write!(f, ", ")?;
497            }
498            write!(f, "{:?}", trit)?;
499        }
500        write!(f, "]")
501    }
502}
503
504impl<T: RawEncodingBuf> Borrow<Trits<T::Slice>> for TritBuf<T> {
505    fn borrow(&self) -> &Trits<T::Slice> {
506        self.as_slice()
507    }
508}
509
510impl<T: RawEncodingBuf> BorrowMut<Trits<T::Slice>> for TritBuf<T> {
511    fn borrow_mut(&mut self) -> &mut Trits<T::Slice> {
512        self.as_slice_mut()
513    }
514}