• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

iotaledger / crypto.rs / 10388581153

14 Aug 2024 01:30PM UTC coverage: 70.605% (-0.01%) from 70.617%
10388581153

push

github

web-flow
update code coverage flag (use stable options argument) (#225)

3771 of 5341 relevant lines covered (70.6%)

48948487.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

57.94
/src/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

55
use core::slice;
56

57
/// Utility functions for encoding and decoding B1T6 encoding.
58
pub mod b1t6;
59
/// Conversions between to and from standard types.
60
pub mod convert;
61
/// Types and traits that allow the implementation of new encoding formats.
62
pub mod raw;
63
/// The [`T1B1`] and [`T1B1Buf`] encodings.
64
pub mod t1b1;
65
/// The [`T2B1`] and [`T2B1Buf`] encodings.
66
pub mod t2b1;
67
/// The [`T3B1`] and [`T3B1Buf`] encodings.
68
pub mod t3b1;
69
/// The [`T4B1`] and [`T4B1Buf`] encodings.
70
pub mod t4b1;
71
/// The [`T5B1`] and [`T5B1Buf`] encodings.
72
pub mod t5b1;
73
/// Types and traits used to represent trits, both balanced and unbalanced.
74
pub mod trit;
75
/// Types and traits used to represent trytes and buffers of trytes.
76
pub mod tryte;
77

78
#[cfg(feature = "serde")]
79
mod serde;
80

81
use alloc::borrow::ToOwned;
82
use 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

94
use self::raw::{RawEncoding, RawEncodingBuf};
95
pub 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)]
107
pub enum Error {
108
    /// A value that does not represent a valid ternary representation was encountered.
109
    InvalidRepr,
110
}
111

112
impl 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")]
121
impl 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)]
130
pub struct Trits<T: RawEncoding + ?Sized = T1B1<Btrit>>(T);
131

132
impl<T> Trits<T>
133
where
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 {
310✔
158
        debug_assert!(
310✔
159
            raw.iter().copied().all(T::is_valid),
310✔
160
            "Invalid i8 slice used to create trit slice"
×
161
        );
162
        &*(T::from_raw_unchecked(raw, num_trits) as *const _ as *const _)
310✔
163
    }
310✔
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 {
698,607✔
223
        self.len() == 0
698,607✔
224
    }
698,607✔
225

226
    /// Returns the number of trits in this trit slice.
227
    pub fn len(&self) -> usize {
140,366,978✔
228
        self.0.len()
140,366,978✔
229
    }
140,366,978✔
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] {
7,864,048✔
237
        self.0.as_i8_slice()
7,864,048✔
238
    }
7,864,048✔
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] {
7,793,726✔
251
        self.0.as_i8_slice_mut()
7,793,726✔
252
    }
7,793,726✔
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 {
92,218,718✔
267
        debug_assert!(
92,218,718✔
268
            index < self.0.len(),
92,218,718✔
269
            "Attempt to get trit at index {}, but length of slice is {}",
×
270
            index,
×
271
            self.len(),
×
272
        );
273
        self.0.get_unchecked(index)
92,218,718✔
274
    }
92,218,718✔
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) {
2,147,483,647✔
289
        debug_assert!(
2,147,483,647✔
290
            index < self.0.len(),
2,147,483,647✔
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);
2,147,483,647✔
296
    }
2,147,483,647✔
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> {
8,252,872✔
300
        if index < self.0.len() {
8,252,872✔
301
            unsafe { Some(self.get_unchecked(index)) }
8,237,872✔
302
        } else {
303
            None
15,000✔
304
        }
305
    }
8,252,872✔
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) {
442,134✔
314
        assert!(
442,134✔
315
            index < self.0.len(),
442,134✔
316
            "Attempt to set trit at index {}, but length of slice is {}",
1✔
317
            index,
1✔
318
            self.len(),
1✔
319
        );
320
        unsafe { self.set_unchecked(index, trit) };
442,133✔
321
    }
442,133✔
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> + '_ {
32,126,995✔
328
        (0..self.0.len()).map(move |idx| unsafe { self.0.get_unchecked(idx) })
2,147,483,647✔
329
    }
