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