bee_block/payload/milestone/option/receipt/
tail_transaction_hash.rs

1// Copyright 2020-2021 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use alloc::string::String;
5use core::fmt;
6
7use bee_ternary::{T5B1Buf, TritBuf, Trits, T5B1};
8use bytemuck::cast_slice;
9use packable::{
10    error::{UnpackError, UnpackErrorExt},
11    packer::Packer,
12    unpacker::Unpacker,
13    Packable,
14};
15
16use crate::Error;
17
18/// Represents a tail transaction hash of a legacy bundle.
19#[derive(Clone, Eq, PartialEq)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
21pub struct TailTransactionHash(TritBuf<T5B1Buf>);
22
23impl TailTransactionHash {
24    /// The length of a [`TailTransactionHash`].
25    pub const LENGTH: usize = 49;
26
27    /// Creates a new [`TailTransactionHash`].
28    pub fn new(bytes: [u8; TailTransactionHash::LENGTH]) -> Result<Self, Error> {
29        bytes.try_into()
30    }
31}
32
33impl TryFrom<[u8; TailTransactionHash::LENGTH]> for TailTransactionHash {
34    type Error = Error;
35
36    fn try_from(bytes: [u8; TailTransactionHash::LENGTH]) -> Result<Self, Error> {
37        Ok(TailTransactionHash(
38            Trits::<T5B1>::try_from_raw(cast_slice(&bytes), 243)
39                .map_err(|_| Error::InvalidTailTransactionHash)?
40                .to_buf(),
41        ))
42    }
43}
44
45impl AsRef<[u8]> for TailTransactionHash {
46    fn as_ref(&self) -> &[u8] {
47        cast_slice(self.0.as_slice().as_i8_slice())
48    }
49}
50
51impl fmt::Display for TailTransactionHash {
52    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
53        write!(f, "{}", self.0.iter_trytes().map(char::from).collect::<String>())
54    }
55}
56
57impl fmt::Debug for TailTransactionHash {
58    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
59        write!(f, "TailTransactionHash({})", self)
60    }
61}
62
63impl Packable for TailTransactionHash {
64    type UnpackError = Error;
65    type UnpackVisitor = ();
66
67    fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error> {
68        packer.pack_bytes(self.as_ref())
69    }
70
71    fn unpack<U: Unpacker, const VERIFY: bool>(
72        unpacker: &mut U,
73        visitor: &Self::UnpackVisitor,
74    ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>> {
75        Self::new(<[u8; TailTransactionHash::LENGTH]>::unpack::<_, VERIFY>(unpacker, visitor).coerce()?)
76            .map_err(UnpackError::Packable)
77    }
78}