32,126,995✔
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 {
10,668,170✔
338
        assert!(
10,668,170✔
339
            range.end >= range.start && range.end <= self.len(),
10,668,170✔
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) }
10,668,170✔
343
    }
10,668,170✔
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 {
234,880✔
352
        assert!(
234,880✔
353
            range.end >= range.start && range.end <= self.len(),
234,880✔
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) }
234,880✔
357
    }
234,880✔
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>) {
15,648,335✔
366
        assert!(
15,648,335✔
367
            self.len() == trits.len(),
15,648,335✔
368
            "Source trit slice must be the same length as target"
×
369
        );
370
        for (i, trit) in trits.iter().enumerate() {
2,147,483,647✔
371
            unsafe {
2,147,483,647✔
372
                self.set_unchecked(i, trit);
2,147,483,647✔
373
            }
2,147,483,647✔
374
        }
375
    }
15,648,335✔
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> {
310✔
389
        // TODO: A faster impl than this!
310✔
390
        self.iter().collect()
310✔
391
    }
310✔
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(
7,557,168✔
401
        &self,
7,557,168✔
402
        chunk_len: usize,
7,557,168✔
403
    ) -> impl DoubleEndedIterator<Item = &Self> + ExactSizeIterator<Item = &Self> + '_ {
7,557,168✔
404
        assert!(chunk_len > 0, "Chunk length must be non-zero");
7,557,168✔
405
        (0..self.len())
7,557,168✔
406
            .step_by(chunk_len)
7,557,168✔
407
            .map(move |i| &self[i..(i + chunk_len).min(self.len())])
10,551,085✔
408
    }
7,557,168✔
409

410
    /// Encode the contents of this trit slice into a `TritBuf` with a different encoding.
411
    pub fn encode<U>(&self) -> TritBuf<U>
87,614✔
412
    where
87,614✔
413
        U: RawEncodingBuf,
87,614✔
414
        U::Slice: RawEncoding<Trit = T::Trit>,
87,614✔
415
    {
87,614✔
416
        self.iter().collect()
87,614✔
417
    }
87,614✔
418
}
419

420
impl<T> Trits<T>
421
where
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> + '_ {
4,911✔
429
        assert!(self.len() % 3 == 0, "Trit slice length must be a multiple of 3");
4,911✔
430
        self.chunks(3)
4,911✔
431
            .map(|trits| Tryte::from_trits([trits.get(0).unwrap(), trits.get(1).unwrap(), trits.get(2).unwrap()]))
2,669,291✔
432
    }
4,911✔
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) {
4✔
438
        for i in 0..self.len() {
46✔
439
            unsafe {
46✔
440
                let t = self.get_unchecked(i);
46✔
441
                self.set_unchecked(i, -t);
46✔
442
            }
46✔
443
        }
444
    }
4✔
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.
453
impl<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] {
43,174✔
461
        self.0.as_raw_slice_mut()
43,174✔
462
    }
43,174✔
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> + '_ {
7,575,372✔
474
        assert!(chunk_len > 0, "Chunk length must be non-zero");
7,575,372✔
475
        (0..self.len()).step_by(chunk_len).scan(self, move |this, _| {
8,120,267✔
476
            let idx = chunk_len.min(this.len());
8,120,267✔
477
            let (a, b) = Trits::split_at_mut(this, idx);
8,120,267✔
478
            *this = b;
8,120,267✔
479
            Some(a)
8,120,267✔
480
        })
8,120,267✔
481
    }
7,575,372✔
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) {
8,120,267✔
487
        assert!(
8,120,267✔
488
            mid <= this.len(),
8,120,267✔
489
            "Cannot split at an index outside the trit slice bounds"
×
490
        );
491
        (
8,120,267✔
492
            unsafe { &mut *(this.0.slice_unchecked_mut(0..mid) as *mut _ as *mut Self) },
8,120,267✔
493
            unsafe { &mut *(this.0.slice_unchecked_mut(mid..this.len()) as *mut _ as *mut Self) },
8,120,267✔
494
        )
8,120,267✔
495
    }
8,120,267✔
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> {
43,174✔
502
        self.as_raw_slice_mut().iter_mut()
43,174✔
503
    }
43,174✔
504
}
505

506
impl<'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

512
impl<'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

