crypto/encoding/ternary/
mod.rs

1// Copyright 2020-2021 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4//! A general-purpose ternary manipulation, translation and encoding crate.
5//!
6//! # Features
7//!
8//! - Creation of trit and tryte buffers with multiple encodings
9//! - Safe encoding API that allows the efficient manipulation and sharing of trit and tryte buffers and slices
10//! - Mutation of trit buffers and slices
11//! - Ternary BigInt implementation
12//! - Balanced and unbalanced ternary
13//! - `serde` support
14//!
15//! # Encodings
16//!
17//! This crate includes support for many different trit encodings. Encodings allow the trading off
18//! of different features against each other.
19//!
20//! [`T1B1`] is the canonical default encoding and represents every trit with a single byte of
21//! memory. It is the fastest encoding to manipulate since no bitwise operations are necessary to
22//! pack and unpack it from memory during manipulation. As a result of this, it also permits
23//! certain extra features like mutable chunking and accessing its contents through ordinary
24//! slices.
25//!
26//! [`T3B1`] is also commonly used. It provides good compression and has the advantage that it has
27//! an identical bit representation as a [`Tryte`] slice. For this reason, it is the only encoding
28//! that can be converted to a tryte slice with no overhead.
29//!
30//! [`T5B1`] is the most compressed encoding. It provides very high storage densities (almost
31//! optimal, in fact) and is the densest encoding supported by this crate.
32//!
33//! It is likely that one of the 3 encodings above will suit your requirements. In addition, this
34//! crate also supports [`T2B1`] and [`T4B1`] for completeness.
35//!
36//! # Byte Alignment
37//!
38//! This crate supports creating sub-slices of trit slices. To enable this, it stores extra
39//! metadata along with a trit slice in order to correct identify the index of a buffer it starts
40//! on. With compressed encodings, such as [`T3B1`], that starting index (and, indeed, the end
41//! index) may not fall exactly on a byte boundary.
42//!
43//! This crate makes a best attempt at avoiding the negative ramifications of this fact, but sadly
44//! some still leak through into the API. For example, some methods may panic if a slice does not
45//! have a byte-aligned starting index or otherwise does not fulfil certain invariants. However,
46//! all panicking behaviours are documented on each method such that you can easily avoid
47//! circumstances like this.
48//!
49//! When the documentation refers to 'byte alignment', it is referring specifically to whether the
50//! starting index is a multiple of the compression factor. For example a byte-aligned [`T3B1`]
51//! buffer will always start on an index of the *original* buffer that is a multiple of 3.
52
53#![deny(missing_docs)]
54
55use core::slice;
56
57/// Utility functions for encoding and decoding B1T6 encoding.
58pub mod b1t6;
59/// Conversions between to and from standard types.
60pub mod convert;
61/// Types and traits that allow the implementation of new encoding formats.
62pub mod raw;
63/// The [`T1B1`] and [`T1B1Buf`] encodings.
64pub mod t1b1;
65/// The [`T2B1`] and [`T2B1Buf`] encodings.
66pub mod t2b1;
67/// The [`T3B1`] and [`T3B1Buf`] encodings.
68pub mod t3b1;
69/// The [`T4B1`] and [`T4B1Buf`] encodings.
70pub mod t4b1;
71/// The [`T5B1`] and [`T5B1Buf`] encodings.
72pub mod t5b1;
73/// Types and traits used to represent trits, both balanced and unbalanced.
74pub mod trit;
75/// Types and traits used to represent trytes and buffers of trytes.
76pub mod tryte;
77
78#[cfg(feature = "serde")]
79mod serde;
80
81use alloc::borrow::ToOwned;
82use core::{
83    any,
84    borrow::{Borrow, BorrowMut},
85    cmp::Ordering,
86    convert::TryFrom,
87    fmt, hash,
88    iter::FromIterator,
89    ops::{
90        Deref, DerefMut, Index, IndexMut, Neg, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive,
91    },
92};
93
94use self::raw::{RawEncoding, RawEncodingBuf};
95pub use self::{
96    t1b1::{T1B1Buf, T1B1},
97    t2b1::{T2B1Buf, T2B1},
98    t3b1::{T3B1Buf, T3B1},
99    t4b1::{T4B1Buf, T4B1},
100    t5b1::{T5B1Buf, T5B1},
101    trit::{Btrit, ShiftTernary, Trit, Utrit},
102    tryte::{Tryte, TryteBuf},
103};
104
105/// An error that may be produced as a result of fallible conversions.
106#[derive(Debug)]
107pub enum Error {
108    /// A value that does not represent a valid ternary representation was encountered.
109    InvalidRepr,
110}
111
112impl fmt::Display for Error {
113    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114        match self {
115            Error::InvalidRepr => write!(f, "invalid representation"),
116        }
117    }
118}
119
120#[cfg(feature = "std")]
121impl std::error::Error for Error {}
122
123/// A type that represents a buffer of trits of unknown length.
124///
125/// This type is roughly analogous to `[T]` or [`str`]. It is an unsized type and hence is rarely
126/// used directly. Instead, it's more common to see it used from behind a reference (in a similar
127/// manner to `&[T]` and `&str`.
128#[derive(Hash)]
129#[repr(transparent)]
130pub struct Trits<T: RawEncoding + ?Sized = T1B1<Btrit>>(T);
131
132impl<T> Trits<T>
133where
134    T: RawEncoding + ?Sized,
135{
136    /// Create an empty trit slice.
137    pub fn empty() -> &'static Self {
138        unsafe { &*(T::empty() as *const _ as *const Self) }
139    }
140
141    /// Interpret an (`core::i8`) slice as a trit slice with the given encoding without first
142    /// checking that the slice is valid in the given encoding. The `num_trits` parameter is used
143    /// to specify the exact length, in trits, that the slice should be taken to have. Providing a
144    /// slice that is not valid for this encoding is undefined behaviour.
145    ///
146    /// # Panics
147    ///
148    /// This function will panic if `num_trits` is more than can be represented with the slice in
149    /// the given encoding.
150    ///
151    /// # Safety
152    ///
153    /// This function must only be called with an [`i8`] slice that is valid for this trit encoding
154    /// given the specified `num_trits` length. Right now, this validity is not well-defined and so
155    /// it is suggested that only [`i8`] slices created from existing trit slices or trit buffers
156    /// be used. Calling this function with an invalid [`i8`] slice is undefined behaviour.
157    pub unsafe fn from_raw_unchecked(raw: &[i8], num_trits: usize) -> &Self {
158        debug_assert!(
159            raw.iter().copied().all(T::is_valid),
160            "Invalid i8 slice used to create trit slice"
161        );
162        &*(T::from_raw_unchecked(raw, num_trits) as *const _ as *const _)
163    }
164
165    /// Interpret a mutable (`core::i8`) slice as a mutable trit slice with the given encoding
166    /// without first checking that the slice is valid in the given encoding. The `num_trits`
167    /// parameter is used to specify the exact length, in trits, that the slice should be taken to
168    /// have. Providing a slice that is not valid for this encoding is undefined behaviour.
169    ///
170    /// # Panics
171    ///
172    /// This function will panic if `num_trits` is more than can be represented with the slice in
173    /// the given encoding.
174    ///
175    /// # Safety
176    ///
177    /// This function must only be called with an [`i8`] slice that is valid for this trit encoding
178    /// given the specified `num_trits` length. Right now, this validity is not well-defined and so
179    /// it is suggested that only [`i8`] slices created from existing trit slices or trit buffers
180    /// be used. Calling this function with an invalid [`i8`] slice is undefined behaviour.
181    pub unsafe fn from_raw_unchecked_mut(raw: &mut [i8], num_trits: usize) -> &mut Self {
182        debug_assert!(
183            raw.iter().copied().all(T::is_valid),
184            "Invalid i8 slice used to create trit slice"
185        );
186        &mut *(T::from_raw_unchecked_mut(raw, num_trits) as *mut _ as *mut _)
187    }
188
189    /// Interpret an (`core::i8`) slice as a trit slice with the given encoding, checking to ensure
190    /// that the slice is valid in the given encoding. The `num_trits` parameter is used to specify
191    /// the exact length, in trits, that the slice should be taken to have.
192    ///
193    /// # Panics
194    ///
195    /// This function will panic if `num_trits` is more than can be represented with the slice in
196    /// the given encoding.
197    pub fn try_from_raw(raw: &[i8], num_trits: usize) -> Result<&Self, Error> {
198        if raw.iter().copied().all(T::is_valid) {
199            Ok(unsafe { Self::from_raw_unchecked(raw, num_trits) })
200        } else {
201            Err(Error::InvalidRepr)
202        }
203    }
204
205    /// Interpret a mutable (`core::i8`) slice as a mutable trit slice with the given encoding,
206    /// checking to ensure that the slice is valid in the given encoding. The `num_trits` parameter
207    /// is used to specify the exact length, in trits, that the slice should be taken to have.
208    ///
209    /// # Panics
210    ///
211    /// This function will panic if `num_trits` is more than can be represented with the slice in
212    /// the given encoding.
213    pub fn try_from_raw_mut(raw: &mut [i8], num_trits: usize) -> Result<&mut Self, Error> {
214        if raw.iter().copied().all(T::is_valid) {
215            Ok(unsafe { Self::from_raw_unchecked_mut(raw, num_trits) })
216        } else {
217            Err(Error::InvalidRepr)
218        }
219    }
220
221    /// Returns `true` if the trit slice is empty.
222    pub fn is_empty(&self) -> bool {
223        self.len() == 0
224    }
225
226    /// Returns the number of trits in this trit slice.
227    pub fn len(&self) -> usize {
228        self.0.len()
229    }
230
231    /// Interpret this slice as an (`core::i8`) slice.
232    ///
233    /// # Panics
234    ///
235    /// This function will panic if the slice is not byte-aligned.
236    pub fn as_i8_slice(&self) -> &[i8] {
237        self.0.as_i8_slice()
238    }
239
240    /// Interpret this slice as a mutable (`core::i8`) slice.
241    ///
242    /// # Panics
243    ///
244    /// This function will panic if the slice is not byte-aligned.
245    ///
246    /// # Safety
247    ///
248    /// This function is marked `unsafe` because modification of the trit slice in a manner that is
249    /// not valid for this encoding is undefined behaviour.
250    pub unsafe fn as_i8_slice_mut(&mut self) -> &mut [i8] {
251        self.0.as_i8_slice_mut()
252    }
253
254    /// Fetch the trit at the given index of this trit slice without first checking whether the
255    /// index is in bounds. Providing an index that is not less than the length of this slice is
256    /// undefined behaviour.
257    ///
258    /// This is perhaps the 'least bad' `unsafe` function in this crate: not because any form of
259    /// undefined behaviour is better or worse than another (after all, the point of undefined
260    /// behaviour is that it is undefined) but because it's the easiest to use correctly.
261    ///
262    /// # Safety
263    ///
264    /// An index with a value less then the result of [`Trits::len`] must be used. Any other value
265    /// is undefined behaviour.
266    pub unsafe fn get_unchecked(&self, index: usize) -> T::Trit {
267        debug_assert!(
268            index < self.0.len(),
269            "Attempt to get trit at index {}, but length of slice is {}",
270            index,
271            self.len(),
272        );
273        self.0.get_unchecked(index)
274    }
275
276    /// Set the trit at the given index of this trit slice without first checking whether the
277    /// index is in bounds. Providing an index that is not less than the length of this slice is
278    /// undefined behaviour.
279    ///
280    /// This is perhaps the 'least bad' `unsafe` function in this crate: not because any form of
281    /// undefined behaviour is better or worse than another (after all, the point of undefined
282    /// behaviour is that it is undefined) but because it's the easiest to use correctly.
283    ///
284    /// # Safety
285    ///
286    /// An index with a value less then the result of [`Trits::len`] must be used. Any other value
287    /// is undefined behaviour.
288    pub unsafe fn set_unchecked(&mut self, index: usize, trit: T::Trit) {
289        debug_assert!(
290            index < self.0.len(),
291            "Attempt to set trit at index {}, but length of slice is {}",
292            index,
293            self.len(),
294        );
295        self.0.set_unchecked(index, trit);
296    }
297
298    /// Fetch the trit at the given index of this trit slice, if the index is valid.
299    pub fn get(&self, index: usize) -> Option<T::Trit> {
300        if index < self.0.len() {
301            unsafe { Some(self.get_unchecked(index)) }
302        } else {
303            None
304        }
305    }
306
307    /// Set the trit at the given index of this mutable trit slice, if the index is valid.
308    ///
309    /// # Panics
310    ///
311    /// This function will panic if the index is not less than the length of this slice.
312    // TODO: Should we return `Option<()>` instead?
313    pub fn set(&mut self, index: usize, trit: T::Trit) {
314        assert!(
315            index < self.0.len(),
316            "Attempt to set trit at index {}, but length of slice is {}",
317            index,
318            self.len(),
319        );
320        unsafe { self.set_unchecked(index, trit) };
321    }
322
323    /// Returns an iterator over the trits in this slice.
324    ///
325    /// Using this function is significantly faster than calling [`Trits::get`] in a loop and
326    /// should be used where possible.
327    pub fn iter(&self) -> impl DoubleEndedIterator<Item = T::Trit> + ExactSizeIterator<Item = T::Trit> + '_ {
328        (0..self.0.len()).map(move |idx| unsafe { self.0.get_unchecked(idx) })
329    }
330
331    /// Returns a subslice of this slice with the given range of trits.
332    ///
333    /// # Panics
334    ///
335    /// This function will panic if called with a range that contains indices outside this slice,
336    /// or the start of the range is greater than its end.
337    pub fn subslice(&self, range: Range<usize>) -> &Self {
338        assert!(
339            range.end >= range.start && range.end <= self.len(),
340            "Sub-slice range must be within the bounds of the source trit slice",
341        );
342        unsafe { &*(self.0.slice_unchecked(range) as *const _ as *const Self) }
343    }
344
345    /// Returns a mutable subslice of this mutable slice with the given range of trits.
346    ///
347    /// # Panics
348    ///
349    /// This function will panic if called with a range that contains indices outside this slice,
350    /// or the start of the range is greater than its end.
351    pub fn subslice_mut(&mut self, range: Range<usize>) -> &mut Self {
352        assert!(
353            range.end >= range.start && range.end <= self.len(),
354            "Sub-slice range must be within the bounds of the source trit slice",
355        );
356        unsafe { &mut *(self.0.slice_unchecked_mut(range) as *mut _ as *mut Self) }
357    }
358
359    /// Copy the trits from a trit slice into this mutable trit slice (the encoding need not be
360    /// equivalent).
361    ///
362    /// # Panics
363    ///
364    /// This function will panic if the length of the slices are different.
365    pub fn copy_from<U: RawEncoding<Trit = T::Trit> + ?Sized>(&mut self, trits: &Trits<U>) {
366        assert!(
367            self.len() == trits.len(),
368            "Source trit slice must be the same length as target"
369        );
370        for (i, trit) in trits.iter().enumerate() {
371            unsafe {
372                self.set_unchecked(i, trit);
373            }
374        }
375    }
376
377    /// Fill this mutable trit slice with copied of the given trit.
378    pub fn fill(&mut self, trit: T::Trit) {
379        for i in 0..self.len() {
380            unsafe {
381                self.set_unchecked(i, trit);
382            }
383        }
384    }
385
386    /// Copy the contents of this trit slice into a new [`TritBuf`] with the same encoding. This
387    /// function is analogous to `to_vec` method implemented on ordinary slices.
388    pub fn to_buf<U: RawEncodingBuf<Slice = T>>(&self) -> TritBuf<U> {
389        // TODO: A faster impl than this!
390        self.iter().collect()
391    }
392
393    /// Return an iterator over distinct, non-overlapping subslices of this trit slice, each with
394    /// the given chunk length. If the length of the trit slice is not a multiple of the given
395    /// chunk length, the last slice provided by the iterator will be smaller to compensate.
396    ///
397    /// # Panics
398    ///
399    /// This function will panic if the given chunk length is `0`.
400    pub fn chunks(
401        &self,
402        chunk_len: usize,
403    ) -> impl DoubleEndedIterator<Item = &Self> + ExactSizeIterator<Item = &Self> + '_ {
404        assert!(chunk_len > 0, "Chunk length must be non-zero");
405        (0..self.len())
406            .step_by(chunk_len)
407            .map(move |i| &self[i..(i + chunk_len).min(self.len())])
408    }
409
410    /// Encode the contents of this trit slice into a `TritBuf` with a different encoding.
411    pub fn encode<U>(&self) -> TritBuf<U>
412    where
413        U: RawEncodingBuf,
414        U::Slice: RawEncoding<Trit = T::Trit>,
415    {
416        self.iter().collect()
417    }
418}
419
420impl<T> Trits<T>
421where
422    T: RawEncoding<Trit = Btrit> + ?Sized,
423{
424    /// Returns an iterator over the trytes represented within this slice.
425    ///
426    /// For encodings that are representation-compatible with trytes, such as [`T3B1`], use
427    /// [`Trits::as_trytes`] instead since it is faster and more capable.
428    pub fn iter_trytes(&self) -> impl DoubleEndedIterator<Item = Tryte> + ExactSizeIterator<Item = Tryte> + '_ {
429        assert!(self.len() % 3 == 0, "Trit slice length must be a multiple of 3");
430        self.chunks(3)
431            .map(|trits| Tryte::from_trits([trits.get(0).unwrap(), trits.get(1).unwrap(), trits.get(2).unwrap()]))
432    }
433
434    /// Negate each trit in this buffer.
435    ///
436    /// This has the effect of making the trit buffer negative when expressed in numeric form.
437    pub fn negate(&mut self) {
438        for i in 0..self.len() {
439            unsafe {
440                let t = self.get_unchecked(i);
441                self.set_unchecked(i, -t);
442            }
443        }
444    }
445}
446
447/// These functions are only implemented for trit slices with the [`T1B1`] encoding because other
448/// encodings are compressed and do not support handing out references to their internal trits.
449/// [`T1B1`] is an exception because its trits are strictly byte-aligned.
450///
451/// This fact also implies that [`T1B1`] is the fastest encoding for general-purpose manipulation
452/// of trits.
453impl<T: Trit> Trits<T1B1<T>> {
454    /// View this trit slice as an ordinary slice of trits.
455    pub fn as_raw_slice(&self) -> &[T] {
456        self.0.as_raw_slice()
457    }
458
459    /// View this mutable trit slice as an ordinary slice of mutable trits.
460    pub fn as_raw_slice_mut(&mut self) -> &mut [T] {
461        self.0.as_raw_slice_mut()
462    }
463
464    /// Return an iterator over distinct, non-overlapping mutable subslices of this mutable trit
465    /// slice, each with the given chunk length. If the length of the trit slice is not a multiple
466    /// of the given chunk length, the last slice provided by the iterator will be smaller to compensate.
467    ///
468    /// # Panics
469    ///
470    /// This function will panic if the given chunk length is `0`.
471    // Q: Why isn't this method on Trits<T>?
472    // A: Because overlapping slice lifetimes make this unsound on squashed encodings
473    pub fn chunks_mut(&mut self, chunk_len: usize) -> impl Iterator<Item = &mut Self> + '_ {
474        assert!(chunk_len > 0, "Chunk length must be non-zero");
475        (0..self.len()).step_by(chunk_len).scan(self, move |this, _| {
476            let idx = chunk_len.min(this.len());
477            let (a, b) = Trits::split_at_mut(this, idx);
478            *this = b;
479            Some(a)
480        })
481    }
482
483    /// Divides this mutable slice into two mutually exclusive mutable slices at the given index.
484    ///
485    /// The first slice will contain the indices within the range `0..mid` and the second `mid..len`.
486    fn split_at_mut<'a>(this: &mut &'a mut Self, mid: usize) -> (&'a mut Self, &'a mut Self) {
487        assert!(
488            mid <= this.len(),
489            "Cannot split at an index outside the trit slice bounds"
490        );
491        (
492            unsafe { &mut *(this.0.slice_unchecked_mut(0..mid) as *mut _ as *mut Self) },
493            unsafe { &mut *(this.0.slice_unchecked_mut(mid..this.len()) as *mut _ as *mut Self) },
494        )
495    }
496
497    /// Returns a mutable iterator over the trits in this slice.
498    ///
499    /// Using this function is significantly faster than calling [`Trits::set`] in a loop and
500    /// should be used where possible.
501    pub fn iter_mut(&mut self) -> slice::IterMut<T> {
502        self.as_raw_slice_mut().iter_mut()
503    }
504}
505
506impl<'a, T: Trit> From<&'a [T]> for &'a Trits<T1B1<T>> {
507    fn from(xs: &'a [T]) -> Self {
508        unsafe { Trits::from_raw_unchecked(&*(xs as *const _ as *const _), xs.len()) }
509    }
510}
511
512impl<'a, T: Trit> From<&'a mut [T]> for &'a mut Trits<T1B1<T>> {
513    fn from(xs: &'a mut [T]) -> Self {
514        unsafe { Trits::from_raw_unchecked_mut(&mut *(xs as *mut _ as *mut _), xs.len()) }
515    }
516}
517
518impl<'a, T: Trit> From<&'a Trits<T1B1<T>>> for &'a [T] {
519    fn from(trits: &'a Trits<T1B1<T>>) -> Self {
520        trits.as_raw_slice()
521    }
522}
523
524impl<'a, T: Trit> From<&'a mut Trits<T1B1<T>>> for &'a mut [T] {
525    fn from(trits: &'a mut Trits<T1B1<T>>) -> Self {
526        trits.as_raw_slice_mut()
527    }
528}
529
530/// These functions are only implemented for trit slices with the [`T3B1`] encoding because only
531/// the [`T3B1`] encoding has a representation compatible with a slice of `Tryte`s. If you find
532/// yourself commonly needing to convert between trits and trytes, [`T3B1`] is the encoding to use.
533impl Trits<T3B1> {
534    /// Interpret this trit slice as a [`Tryte`] slice.
535    ///
536    /// # Panics
537    ///
538    /// This function will panic if the length of the slice is not a multiple of `3`, or if the
539    /// slice is not byte-aligned.
540    pub fn as_trytes(&self) -> &[Tryte] {
541        assert!(self.len() % 3 == 0, "Trit slice length must be a multiple of 3");
542        unsafe { &*(self.as_i8_slice() as *const _ as *const _) }
543    }
544
545    /// Interpret this mutable trit slice as a mutable [`Tryte`] slice.
546    ///
547    /// # Panics
548    ///
549    /// This function will panic if the length of the slice is not a multiple of `3`, or if the
550    /// slice is not byte-aligned.
551    pub fn as_trytes_mut(&mut self) -> &mut [Tryte] {
552        assert!(self.len() % 3 == 0, "Trit slice length must be a multiple of 3");
553        unsafe { &mut *(self.as_i8_slice_mut() as *mut _ as *mut _) }
554    }
555}
556
557impl<T, U> PartialEq<Trits<U>> for Trits<T>
558where
559    T: RawEncoding + ?Sized,
560    U: RawEncoding<Trit = T::Trit> + ?Sized,
561{
562    fn eq(&self, other: &Trits<U>) -> bool {
563        self.len() == other.len() && self.iter().zip(other.iter()).all(|(a, b)| a == b)
564    }
565}
566
567impl<T> Eq for Trits<T> where T: RawEncoding + ?Sized {}
568
569impl<T, U> PartialOrd<Trits<U>> for Trits<T>
570where
571    T: RawEncoding + ?Sized,
572    U: RawEncoding<Trit = T::Trit> + ?Sized,
573    T::Trit: PartialOrd,
574{
575    fn partial_cmp(&self, other: &Trits<U>) -> Option<Ordering> {
576        if self.len() != other.len() {
577            return None;
578        }
579
580        for (a, b) in self.iter().zip(other.iter()) {
581            match a.partial_cmp(&b) {
582                Some(Ordering::Equal) => continue,
583                other_order => return other_order,
584            }
585        }
586
587        Some(Ordering::Equal)
588    }
589}
590
591impl<'a, T: RawEncoding + ?Sized> fmt::Debug for &'a Trits<T> {
592    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
593        write!(f, "Trits<{}> [", any::type_name::<T>())?;
594        for (i, trit) in self.iter().enumerate() {
595            if i != 0 {
596                write!(f, ", ")?;
597            }
598            write!(f, "{:?}", trit)?;
599        }
600        write!(f, "]")
601    }
602}
603
604// x
605
606impl<T: RawEncoding + ?Sized> Index<usize> for Trits<T> {
607    type Output = T::Trit;
608    fn index(&self, index: usize) -> &Self::Output {
609        self.get(index).expect("Index out of range").as_arbitrary_ref()
610    }
611}
612
613// x..y
614
615impl<T: RawEncoding + ?Sized> Index<Range<usize>> for Trits<T> {
616    type Output = Self;
617    fn index(&self, range: Range<usize>) -> &Self::Output {
618        self.subslice(range)
619    }
620}
621impl<T: RawEncoding + ?Sized> IndexMut<Range<usize>> for Trits<T> {
622    fn index_mut(&mut self, range: Range<usize>) -> &mut Self::Output {
623        self.subslice_mut(range)
624    }
625}
626
627// x..
628
629impl<T: RawEncoding + ?Sized> Index<RangeFrom<usize>> for Trits<T> {
630    type Output = Self;
631    fn index(&self, range: RangeFrom<usize>) -> &Self::Output {
632        self.subslice(range.start..self.len())
633    }
634}
635impl<T: RawEncoding + ?Sized> IndexMut<RangeFrom<usize>> for Trits<T> {
636    fn index_mut(&mut self, range: RangeFrom<usize>) -> &mut Self::Output {
637        self.subslice_mut(range.start..self.len())
638    }
639}
640
641// ..
642
643impl<T: RawEncoding + ?Sized> Index<RangeFull> for Trits<T> {
644    type Output = Self;
645    fn index(&self, _range: RangeFull) -> &Self::Output {
646        self
647    }
648}
649impl<T: RawEncoding + ?Sized> IndexMut<RangeFull> for Trits<T> {
650    fn index_mut(&mut self, _range: RangeFull) -> &mut Self::Output {
651        self
652    }
653}
654
655// x..=y
656
657impl<T: RawEncoding + ?Sized> Index<RangeInclusive<usize>> for Trits<T> {
658    type Output = Self;
659    fn index(&self, range: RangeInclusive<usize>) -> &Self::Output {
660        self.subslice(*range.start()..*range.end() + 1)
661    }
662}
663impl<T: RawEncoding + ?Sized> IndexMut<RangeInclusive<usize>> for Trits<T> {
664    fn index_mut(&mut self, range: RangeInclusive<usize>) -> &mut Self::Output {
665        self.subslice_mut(*range.start()..*range.end() + 1)
666    }
667}
668
669// ..y
670
671impl<T: RawEncoding + ?Sized> Index<RangeTo<usize>> for Trits<T> {
672    type Output = Self;
673    fn index(&self, range: RangeTo<usize>) -> &Self::Output {
674        self.subslice(0..range.end)
675    }
676}
677impl<T: RawEncoding + ?Sized> IndexMut<RangeTo<usize>> for Trits<T> {
678    fn index_mut(&mut self, range: RangeTo<usize>) -> &mut Self::Output {
679        self.subslice_mut(0..range.end)
680    }
681}
682
683// ..=y
684
685impl<T: RawEncoding + ?Sized> Index<RangeToInclusive<usize>> for Trits<T> {
686    type Output = Self;
687    fn index(&self, range: RangeToInclusive<usize>) -> &Self::Output {
688        self.subslice(0..range.end + 1)
689    }
690}
691impl<T: RawEncoding + ?Sized> IndexMut<RangeToInclusive<usize>> for Trits<T> {
692    fn index_mut(&mut self, range: RangeToInclusive<usize>) -> &mut Self::Output {
693        self.subslice_mut(0..range.end + 1)
694    }
695}
696
697impl<T: RawEncoding + ?Sized> ToOwned for Trits<T> {
698    type Owned = TritBuf<T::Buf>;
699
700    fn to_owned(&self) -> Self::Owned {
701        self.to_buf()
702    }
703}
704
705impl<T: RawEncoding + ?Sized> fmt::Display for Trits<T> {
706    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
707        write!(f, "[")?;
708        for (i, t) in self.iter().enumerate() {
709            if i != 0 {
710                write!(f, ", ")?;
711            }
712            write!(f, "{}", t)?;
713        }
714        write!(f, "]")
715    }
716}
717
718/// A buffer containing trits.
719///
720/// This type is roughly analogous to [`Vec`](alloc::vec::Vec) or [`String`](alloc::string::String). It supports pushing
721/// and popping trits and dereferences to [`Trits`]. It may be borrowed as a trit slice, either mutably or immutably.
722#[derive(Clone)]
723#[repr(transparent)]
724pub struct TritBuf<T: RawEncodingBuf = T1B1Buf<Btrit>>(T);
725
726impl<T: RawEncodingBuf> TritBuf<T> {
727    /// Create a new empty [`TritBuf`].
728    pub fn new() -> Self {
729        Self::default()
730    }
731
732    /// Create a new empty [`TritBuf`], backed by the given capacity, `cap`. The resulting
733    /// [`TritBuf`] will contain at least enough space to contain `cap` trits without needing to
734    /// reallocate.
735    pub fn with_capacity(cap: usize) -> Self {
736        Self(T::with_capacity(cap))
737    }
738
739    /// Create a new [`TritBuf`] of the given length, filled with copies of the provided trit.
740    pub fn filled(len: usize, trit: <T::Slice as RawEncoding>::Trit) -> Self {
741        let mut this = Self::with_capacity(len);
742        for _ in 0..len {
743            this.push(trit);
744        }
745        this
746    }
747
748    /// Create a new [`TritBuf`] of the given length, filled with zero trit.
749    pub fn zeros(len: usize) -> Self {
750        Self::filled(len, <T::Slice as RawEncoding>::Trit::zero())
751    }
752
753    /// Create a new [`TritBuf`] containing the trits from the given slice of trits.
754    pub fn from_trits(trits: &[<T::Slice as RawEncoding>::Trit]) -> Self {
755        Self(T::from_trits(trits))
756    }
757
758    /// Clears the buffer, removing all values.
759    /// Note that this method has no effect on the allocated capacity of the buffer.
760    pub fn clear(&mut self) {
761        self.0.clear();
762    }
763
764    /// Push a trit to the back of this [`TritBuf`].
765    pub fn push(&mut self, trit: <T::Slice as RawEncoding>::Trit) {
766        self.0.push(trit);
767    }
768
769    /// Pop a trit from the back of this [`TritBuf`], returning it if successful.
770    pub fn pop(&mut self) -> Option<<T::Slice as RawEncoding>::Trit> {
771        self.0.pop()
772    }
773
774    /// Append a trit slice to the end of this [`TritBuf`].
775    pub fn append<U: RawEncoding<Trit = <T::Slice as RawEncoding>::Trit> + ?Sized>(&mut self, trits: &Trits<U>) {
776        trits.iter().for_each(|t| self.push(t));
777    }
778
779    /// Extracts a trit slice containing the data within this buffer.
780    ///
781    /// Note that [`TritBuf`] dereferences to `Trits` anyway, so it's usually sufficient to take
782    /// a reference to [`TritBuf`] or to just call `&Trits` methods on it rather than explicitly
783    /// calling this method first.
784    pub fn as_slice(&self) -> &Trits<T::Slice> {
785        unsafe { &*(self.0.as_slice() as *const T::Slice as *const Trits<T::Slice>) }
786    }
787
788    /// Extracts a mutable trit slice containing the data within this buffer.
789    ///
790    /// Note that [`TritBuf`] dereferences to `Trits` anyway, so it's usually sufficient to take
791    /// a reference to [`TritBuf`] or to just call `&mut Trits` methods on it rather
792    /// explicitly calling this method first.
793    pub fn as_slice_mut(&mut self) -> &mut Trits<T::Slice> {
794        unsafe { &mut *(self.0.as_slice_mut() as *mut T::Slice as *mut Trits<T::Slice>) }
795    }
796
797    /// Returns the number of trits the `TritBuf` can hold without reallocating.
798    pub fn capacity(&self) -> usize {
799        self.0.capacity()
800    }
801}
802
803impl TritBuf<T3B1Buf> {
804    /// Pad the trit buffer with [`Btrit::Zero`] until the buffer's length is a multiple of 3.
805    ///
806    /// This method is often used in conjunction with [`Trits::as_trytes`].
807    pub fn pad_zeros(&mut self) {
808        while self.len() % 3 != 0 {
809            self.push(Btrit::Zero);
810        }
811    }
812
813    /// Pad the trit buffer with [`Btrit::Zero`] until the buffer's length is a multiple of 3.
814    ///
815    /// This method is often used in conjunction with [`Trits::as_trytes`].
816    #[must_use]
817    pub fn padded_zeros(mut self) -> Self {
818        self.pad_zeros();
819        self
820    }
821}
822
823impl<T: RawEncodingBuf> Neg for TritBuf<T>
824where
825    T::Slice: RawEncoding<Trit = Btrit>,
826{
827    type Output = Self;
828
829    #[must_use]
830    fn neg(mut self) -> Self {
831        self.negate();
832        self
833    }
834}
835
836impl<T: RawEncodingBuf> TritBuf<T>
837where
838    T::Slice: RawEncoding<Trit = Btrit>,
839{
840    /// Create a new [`TritBuf`] containing the trits given by the slice of i8s.
841    pub fn from_i8s(trits: &[i8]) -> Result<Self, <Btrit as TryFrom<i8>>::Error> {
842        trits.iter().map(|x| Btrit::try_from(*x)).collect()
843    }
844}
845
846impl<T: RawEncodingBuf> TritBuf<T>
847where
848    T::Slice: RawEncoding<Trit = Utrit>,
849{
850    /// Create a new [`TritBuf`] containing the trits given by the slice of u8s.
851    pub fn from_u8s(trits: &[u8]) -> Result<Self, <Btrit as TryFrom<u8>>::Error> {
852        trits.iter().map(|x| Utrit::try_from(*x)).collect()
853    }
854}
855
856impl<T: RawEncodingBuf> Default for TritBuf<T> {
857    fn default() -> Self {
858        Self(T::new())
859    }
860}
861
862impl<T> TritBuf<T1B1Buf<T>>
863where
864    T: Trit,
865    T::Target: Trit,
866{
867    /// Transform this [`TritBuf`] into a shifted representation. If the buffer contains
868    /// balanced trits ([`Btrit`]), the returned buffer will contain unbalanced trits ([`Utrit`]).
869    pub fn into_shifted(self) -> TritBuf<T1B1Buf<<T as ShiftTernary>::Target>> {
870        TritBuf(self.0.into_shifted())
871    }
872}
873
874impl<T: RawEncodingBuf, U: RawEncodingBuf> PartialEq<TritBuf<U>> for TritBuf<T>
875where
876    T::Slice: RawEncoding,
877    U::Slice: RawEncoding<Trit = <T::Slice as RawEncoding>::Trit>,
878{
879    fn eq(&self, other: &TritBuf<U>) -> bool {
880        self.as_slice() == other.as_slice()
881    }
882}
883
884impl<T: RawEncodingBuf> Eq for TritBuf<T> where T::Slice: RawEncoding {}
885
886impl<T: RawEncodingBuf> Deref for TritBuf<T> {
887    type Target = Trits<T::Slice>;
888
889    fn deref(&self) -> &Self::Target {
890        self.as_slice()
891    }
892}
893
894impl<T: RawEncodingBuf> DerefMut for TritBuf<T> {
895    fn deref_mut(&mut self) -> &mut Self::Target {
896        self.as_slice_mut()
897    }
898}
899
900impl<T: RawEncodingBuf> FromIterator<<T::Slice as RawEncoding>::Trit> for TritBuf<T> {
901    fn from_iter<I: IntoIterator<Item = <T::Slice as RawEncoding>::Trit>>(iter: I) -> Self {
902        let iter = iter.into_iter();
903        let mut this = Self::with_capacity(iter.size_hint().0);
904        for trit in iter {
905            this.push(trit);
906        }
907        this
908    }
909}
910
911impl<T> hash::Hash for TritBuf<T>
912where
913    T: RawEncodingBuf,
914    T::Slice: hash::Hash,
915{
916    fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
917        (**self).hash(hasher)
918    }
919}
920
921impl<T: RawEncodingBuf> fmt::Debug for TritBuf<T> {
922    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
923        write!(f, "TritBuf<{}> [", any::type_name::<T>())?;
924        for (i, trit) in self.iter().enumerate() {
925            if i != 0 {
926                write!(f, ", ")?;
927            }
928            write!(f, "{:?}", trit)?;
929        }
930        write!(f, "]")
931    }
932}
933
934impl<T: RawEncodingBuf> fmt::Display for TritBuf<T> {
935    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
936        write!(f, "{}", self.as_slice())
937    }
938}
939
940impl<T: RawEncodingBuf> Borrow<Trits<T::Slice>> for TritBuf<T> {
941    fn borrow(&self) -> &Trits<T::Slice> {
942        self.as_slice()
943    }
944}
945
946impl<T: RawEncodingBuf> BorrowMut<Trits<T::Slice>> for TritBuf<T> {
947    fn borrow_mut(&mut self) -> &mut Trits<T::Slice> {
948        self.as_slice_mut()
949    }
950}
951
952impl<T, U> PartialOrd<TritBuf<U>> for TritBuf<T>
953where
954    T: RawEncodingBuf,
955    U: RawEncodingBuf,
956    U::Slice: RawEncoding<Trit = <T::Slice as RawEncoding>::Trit>,
957    <T::Slice as RawEncoding>::Trit: PartialOrd,
958{
959    fn partial_cmp(&self, other: &TritBuf<U>) -> Option<Ordering> {
960        self.as_slice().partial_cmp(other.as_slice())
961    }
962}