1use std::cmp::Ordering;
4use std::convert::{TryFrom, TryInto};
5use std::error;
6use std::fmt;
7use std::ops::Deref;
8use std::str;
9
10fn fmt_colon_delimited_hex<B>(f: &mut fmt::Formatter<'_>, bytes: B) -> fmt::Result
15where
16 B: AsRef<[u8]>,
17{
18 let len = bytes.as_ref().len();
19
20 for (i, byte) in bytes.as_ref().iter().enumerate() {
21 write!(f, "{:02x}", byte)?;
22
23 if i != len - 1 {
24 write!(f, ":")?;
25 }
26 }
27
28 Ok(())
29}
30
31#[derive(Debug, PartialEq)]
33pub enum Error {
34 InvalidUtf8(std::str::Utf8Error),
35 TooLong(usize),
36}
37
38impl fmt::Display for Error {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 match self {
41 Error::InvalidUtf8(e) => write!(f, "Invalid UTF-8: {}", e),
42 Error::TooLong(n) => write!(f, "Memo length {} is larger than maximum of 512", n),
43 }
44 }
45}
46
47impl error::Error for Error {}
48
49#[derive(Clone)]
51pub struct MemoBytes(pub(crate) Box<[u8; 512]>);
52
53impl fmt::Debug for MemoBytes {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 write!(f, "MemoBytes(")?;
56 fmt_colon_delimited_hex(f, &self.0[..])?;
57 write!(f, ")")
58 }
59}
60
61impl PartialEq for MemoBytes {
62 fn eq(&self, rhs: &MemoBytes) -> bool {
63 self.0[..] == rhs.0[..]
64 }
65}
66
67impl Eq for MemoBytes {}
68
69impl PartialOrd for MemoBytes {
70 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
71 Some(self.cmp(other))
72 }
73}
74
75impl Ord for MemoBytes {
76 fn cmp(&self, rhs: &Self) -> Ordering {
77 self.0[..].cmp(&rhs.0[..])
78 }
79}
80
81impl MemoBytes {
82 pub fn empty() -> Self {
84 let mut bytes = [0u8; 512];
85 bytes[0] = 0xF6;
86 MemoBytes(Box::new(bytes))
87 }
88
89 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
99 if bytes.len() > 512 {
100 return Err(Error::TooLong(bytes.len()));
101 }
102
103 let mut memo = [0u8; 512];
104 memo[..bytes.len()].copy_from_slice(bytes);
105 Ok(MemoBytes(Box::new(memo)))
106 }
107
108 pub fn as_array(&self) -> &[u8; 512] {
110 &self.0
111 }
112
113 pub fn as_slice(&self) -> &[u8] {
115 let first_null = self
116 .0
117 .iter()
118 .enumerate()
119 .rev()
120 .find(|(_, &b)| b != 0)
121 .map(|(i, _)| i + 1)
122 .unwrap_or_default();
123
124 &self.0[..first_null]
125 }
126}
127
128#[derive(Clone, PartialEq)]
130pub struct TextMemo(String);
131
132impl From<TextMemo> for String {
133 fn from(memo: TextMemo) -> String {
134 memo.0
135 }
136}
137
138impl Deref for TextMemo {
139 type Target = str;
140
141 #[inline]
142 fn deref(&self) -> &str {
143 self.0.deref()
144 }
145}
146
147#[derive(Clone)]
149pub enum Memo {
150 Empty,
152 Text(TextMemo),
154 Future(MemoBytes),
156 Arbitrary(Box<[u8; 511]>),
158}
159
160impl fmt::Debug for Memo {
161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 match self {
163 Memo::Empty => write!(f, "Memo::Empty"),
164 Memo::Text(memo) => write!(f, "Memo::Text(\"{}\")", memo.0),
165 Memo::Future(bytes) => write!(f, "Memo::Future({:0x})", bytes.0[0]),
166 Memo::Arbitrary(bytes) => {
167 write!(f, "Memo::Arbitrary(")?;
168 fmt_colon_delimited_hex(f, &bytes[..])?;
169 write!(f, ")")
170 }
171 }
172 }
173}
174
175impl Default for Memo {
176 fn default() -> Self {
177 Memo::Empty
178 }
179}
180
181impl PartialEq for Memo {
182 fn eq(&self, rhs: &Memo) -> bool {
183 match (self, rhs) {
184 (Memo::Empty, Memo::Empty) => true,
185 (Memo::Text(a), Memo::Text(b)) => a == b,
186 (Memo::Future(a), Memo::Future(b)) => a.0[..] == b.0[..],
187 (Memo::Arbitrary(a), Memo::Arbitrary(b)) => a[..] == b[..],
188 _ => false,
189 }
190 }
191}
192
193impl TryFrom<MemoBytes> for Memo {
194 type Error = Error;
195
196 fn try_from(bytes: MemoBytes) -> Result<Self, Self::Error> {
201 match bytes.0[0] {
202 0xF6 if bytes.0.iter().skip(1).all(|&b| b == 0) => Ok(Memo::Empty),
203 0xFF => Ok(Memo::Arbitrary(Box::new(bytes.0[1..].try_into().unwrap()))),
204 b if b <= 0xF4 => str::from_utf8(bytes.as_slice())
205 .map(|r| Memo::Text(TextMemo(r.to_owned())))
206 .map_err(Error::InvalidUtf8),
207 _ => Ok(Memo::Future(bytes)),
208 }
209 }
210}
211
212impl From<Memo> for MemoBytes {
213 fn from(memo: Memo) -> Self {
215 match memo {
216 Memo::Future(memo) => memo,
218 memo => (&memo).into(),
219 }
220 }
221}
222
223impl From<&Memo> for MemoBytes {
224 fn from(memo: &Memo) -> Self {
226 match memo {
227 Memo::Empty => MemoBytes::empty(),
228 Memo::Text(s) => {
229 let mut bytes = [0u8; 512];
230 let s_bytes = s.0.as_bytes();
231 bytes[..s_bytes.len()].copy_from_slice(s_bytes);
233 MemoBytes(Box::new(bytes))
234 }
235 Memo::Future(memo) => memo.clone(),
236 Memo::Arbitrary(arb) => {
237 let mut bytes = [0u8; 512];
238 bytes[0] = 0xFF;
239 bytes[1..].copy_from_slice(arb.as_ref());
240 MemoBytes(Box::new(bytes))
241 }
242 }
243 }
244}
245
246impl Memo {
247 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
252 MemoBytes::from_bytes(bytes).and_then(TryFrom::try_from)
253 }
254
255 pub fn encode(&self) -> MemoBytes {
257 self.into()
258 }
259}
260
261impl str::FromStr for Memo {
262 type Err = Error;
263
264 fn from_str(memo: &str) -> Result<Self, Self::Err> {
266 if memo.is_empty() {
267 Ok(Memo::Empty)
268 } else if memo.len() <= 512 {
269 Ok(Memo::Text(TextMemo(memo.to_owned())))
270 } else {
271 Err(Error::TooLong(memo.len()))
272 }
273 }
274}
275
276#[cfg(test)]
277mod tests {
278 use std::convert::TryInto;
279 use std::str::FromStr;
280
281 use super::{Error, Memo, MemoBytes};
282
283 #[test]
284 fn memo_from_str() {
285 assert_eq!(
286 Memo::from_str("").unwrap().encode(),
287 MemoBytes(Box::new([
288 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
298 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
299 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
301 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
302 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
305 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
306 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
307 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
310 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
314 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
317 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
318 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
319 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
321 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
325 ]))
326 );
327 assert_eq!(
328 Memo::from_str(
329 "thiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \
330 iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \
331 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
332 veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeryyyyyyyyyyyyyyyyyyyyyyyyyy \
333 looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong \
334 meeeeeeeeeeeeeeeeeeemooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo \
335 but it's just short enough"
336 )
337 .unwrap()
338 .encode(),
339 MemoBytes(Box::new([
340 0x74, 0x68, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
341 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
342 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
343 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
344 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
345 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x73, 0x20, 0x69, 0x69, 0x69,
346 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
347 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
348 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
349 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
350 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
351 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x73, 0x20, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
352 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
353 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
354 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
355 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
356 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
357 0x61, 0x61, 0x61, 0x61, 0x20, 0x76, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
358 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
359 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
360 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
361 0x65, 0x65, 0x72, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79,
362 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79,
363 0x79, 0x20, 0x6c, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
364 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
365 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
366 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
367 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
368 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6e, 0x67, 0x20, 0x6d,
369 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
370 0x65, 0x65, 0x65, 0x65, 0x65, 0x6d, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
371 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
372 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
373 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
374 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x20, 0x62, 0x75, 0x74, 0x20,
375 0x69, 0x74, 0x27, 0x73, 0x20, 0x6a, 0x75, 0x73, 0x74, 0x20, 0x73, 0x68, 0x6f, 0x72,
376 0x74, 0x20, 0x65, 0x6e, 0x6f, 0x75, 0x67, 0x68
377 ]))
378 );
379 assert_eq!(
380 Memo::from_str(
381 "thiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \
382 iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \
383 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
384 veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeryyyyyyyyyyyyyyyyyyyyyyyyyy \
385 looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong \
386 meeeeeeeeeeeeeeeeeeemooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo \
387 but it's now a bit too long"
388 ),
389 Err(Error::TooLong(513))
390 );
391 }
392
393 #[test]
394 fn future_memo() {
395 let bytes = [0xFE; 512];
396 assert_eq!(
397 MemoBytes::from_bytes(&bytes).unwrap().try_into(),
398 Ok(Memo::Future(MemoBytes(Box::new(bytes))))
399 );
400 }
401
402 #[test]
403 fn arbitrary_memo() {
404 let bytes = [42; 511];
405 let memo = Memo::Arbitrary(Box::new(bytes));
406 let raw = memo.encode();
407 let encoded = raw.as_array();
408 assert_eq!(encoded[0], 0xFF);
409 assert_eq!(encoded[1..], bytes[..]);
410 assert_eq!(MemoBytes::from_bytes(encoded).unwrap().try_into(), Ok(memo));
411 }
412}