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}