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}