1mod element;
6mod pack;
7mod subspace;
8mod versionstamp;
9
10use std::borrow::Cow;
11use std::fmt::{self, Display};
12use std::io;
13use std::ops::Deref;
14use std::result;
15
16#[cfg(feature = "uuid")]
17pub use uuid::Uuid;
18
19pub use element::Element;
20pub use pack::{TuplePack, TupleUnpack, VersionstampOffset};
21pub use subspace::Subspace;
22pub use versionstamp::Versionstamp;
23
24const NIL: u8 = 0x00;
25const BYTES: u8 = 0x01;
26const STRING: u8 = 0x02;
27const NESTED: u8 = 0x05;
28const NEGINTSTART: u8 = 0x0b;
29const INTZERO: u8 = 0x14;
30const POSINTEND: u8 = 0x1d;
31const FLOAT: u8 = 0x20;
32const DOUBLE: u8 = 0x21;
33const FALSE: u8 = 0x26;
34const TRUE: u8 = 0x27;
35#[cfg(feature = "uuid")]
36const UUID: u8 = 0x30;
37const VERSIONSTAMP: u8 = 0x33;
40
41const ESCAPE: u8 = 0xff;
42
43#[derive(Copy, Clone)]
45pub struct TupleDepth(usize);
46
47impl TupleDepth {
48 fn new() -> Self {
49 TupleDepth(0)
50 }
51
52 pub fn increment(self) -> Self {
54 TupleDepth(self.0 + 1)
55 }
56
57 pub fn depth(self) -> usize {
59 self.0
60 }
61}
62
63#[derive(Debug)]
65pub enum PackError {
66 Message(Box<str>),
67 IoError(io::Error),
68 TrailingBytes,
69 MissingBytes,
70 BadStringFormat,
71 BadCode {
72 found: u8,
73 expected: Option<u8>,
74 },
75 BadPrefix,
76 #[cfg(feature = "uuid")]
77 BadUuid,
78 UnsupportedIntLength,
79}
80
81impl From<io::Error> for PackError {
82 fn from(err: io::Error) -> Self {
83 PackError::IoError(err)
84 }
85}
86
87impl Display for PackError {
88 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89 match self {
90 PackError::Message(s) => s.fmt(f),
91 PackError::IoError(err) => err.fmt(f),
92 PackError::TrailingBytes => write!(f, "trailing bytes"),
93 PackError::MissingBytes => write!(f, "missing bytes"),
94 PackError::BadStringFormat => write!(f, "not an utf8 string"),
95 PackError::BadCode { found, .. } => write!(f, "bad code, found {}", found),
96 PackError::BadPrefix => write!(f, "bad prefix"),
97 #[cfg(feature = "uuid")]
98 PackError::BadUuid => write!(f, "bad uuid"),
99 PackError::UnsupportedIntLength => write!(f, "integer length was to large"),
100 }
101 }
102}
103
104impl std::error::Error for PackError {}
105
106pub type PackResult<T> = result::Result<T, PackError>;
108
109#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
113pub struct Bytes<'a>(pub Cow<'a, [u8]>);
114
115impl fmt::Debug for Bytes<'_> {
116 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
117 fmt::Display::fmt(self, f)
118 }
119}
120
121impl fmt::Display for Bytes<'_> {
122 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
123 write!(fmt, "b\"")?;
124 for &byte in self.0.iter() {
125 if byte == b'\\' {
126 write!(fmt, r"\\")?;
127 } else if byte.is_ascii_alphanumeric() {
128 write!(fmt, "{}", byte as char)?;
129 } else {
130 write!(fmt, "\\x{:02x}", byte)?;
131 }
132 }
133 write!(fmt, "\"")
134 }
135}
136
137impl Bytes<'_> {
138 pub fn into_owned(self) -> Vec<u8> {
139 self.0.into_owned()
140 }
141}
142
143impl Deref for Bytes<'_> {
144 type Target = [u8];
145 fn deref(&self) -> &Self::Target {
146 &self.0
147 }
148}
149impl AsRef<[u8]> for Bytes<'_> {
150 fn as_ref(&self) -> &[u8] {
151 &self.0
152 }
153}
154
155impl<'a> From<&'a [u8]> for Bytes<'a> {
156 fn from(bytes: &'a [u8]) -> Self {
157 Self(Cow::Borrowed(bytes))
158 }
159}
160impl From<Vec<u8>> for Bytes<'static> {
161 fn from(vec: Vec<u8>) -> Self {
162 Self(Cow::Owned(vec))
163 }
164}
165
166impl<'a> From<&'a str> for Bytes<'a> {
167 fn from(s: &'a str) -> Self {
168 s.as_bytes().into()
169 }
170}
171impl From<String> for Bytes<'static> {
172 fn from(vec: String) -> Self {
173 vec.into_bytes().into()
174 }
175}
176
177pub fn pack<T: TuplePack>(v: &T) -> Vec<u8> {
183 v.pack_to_vec()
184}
185
186pub fn pack_with_versionstamp<T: TuplePack>(v: &T) -> Vec<u8> {
192 v.pack_to_vec_with_versionstamp()
193}
194
195pub fn pack_into<T: TuplePack>(v: &T, output: &mut Vec<u8>) -> VersionstampOffset {
201 v.pack_into_vec(output)
202}
203
204pub fn pack_into_with_versionstamp<T: TuplePack>(v: &T, output: &mut Vec<u8>) {
210 let offset = v.pack_into_vec_with_versionstamp(output);
211 if let VersionstampOffset::MultipleIncomplete = offset {
212 panic!("pack_into_with_versionstamp does not allow multiple versionstamps");
213 }
214}
215
216pub fn unpack<'de, T: TupleUnpack<'de>>(input: &'de [u8]) -> PackResult<T> {
218 T::unpack_root(input)
219}
220
221#[cfg(test)]
222mod tests {
223 use super::*;
224
225 const NIL_VAL: Option<()> = None;
226
227 fn test_serde<'de, T>(val: T, buf: &'de [u8])
228 where
229 T: TuplePack + TupleUnpack<'de> + fmt::Debug + PartialEq,
230 {
231 assert_eq!(Bytes::from(pack(&val)), Bytes::from(buf));
232 assert_eq!(unpack::<'de, T>(buf).unwrap(), val);
233 }
234
235 #[test]
236 fn test_spec() {
237 test_serde(NIL_VAL, &[NIL]);
238 test_serde((NIL_VAL,), &[NIL]);
239 test_serde(((NIL_VAL,),), &[NESTED, NIL, ESCAPE, NIL]);
240 test_serde("FÔO\x00bar".to_owned(), b"\x02F\xc3\x94O\x00\xffbar\x00");
242 test_serde(
243 (("foo\x00bar".to_owned(), NIL_VAL, ()),),
244 b"\x05\x02foo\x00\xffbar\x00\x00\xff\x05\x00\x00",
245 );
246 test_serde(-1, b"\x13\xfe");
247 test_serde(-5551212, b"\x11\xabK\x93");
248 test_serde(-42f32, b"\x20\x3d\xd7\xff\xff");
249 }
250
251 #[test]
252 fn test_simple() {
253 test_serde(false, &[FALSE]);
255 test_serde(true, &[TRUE]);
256
257 test_serde(0i64, &[INTZERO]);
259 test_serde(1i64, &[0x15, 1]);
260 test_serde(-1i64, &[0x13, 254]);
261 test_serde(100i64, &[21, 100]);
262
263 test_serde(10000i32, &[22, 39, 16]);
264 test_serde(-100i16, &[19, 155]);
265 test_serde(-10000i64, &[18, 216, 239]);
266 test_serde(-1000000i64, &[17, 240, 189, 191]);
267
268 test_serde(255u16, &[0x15, 255]);
270 test_serde(256i32, &[0x16, 1, 0]);
271 test_serde(-255i16, &[0x13, 0]);
272 test_serde(-256i64, &[0x12, 254, 255]);
273
274 test_serde(
276 Versionstamp::complete(*b"\xaa\xbb\xcc\xdd\xee\xff\x00\x01\x02\x03", 0),
277 b"\x33\xaa\xbb\xcc\xdd\xee\xff\x00\x01\x02\x03\x00\x00",
278 );
279 test_serde(
280 Versionstamp::complete(*b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a", 657),
281 b"\x33\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x02\x91",
282 );
283
284 test_serde(0, b"\x14");
285 test_serde(1, b"\x15\x01");
286 test_serde(-1, b"\x13\xfe");
287 test_serde(255, b"\x15\xff");
288 test_serde(-255, b"\x13\x00");
289 test_serde(256, b"\x16\x01\x00");
290 test_serde(-256, b"\x12\xfe\xff");
291 test_serde(65536, b"\x17\x01\x00\x00");
292 test_serde(-65536, b"\x11\xfe\xff\xff");
293 test_serde(i64::MAX, b"\x1C\x7f\xff\xff\xff\xff\xff\xff\xff");
294 test_serde(i64::MAX as u64 + 1, b"\x1C\x80\x00\x00\x00\x00\x00\x00\x00");
295 test_serde(u64::MAX, b"\x1C\xff\xff\xff\xff\xff\xff\xff\xff");
296 test_serde(
297 u128::MAX,
298 b"\x1D\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
299 );
300 test_serde(
301 u64::MAX as u128 + 1,
302 b"\x1D\x09\x01\x00\x00\x00\x00\x00\x00\x00\x00",
303 );
304 test_serde(
305 u64::MAX as i128 + 1,
306 b"\x1D\x09\x01\x00\x00\x00\x00\x00\x00\x00\x00",
307 );
308 test_serde(
309 i64::MIN as i128 + 1,
310 b"\x0C\x80\x00\x00\x00\x00\x00\x00\x00",
311 );
312 test_serde(
313 i64::MIN as i128 - 1,
314 b"\x0C\x7f\xff\xff\xff\xff\xff\xff\xfe",
315 );
316 test_serde(-(u64::MAX as i128), b"\x0C\x00\x00\x00\x00\x00\x00\x00\x00");
317 test_serde(
318 -(u64::MAX as i128) - 1,
319 b"\x0b\xf6\xfe\xff\xff\xff\xff\xff\xff\xff\xff",
320 );
321 test_serde(
322 -(u64::MAX as i128) - 2,
323 b"\x0b\xf6\xfe\xff\xff\xff\xff\xff\xff\xff\xfe",
324 );
325 test_serde(
326 (u64::MAX as i128) * -2,
327 b"\x0b\xf6\xfe\x00\x00\x00\x00\x00\x00\x00\x01",
328 );
329 test_serde(
330 (u64::MAX as i128) * 2,
331 b"\x1d\x09\x01\xff\xff\xff\xff\xff\xff\xff\xfe",
332 );
333 test_serde(-4294967295i64, b"\x10\x00\x00\x00\x00");
334 test_serde(i64::MIN + 2, b"\x0C\x80\x00\x00\x00\x00\x00\x00\x01");
335 test_serde(i64::MIN + 1, b"\x0C\x80\x00\x00\x00\x00\x00\x00\x00");
336 test_serde(i64::MIN, b"\x0C\x7f\xff\xff\xff\xff\xff\xff\xff");
337
338 test_serde(9252427359321063944i128, b"\x1c\x80g9\xa9np\x02\x08");
339 assert!(matches!(
340 unpack::<i64>(b"\x1c\x80g9\xa9np\x02\x08").unwrap_err(),
341 PackError::UnsupportedIntLength
342 ));
343
344 test_serde(
345 -9252427359321063944i128,
346 b"\x0c\x7f\x98\xc6V\x91\x8f\xfd\xf7",
347 );
348 assert!(matches!(
349 unpack::<i64>(b"\x0c\x7f\x98\xc6V\x91\x8f\xfd\xf7").unwrap_err(),
350 PackError::UnsupportedIntLength
351 ));
352
353 test_serde(u64::MAX as i128, b"\x1c\xff\xff\xff\xff\xff\xff\xff\xff");
354 assert!(matches!(
355 unpack::<i64>(b"\x1c\xff\xff\xff\xff\xff\xff\xff\xff").unwrap_err(),
356 PackError::UnsupportedIntLength
357 ));
358
359 test_serde(-(u64::MAX as i128), b"\x0c\x00\x00\x00\x00\x00\x00\x00\x00");
360 assert!(matches!(
361 unpack::<i64>(b"\x0c\x00\x00\x00\x00\x00\x00\x00\x00").unwrap_err(),
362 PackError::UnsupportedIntLength
363 ));
364
365 test_serde(
366 (i64::MAX as i128) + 1,
367 b"\x1c\x80\x00\x00\x00\x00\x00\x00\x00",
368 );
369 assert!(matches!(
370 unpack::<i64>(b"\x1c\x80\x00\x00\x00\x00\x00\x00\x00").unwrap_err(),
371 PackError::UnsupportedIntLength
372 ));
373
374 test_serde(
375 (i64::MIN as i128) - 1,
376 b"\x0c\x7f\xff\xff\xff\xff\xff\xff\xfe",
377 );
378 assert!(matches!(
379 unpack::<i64>(b"\x0c\x7f\xff\xff\xff\xff\xff\xff\xfe").unwrap_err(),
380 PackError::UnsupportedIntLength
381 ));
382 }
383
384 #[cfg(feature = "num-bigint")]
385 #[test]
386 fn test_bigint() {
387 use num_bigint::{BigInt, BigUint};
388 test_serde(BigInt::from(0i64), &[INTZERO]);
390 test_serde(BigUint::from(0u64), &[INTZERO]);
391 test_serde(BigInt::from(1i64), &[0x15, 1]);
392 test_serde(BigUint::from(1u64), &[0x15, 1]);
393 test_serde(BigInt::from(-1i64), &[0x13, 254]);
394 test_serde(BigInt::from(100i64), &[0x15, 100]);
395 test_serde(BigUint::from(100u64), &[0x15, 100]);
396
397 test_serde(BigInt::from(10000i32), &[0x16, 39, 16]);
398 test_serde(BigUint::from(10000u32), &[0x16, 39, 16]);
399 test_serde(BigInt::from(-100i16), &[19, 155]);
400 test_serde(BigInt::from(-10000i64), &[18, 216, 239]);
401 test_serde(BigInt::from(-1000000i64), &[17, 240, 189, 191]);
402
403 test_serde(BigInt::from(255u16), &[0x15, 255]);
405 test_serde(BigUint::from(255u16), &[0x15, 255]);
406 test_serde(BigInt::from(256i32), &[0x16, 1, 0]);
407 test_serde(BigInt::from(-255i16), &[0x13, 0]);
408 test_serde(BigInt::from(-256i64), &[0x12, 254, 255]);
409
410 test_serde(BigInt::from(0), b"\x14");
411 test_serde(BigUint::from(0u64), b"\x14");
412 test_serde(BigInt::from(1), b"\x15\x01");
413 test_serde(BigUint::from(1u64), b"\x15\x01");
414 test_serde(BigInt::from(-1), b"\x13\xfe");
415 test_serde(BigInt::from(255), b"\x15\xff");
416 test_serde(BigUint::from(255u64), b"\x15\xff");
417 test_serde(BigInt::from(-255), b"\x13\x00");
418 test_serde(BigInt::from(256), b"\x16\x01\x00");
419 test_serde(BigUint::from(256u64), b"\x16\x01\x00");
420 test_serde(BigInt::from(-256), b"\x12\xfe\xff");
421 test_serde(BigInt::from(65536), b"\x17\x01\x00\x00");
422 test_serde(BigUint::from(65536u64), b"\x17\x01\x00\x00");
423 test_serde(BigInt::from(-65536), b"\x11\xfe\xff\xff");
424 test_serde(
425 BigInt::from(i64::MAX),
426 b"\x1C\x7f\xff\xff\xff\xff\xff\xff\xff",
427 );
428 test_serde(
429 BigUint::from(i64::MAX as u64),
430 b"\x1C\x7f\xff\xff\xff\xff\xff\xff\xff",
431 );
432 test_serde(
433 BigInt::from(i64::MAX as u64 + 1),
434 b"\x1C\x80\x00\x00\x00\x00\x00\x00\x00",
435 );
436 test_serde(
437 BigUint::from(i64::MAX as u64 + 1),
438 b"\x1C\x80\x00\x00\x00\x00\x00\x00\x00",
439 );
440 test_serde(
441 BigInt::from(u64::MAX),
442 b"\x1C\xff\xff\xff\xff\xff\xff\xff\xff",
443 );
444 test_serde(
445 BigUint::from(u64::MAX),
446 b"\x1C\xff\xff\xff\xff\xff\xff\xff\xff",
447 );
448 test_serde(
449 BigInt::from(u128::MAX),
450 b"\x1D\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
451 );
452 test_serde(
453 BigUint::from(u128::MAX),
454 b"\x1D\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
455 );
456 test_serde(
457 BigInt::from(u64::MAX as u128 + 1),
458 b"\x1D\x09\x01\x00\x00\x00\x00\x00\x00\x00\x00",
459 );
460 test_serde(
461 BigUint::from(u64::MAX as u128 + 1),
462 b"\x1D\x09\x01\x00\x00\x00\x00\x00\x00\x00\x00",
463 );
464 test_serde(
465 BigInt::from(u64::MAX as i128 + 1),
466 b"\x1D\x09\x01\x00\x00\x00\x00\x00\x00\x00\x00",
467 );
468 test_serde(
469 BigUint::from(u64::MAX as u128 + 1),
470 b"\x1D\x09\x01\x00\x00\x00\x00\x00\x00\x00\x00",
471 );
472 test_serde(
473 BigInt::from(i64::MIN as i128 + 1),
474 b"\x0C\x80\x00\x00\x00\x00\x00\x00\x00",
475 );
476 test_serde(
477 BigInt::from(i64::MIN as i128 - 1),
478 b"\x0C\x7f\xff\xff\xff\xff\xff\xff\xfe",
479 );
480 test_serde(
481 BigInt::from(-(u64::MAX as i128)),
482 b"\x0C\x00\x00\x00\x00\x00\x00\x00\x00",
483 );
484 test_serde(
485 BigInt::from(-(u64::MAX as i128) - 1),
486 b"\x0b\xf6\xfe\xff\xff\xff\xff\xff\xff\xff\xff",
487 );
488 test_serde(
489 BigInt::from(-(u64::MAX as i128) - 2),
490 b"\x0b\xf6\xfe\xff\xff\xff\xff\xff\xff\xff\xfe",
491 );
492 test_serde(
493 BigInt::from((u64::MAX as i128) * -2),
494 b"\x0b\xf6\xfe\x00\x00\x00\x00\x00\x00\x00\x01",
495 );
496 test_serde(
497 BigInt::from((u64::MAX as i128) * 2),
498 b"\x1d\x09\x01\xff\xff\xff\xff\xff\xff\xff\xfe",
499 );
500 test_serde(BigInt::from(-4294967295i64), b"\x10\x00\x00\x00\x00");
501 test_serde(
502 BigInt::from(i64::MIN + 2),
503 b"\x0C\x80\x00\x00\x00\x00\x00\x00\x01",
504 );
505 test_serde(
506 BigInt::from(i64::MIN + 1),
507 b"\x0C\x80\x00\x00\x00\x00\x00\x00\x00",
508 );
509 test_serde(
510 BigInt::from(i64::MIN),
511 b"\x0C\x7f\xff\xff\xff\xff\xff\xff\xff",
512 );
513
514 test_serde(
515 Element::BigInt(9252427359321063944i128.into()),
516 b"\x1c\x80g9\xa9np\x02\x08",
517 );
518 test_serde(
519 Element::BigInt((-9252427359321063944i128).into()),
520 b"\x0c\x7f\x98\xc6V\x91\x8f\xfd\xf7",
521 );
522 }
523
524 #[cfg(feature = "uuid")]
525 #[test]
526 fn test_uuid() {
527 use uuid::Uuid;
528
529 test_serde(
530 Element::Uuid(
531 Uuid::from_slice(
532 b"\xba\xff\xff\xff\xff\x5e\xba\x11\x00\x00\x00\x00\x5c\xa1\xab\x1e",
533 )
534 .unwrap(),
535 ),
536 b"\x30\xba\xff\xff\xff\xff\x5e\xba\x11\x00\x00\x00\x00\x5c\xa1\xab\x1e",
537 );
538 }
539
540 #[test]
541 fn test_bindingtester() {
542 test_serde("NEW_TRANSACTION".to_string(), b"\x02NEW_TRANSACTION\x00");
543 test_serde(
544 vec!["NEW_TRANSACTION".to_string()],
545 b"\x02NEW_TRANSACTION\x00",
546 );
547 test_serde(
548 vec![
549 Element::String(Cow::Borrowed("PUSH")),
550 Element::Bytes(Bytes::from(
551 b"\x01tester_output\x00\x01results\x00\x14".as_ref(),
552 )),
553 ],
554 b"\x02PUSH\x00\x01\x01tester_output\x00\xff\x01results\x00\xff\x14\x00",
555 );
556 test_serde(
557 vec![Element::String(Cow::Borrowed("PUSH")), Element::Nil],
558 b"\x02PUSH\x00\x00",
559 );
560 test_serde(
561 vec![
562 Element::String(Cow::Borrowed("PUSH")),
563 Element::Tuple(vec![
564 Element::Nil,
565 Element::Float(3299069000000.0),
566 Element::Float(-0.000000000000000000000000000000000000011883096),
567 ]),
568 ],
569 b"\x02PUSH\x00\x05\x00\xff \xd4@\x07\xf5 \x7f~\x9a\xc2\x00",
570 );
571 test_serde(
572 vec![
573 Element::String(Cow::Borrowed("PUSH")),
574 Element::Int(-133525682914243904),
575 ],
576 b"\x02PUSH\x00\x0c\xfe%\x9f\x19M\x81J\xbf",
577 );
578
579 test_serde(
580 Element::Tuple(vec![Element::Nil, Element::Nil]),
581 b"\x00\x00",
582 );
583 test_serde(
584 Element::Tuple(vec![
585 Element::String(Cow::Borrowed("PUSH")),
586 Element::Tuple(vec![Element::Double(-8.251343508909708e-15)]),
587 ]),
588 b"\x02PUSH\x00\x05!B\xfdkl\x9f\xcc\x8eK\x00",
589 );
590 }
591
592 #[test]
593 fn test_element() {
594 test_serde(Element::Bool(true), &[TRUE]);
595 test_serde(Element::Bool(false), &[FALSE]);
596 test_serde(Element::Int(-1), &[0x13, 254]);
597 test_serde(
598 Element::Versionstamp(Versionstamp::complete(
599 *b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a",
600 657,
601 )),
602 b"\x33\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x02\x91",
603 );
604 test_serde(
605 (Element::Versionstamp(Versionstamp::complete(
606 *b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a",
607 657,
608 )),),
609 b"\x33\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x02\x91",
610 );
611 test_serde(
612 (Element::Versionstamp(Versionstamp::complete(
613 *b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a",
614 657,
615 )),),
616 b"\x33\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x02\x91",
617 );
618 test_serde(
619 vec![Element::Bool(true), Element::Bool(false)],
620 &[TRUE, FALSE],
621 );
622 test_serde(
623 vec![Element::Tuple(vec![
624 Element::Bool(true),
625 Element::Bool(false),
626 ])],
627 &[NESTED, TRUE, FALSE, NIL],
628 );
629 test_serde(Vec::<Element>::new(), &[]);
630 test_serde(Element::Tuple(vec![]), &[]);
631 }
632
633 #[test]
634 fn test_verstionstamp() {
635 assert_eq!(
636 Bytes::from(pack(&("foo", Versionstamp::incomplete(0)))),
637 Bytes::from(&b"\x02foo\x00\x33\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00"[..])
638 );
639 assert_eq!(
640 Bytes::from(pack_with_versionstamp(&(
641 "foo",
642 Versionstamp::incomplete(0)
643 ))),
644 Bytes::from(
645 &b"\x02foo\x00\x33\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x06\x00\x00\x00"
646 [..]
647 )
648 );
649 }
650}