1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use crate::{
constants::INPUT_OUTPUT_INDEX_RANGE,
payload::transaction::{TransactionId, TRANSACTION_ID_LENGTH},
Error,
};
use bee_common::packable::{Packable, Read, Write};
use core::{
convert::{From, TryFrom, TryInto},
str::FromStr,
};
pub const OUTPUT_ID_LENGTH: usize = TRANSACTION_ID_LENGTH + std::mem::size_of::<u16>();
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct OutputId {
transaction_id: TransactionId,
index: u16,
}
impl OutputId {
pub fn new(transaction_id: TransactionId, index: u16) -> Result<Self, Error> {
if !INPUT_OUTPUT_INDEX_RANGE.contains(&index) {
return Err(Error::InvalidInputOutputIndex(index));
}
Ok(Self { transaction_id, index })
}
pub fn transaction_id(&self) -> &TransactionId {
&self.transaction_id
}
pub fn index(&self) -> u16 {
self.index
}
pub fn split(self) -> (TransactionId, u16) {
(self.transaction_id, self.index)
}
}
#[cfg(feature = "serde")]
string_serde_impl!(OutputId);
impl TryFrom<[u8; OUTPUT_ID_LENGTH]> for OutputId {
type Error = Error;
fn try_from(bytes: [u8; OUTPUT_ID_LENGTH]) -> Result<Self, Self::Error> {
let (transaction_id, index) = bytes.split_at(TRANSACTION_ID_LENGTH);
Self::new(
From::<[u8; TRANSACTION_ID_LENGTH]>::from(transaction_id.try_into().unwrap()),
u16::from_le_bytes(index.try_into().unwrap()),
)
}
}
impl FromStr for OutputId {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let bytes: [u8; OUTPUT_ID_LENGTH] = hex::decode(s)
.map_err(|_| Self::Err::InvalidHexadecimalChar(s.to_owned()))?
.try_into()
.map_err(|_| Self::Err::InvalidHexadecimalLength(OUTPUT_ID_LENGTH * 2, s.len()))?;
bytes.try_into()
}
}
impl core::fmt::Display for OutputId {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}{}", self.transaction_id, hex::encode(self.index.to_le_bytes()))
}
}
impl core::fmt::Debug for OutputId {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "OutputId({})", self)
}
}
impl Packable for OutputId {
type Error = Error;
fn packed_len(&self) -> usize {
self.transaction_id.packed_len() + self.index.packed_len()
}
fn pack<W: Write>(&self, writer: &mut W) -> Result<(), Self::Error> {
self.transaction_id.pack(writer)?;
self.index.pack(writer)?;
Ok(())
}
fn unpack_inner<R: Read + ?Sized, const CHECK: bool>(reader: &mut R) -> Result<Self, Self::Error> {
let transaction_id = TransactionId::unpack_inner::<R, CHECK>(reader)?;
let index = u16::unpack_inner::<R, CHECK>(reader)?;
Self::new(transaction_id, index)
}
}