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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/// Creates a new type wrapping a variable-size byte array with common methods and trait implementations.
///
/// The `data!` macro generates a new type that wraps a [`Data`](crate::Data) container,
/// automatically implementing common methods and traits. This provides a convenient way to
/// create domain-specific types for variable-length binary data with minimal boilerplate.
///
/// # Usage
///
/// ```
/// # use zewif::data;
/// #
/// // Define a type for variable-length script data
/// data!(ScriptData, "A variable-length script for Zcash transactions.");
///
/// // Use the generated type
/// let script = ScriptData::new(vec![0xAA, 0xBB, 0xCC]);
/// ```
///
/// # Generated Functionality
///
/// The generated type includes methods for creation, conversion, and inspection,
/// as well as implementations for common traits like `Parse`, `Debug`, `Clone`,
/// and various conversion traits to and from byte collections.
///
/// This macro is especially useful for creating strong types around Zcash protocol
/// elements that have variable lengths, such as encrypted memos, scripts, and
/// other dynamically-sized data.
#[macro_export]
macro_rules! data {
($name:ident, $doc:expr) => {
#[doc = $doc]
pub struct $name($crate::Data);
impl $name {
/// Creates a new instance from a vector of bytes, taking ownership.
///
/// This is the primary constructor when you have a `Vec<u8>` available.
pub fn new(data: Vec<u8>) -> Self {
Self($crate::Data::from_vec(data))
}
/// Returns the number of bytes in this data container.
pub fn len(&self) -> usize {
self.0.len()
}
/// Returns `true` if this data container is empty (contains no bytes).
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
/// Converts this data to a `Vec<u8>`, creating a copy.
pub fn to_vec(&self) -> Vec<u8> {
self.0.to_vec()
}
/// Creates an instance from a slice of bytes.
pub fn from_slice(data: &[u8]) -> Self {
Self($crate::Data::from_slice(data))
}
/// Creates an instance from a `Vec<u8>`, taking ownership of the vector.
pub fn from_vec(data: Vec<u8>) -> Self {
Self($crate::Data::from_vec(data))
}
/// Creates an instance from a hexadecimal string.
///
/// # Panics
/// Panics if the hex string cannot be decoded.
pub fn from_hex(hex: &str) -> Self {
Self($crate::Data::from_hex(hex).unwrap())
}
}
impl Clone for $name {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl std::fmt::Debug for $name {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}({:?})", stringify!($name), self.0)
}
}
impl Default for $name {
fn default() -> Self {
Self($crate::Data::default())
}
}
impl PartialEq for $name {
fn eq(&self, other: &Self) -> bool {
self.0.eq(&other.0)
}
}
impl Eq for $name {}
impl AsRef<[u8]> for $name {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl From<$name> for Vec<u8> {
fn from(data: $name) -> Vec<u8> {
data.to_vec()
}
}
impl From<&$name> for Vec<u8> {
fn from(data: &$name) -> Vec<u8> {
data.to_vec()
}
}
impl From<Vec<u8>> for $name {
fn from(data: Vec<u8>) -> Self {
Self::from_vec(data)
}
}
impl From<&[u8]> for $name {
fn from(data: &[u8]) -> Self {
Self::from_slice(data)
}
}
impl From<$name> for bc_envelope::prelude::CBOR {
fn from(data: $name) -> Self {
bc_envelope::prelude::CBOR::to_byte_string(data.0)
}
}
impl From<&$name> for bc_envelope::prelude::CBOR {
fn from(data: &$name) -> Self {
bc_envelope::prelude::CBOR::to_byte_string(data.0.clone())
}
}
impl TryFrom<bc_envelope::prelude::CBOR> for $name {
type Error = dcbor::Error;
fn try_from(cbor: bc_envelope::prelude::CBOR) -> Result<Self, Self::Error> {
let bytes = cbor.try_into_byte_string()?;
Ok(Self::from_slice(&bytes))
}
}
#[cfg(test)]
impl $crate::RandomInstance for $name {
fn random() -> Self {
Self($crate::Data::random())
}
}
};
}