518
impl<'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

524
impl<'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.
533
impl 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] {
1✔
541
        assert!(self.len() % 3 == 0, "Trit slice length must be a multiple of 3");
1✔
542
        unsafe { &*(self.as_i8_slice() as *const _ as *const _) }
1✔
543
    }
1✔
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

557
impl<T, U> PartialEq<Trits<U>> for Trits<T>
558
where
559
    T: RawEncoding + ?Sized,
560
    U: RawEncoding<Trit = T::Trit> + ?Sized,
561
{
562
    fn eq(&self, other: &Trits<U>) -> bool {
91,796✔
563
        self.len() == other.len() && self.iter().zip(other.iter()).all(|(a, b)| a == b)
23,256,848✔
564
    }
91,796✔
565
}
566

567
impl<T> Eq for Trits<T> where T: RawEncoding + ?Sized {}
568

569
impl<T, U> PartialOrd<Trits<U>> for Trits<T>
570
where
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

591
impl<'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

606
impl<T: RawEncoding + ?Sized> Index<usize> for Trits<T> {
607
    type Output = T::Trit;
608
    fn index(&self, index: usize) -> &Self::Output {
4,113✔
609
        self.get(index).expect("Index out of range").as_arbitrary_ref()
4,113✔
610
    }
4,113✔
611
}
612

613
// x..y
614

615
impl<T: RawEncoding + ?Sized> Index<Range<usize>> for Trits<T> {
616
    type Output = Self;
617
    fn index(&self, range: Range<usize>) -> &Self::Output {
10,668,169✔
618
        self.subslice(range)
10,668,169✔
619
    }
10,668,169✔
620
}
621
impl<T: RawEncoding + ?Sized> IndexMut<Range<usize>> for Trits<T> {
622
    fn index_mut(&mut self, range: Range<usize>) -> &mut Self::Output {
234,880✔
623
        self.subslice_mut(range)
234,880✔
624
    }
234,880✔
625
}
626

627
// x..
628

629
impl<T: RawEncoding + ?Sized> Index<RangeFrom<usize>> for Trits<T> {
630
    type Output = Self;
631
    fn index(&self, range: RangeFrom<usize>) -> &Self::Output {
1✔
632
        self.subslice(range.start..self.len())
1✔
633
    }
1✔
634
}
635
impl<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

643
impl<T: RawEncoding + ?Sized> Index<RangeFull> for Trits<T> {
644
    type Output = Self;
645
    fn index(&self, _range: RangeFull) -> &Self::Output {
×
646
        self
×
647
    }
×
648
}
649
impl<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

657
impl<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
}
663
impl<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

671
impl<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
}
677
impl<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

685
impl<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
}
691
impl<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

697
impl<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

705
impl<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)]
724
pub struct TritBuf<T: RawEncodingBuf = T1B1Buf<Btrit>>(T);
725

726
impl<T: RawEncodingBuf> TritBuf<T> {
727
    /// Create a new empty [`TritBuf`].
728
    pub fn new() -> Self {
6✔
729
        Self::default()
6✔
730
    }
6✔
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 {
8,281,164✔
736
        Self(T::with_capacity(cap))
8,281,164✔
737
    }
8,281,164✔
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 {
7,887,257✔
741
        let mut this = Self::with_capacity(len);
7,887,257✔
742
        for _ in 0..len {
1,971,073,950✔
743
            this.push(trit);
1,971,073,950✔
744
        }
1,971,073,950✔
745
        this
7,887,257✔
746
    }
7,887,257✔
747

748
    /// Create a new [`TritBuf`] of the given length, filled with zero trit.
749
    pub fn zeros(len: usize) -> Self {
7,887,253✔
750
        Self::filled(len, <T::Slice as RawEncoding>::Trit::zero())
7,887,253✔
751
    }
7,887,253✔
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 {
1✔
755
        Self(T::from_trits(trits))
1✔
756
    }
1✔
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) {
500✔
761
        self.0.clear();
500✔
762
    }
500✔
763

764
    /// Push a trit to the back of this [`TritBuf`].
765
    pub fn push(&mut self, trit: <T::Slice as RawEncoding>::Trit) {
2,028,703,068✔
766
        self.0.push(trit);
2,028,703,068✔
767
    }
2,028,703,068✔
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> {
15,948,361✔
771
        self.0.pop()
15,948,361✔
772
    }
15,948,361✔
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>) {
268✔
776
        trits.iter().for_each(|t| self.push(t));
804✔
777
    }
268✔
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> {
147,399,291✔
785
        unsafe { &*(self.0.as_slice() as *const T::Slice as *const Trits<T::Slice>) }
147,399,291✔
786
    }
147,399,291✔
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> {
15,840,971✔
794
        unsafe { &mut *(self.0.as_slice_mut() as *mut T::Slice as *mut Trits<T::Slice>) }
15,840,971✔
795
    }
15,840,971✔
796

797
    /// Returns the number of trits the `TritBuf` can hold without reallocating.
798
    pub fn capacity(&self) -> usize {
18✔
799
        self.0.capacity()
18✔
800
    }
18✔
801
}
802

803
impl 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

823
impl<T: RawEncodingBuf> Neg for TritBuf<T>
824
where
825
    T::Slice: RawEncoding<Trit = Btrit>,
826
{
827
    type Output = Self;
828

829
    #[must_use]
830
    fn neg(mut self) -> Self {
4✔
831
        self.negate();
4✔
832
        self
4✔
833
    }
4✔
834
}
835

836
impl<T: RawEncodingBuf> TritBuf<T>
837
where
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> {
10✔
842
        trits.iter().map(|x| Btrit::try_from(*x)).collect()
88✔
843
    }
10✔
844
}
845

846
impl<T: RawEncodingBuf> TritBuf<T>
847
where
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> {
8✔
852
        trits.iter().map(|x| Utrit::try_from(*x)).collect()
75✔
853
    }
8✔
854
}
855

856
impl<T: RawEncodingBuf> Default for TritBuf<T> {
857
    fn default() -> Self {
6✔
858
        Self(T::new())
6✔
859
    }
6✔
860
}
861

862
impl<T> TritBuf<T1B1Buf<T>>
863
where
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>> {
15,648,335✔
870
        TritBuf(self.0.into_shifted())
15,648,335✔
871
    }
15,648,335✔
872
}
873

874
impl<T: RawEncodingBuf, U: RawEncodingBuf> PartialEq<TritBuf<U>> for TritBuf<T>
875
where
876
    T::Slice: RawEncoding,
877
    U::Slice: RawEncoding<Trit = <T::Slice as RawEncoding>::Trit>,
878
{
879
    fn eq(&self, other: &TritBuf<U>) -> bool {
41,257✔
880
        self.as_slice() == other.as_slice()
41,257✔
881
    }
41,257✔
882
}
883

884
impl<T: RawEncodingBuf> Eq for TritBuf<T> where T::Slice: RawEncoding {}
885

886
impl<T: RawEncodingBuf> Deref for TritBuf<T> {
887
    type Target = Trits<T::Slice>;
888

889
    fn deref(&self) -> &Self::Target {
146,945,183✔
890
        self.as_slice()
146,945,183✔
891
    }
146,945,183✔
892
}
893

894
impl<T: RawEncodingBuf> DerefMut for TritBuf<T> {
895
    fn deref_mut(&mut self) -> &mut Self::Target {
15,770,572✔
896
        self.as_slice_mut()
15,770,572✔
897
    }
15,770,572✔
898
}
899

900
impl<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 {
393,886✔
902
        let iter = iter.into_iter();
393,886✔
903
        let mut this = Self::with_capacity(iter.size_hint().0);
393,886✔
904
        for trit in iter {
42,068,499✔
905
            this.push(trit);
41,674,613✔
906
        }
41,674,613✔
907
        this
393,886✔
908
    }
393,886✔
909
}
910

911
impl<T> hash::Hash for TritBuf<T>
912
where
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

921
impl<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

934
impl<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

940
impl<T: RawEncodingBuf> Borrow<Trits<T::Slice>> for TritBuf<T> {
941
    fn borrow(&self) -> &Trits<T::Slice> {
×
942
        self.as_slice()
×
943
    }
×
944
}
945

946
impl<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

952
impl<T, U> PartialOrd<TritBuf<U>> for TritBuf<T>
953
where
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
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc