Skip to main content

midnight_serialize/
util.rs

1// This file is part of midnight-ledger.
2// Copyright (C) Midnight Foundation
3// SPDX-License-Identifier: Apache-2.0
4// Licensed under the Apache License, Version 2.0 (the "License");
5// You may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7// http://www.apache.org/licenses/LICENSE-2.0
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14use crate::{Deserializable, Serializable, Tagged};
15#[cfg(feature = "proptest")]
16use proptest::strategy::ValueTree;
17#[cfg(feature = "proptest")]
18use proptest::{
19    strategy::{NewTree, Strategy},
20    test_runner::TestRunner,
21};
22#[cfg(feature = "proptest")]
23use rand::Rng;
24#[cfg(feature = "proptest")]
25use rand::distributions::{Distribution, Standard};
26#[cfg(feature = "proptest")]
27use std::fmt::Debug;
28use std::io::{BufWriter, Read};
29#[cfg(feature = "proptest")]
30use std::marker::PhantomData;
31
32pub trait VecExt {
33    fn with_bounded_capacity(n: usize) -> Self;
34}
35
36impl<T> VecExt for Vec<T> {
37    fn with_bounded_capacity(n: usize) -> Self {
38        const MEMORY_LIMIT: usize = 1 << 25; // 32 MiB
39        let alloc_limit = MEMORY_LIMIT.checked_div(std::mem::size_of::<T>()).unwrap_or(n);
40        Self::with_capacity(usize::min(alloc_limit, n))
41    }
42}
43
44pub trait ReadExt: Read {
45    fn read_exact_to_vec(&mut self, n: usize) -> std::io::Result<Vec<u8>> {
46        const CHUNK_SIZE: usize = 4096;
47        let mut res = Vec::with_capacity(CHUNK_SIZE);
48        let mut len = 0;
49        while n > len {
50            let new_len = usize::min(n, len + CHUNK_SIZE);
51            res.resize(new_len, 0);
52            self.read_exact(&mut res[len..])?;
53            len = new_len;
54        }
55        Ok(res)
56    }
57}
58
59impl<R: Read> ReadExt for R {}
60
61impl Serializable for () {
62    fn serialize(&self, _writer: &mut impl std::io::Write) -> std::io::Result<()> {
63        Ok(())
64    }
65    fn serialized_size(&self) -> usize {
66        0
67    }
68}
69
70impl Deserializable for () {
71    fn deserialize(_reader: &mut impl Read, _recursion_depth: u32) -> std::io::Result<Self> {
72        Ok(())
73    }
74}
75
76impl Tagged for () {
77    fn tag() -> std::borrow::Cow<'static, str> {
78        std::borrow::Cow::Borrowed("()")
79    }
80    fn tag_unique_factor() -> String {
81        "()".into()
82    }
83}
84
85impl Serializable for bool {
86    fn serialize(&self, writer: &mut impl std::io::Write) -> std::io::Result<()> {
87        writer.write_all(&[*self as u8])
88    }
89    fn serialized_size(&self) -> usize {
90        1
91    }
92}
93
94impl Deserializable for bool {
95    fn deserialize(reader: &mut impl Read, _recursion_depth: u32) -> std::io::Result<Self> {
96        let mut buf = [0u8];
97        reader.read_exact(&mut buf[..])?;
98        match buf[0] {
99            0 => Ok(false),
100            1 => Ok(true),
101            v => Err(std::io::Error::new(
102                std::io::ErrorKind::InvalidData,
103                format!("cannot deserialize {v} as bool"),
104            )),
105        }
106    }
107}
108
109impl Tagged for bool {
110    fn tag() -> std::borrow::Cow<'static, str> {
111        std::borrow::Cow::Borrowed("bool")
112    }
113    fn tag_unique_factor() -> String {
114        "bool".into()
115    }
116}
117
118macro_rules! via_le_bytes {
119    ($ty:ty, $len:expr_2021) => {
120        impl Serializable for $ty {
121            fn serialize(&self, writer: &mut impl std::io::Write) -> std::io::Result<()> {
122                writer.write_all(&self.to_le_bytes()[..])
123            }
124            fn serialized_size(&self) -> usize {
125                $len
126            }
127        }
128
129        impl Deserializable for $ty {
130            fn deserialize(reader: &mut impl Read, _recursion_depth: u32) -> std::io::Result<Self> {
131                let mut buf = [0u8; $len];
132                reader.read_exact(&mut buf[..])?;
133                Ok(<$ty>::from_le_bytes(buf))
134            }
135        }
136
137        impl Tagged for $ty {
138            fn tag() -> std::borrow::Cow<'static, str> {
139                std::borrow::Cow::Borrowed(stringify!($ty))
140            }
141            fn tag_unique_factor() -> String {
142                stringify!($ty).into()
143            }
144        }
145    };
146}
147
148macro_rules! via_scale {
149    ($ty:ty, $n:expr_2021) => {
150        impl Serializable for $ty {
151            fn serialize(&self, writer: &mut impl std::io::Write) -> std::io::Result<()> {
152                ScaleBigInt::from(*self).serialize(writer)
153            }
154            fn serialized_size(&self) -> usize {
155                ScaleBigInt::from(*self).serialized_size()
156            }
157        }
158
159        impl Deserializable for $ty {
160            fn deserialize(reader: &mut impl Read, recursion_depth: u32) -> std::io::Result<Self> {
161                <$ty>::try_from(ScaleBigInt::deserialize(reader, recursion_depth)?)
162            }
163        }
164
165        impl From<$ty> for ScaleBigInt {
166            fn from(val: $ty) -> ScaleBigInt {
167                let mut res = ScaleBigInt([0u8; SCALE_MAX_BYTES]);
168                let le_bytes = val.to_le_bytes();
169                res.0[..$n].copy_from_slice(&le_bytes[..]);
170                res
171            }
172        }
173
174        impl TryFrom<ScaleBigInt> for $ty {
175            type Error = std::io::Error;
176            fn try_from(val: ScaleBigInt) -> std::io::Result<$ty> {
177                if val.0[$n..].iter().any(|b| *b != 0) {
178                    return Err(std::io::Error::new(
179                        std::io::ErrorKind::InvalidData,
180                        concat!("out of range for ", stringify!($ty)),
181                    ));
182                }
183                Ok(<$ty>::from_le_bytes(
184                    val.0[..$n]
185                        .try_into()
186                        .expect("slice of known size must coerce to array"),
187                ))
188            }
189        }
190
191        impl Tagged for $ty {
192            fn tag() -> std::borrow::Cow<'static, str> {
193                std::borrow::Cow::Borrowed(stringify!($ty))
194            }
195            fn tag_unique_factor() -> String {
196                stringify!($ty).into()
197            }
198        }
199    };
200}
201
202via_le_bytes!(u8, 1);
203via_le_bytes!(u16, 2);
204via_le_bytes!(i8, 1);
205via_le_bytes!(i16, 2);
206via_le_bytes!(i32, 4);
207via_le_bytes!(i64, 8);
208via_le_bytes!(i128, 16);
209via_scale!(u32, 4);
210via_scale!(u64, 8);
211via_scale!(u128, 16);
212
213const SCALE_MAX_BYTES: usize = 67;
214pub struct ScaleBigInt(pub [u8; SCALE_MAX_BYTES]);
215
216impl Default for ScaleBigInt {
217    fn default() -> Self {
218        ScaleBigInt([0u8; SCALE_MAX_BYTES])
219    }
220}
221
222const SCALE_ONE_BYTE_MARKER: u8 = 0b00;
223const SCALE_TWO_BYTE_MARKER: u8 = 0b01;
224const SCALE_FOUR_BYTE_MARKER: u8 = 0b10;
225const SCALE_N_BYTE_MARKER: u8 = 0b11;
226
227impl Serializable for ScaleBigInt {
228    fn serialize(&self, writer: &mut impl std::io::Write) -> std::io::Result<()> {
229        let top2bits = |b| (b & 0b1100_0000) >> 6;
230        let bot6bits = |b| (b & 0b0011_1111) << 2;
231        match self.serialized_size() {
232            1 => writer.write_all(&[bot6bits(self.0[0]) | SCALE_ONE_BYTE_MARKER]),
233            2 => {
234                let b0 = bot6bits(self.0[0]) | SCALE_TWO_BYTE_MARKER;
235                let b1 = top2bits(self.0[0]) | bot6bits(self.0[1]);
236                writer.write_all(&[b0, b1])
237            }
238            4 => {
239                let b0 = bot6bits(self.0[0]) | SCALE_FOUR_BYTE_MARKER;
240                let b1 = top2bits(self.0[0]) | bot6bits(self.0[1]);
241                let b2 = top2bits(self.0[1]) | bot6bits(self.0[2]);
242                let b3 = top2bits(self.0[2]) | bot6bits(self.0[3]);
243                writer.write_all(&[b0, b1, b2, b3])
244            }
245            n => {
246                writer.write_all(&[(n as u8 - 5) << 2 | SCALE_N_BYTE_MARKER])?;
247                writer.write_all(&self.0[..n - 1])
248            }
249        }
250    }
251    fn serialized_size(&self) -> usize {
252        let trailing_zeros = self.0.iter().rev().take_while(|x| **x == 0).count();
253        let occupied = SCALE_MAX_BYTES - trailing_zeros;
254        let can_squeeze = self.0[occupied.saturating_sub(1)] < 64;
255        match (occupied, can_squeeze) {
256            (0, _) | (1, true) => 1,
257            (1, false) | (2, true) => 2,
258            (2, false) | (3, _) | (4, true) => 4,
259            (n, _) => n + 1,
260        }
261    }
262}
263
264impl Deserializable for ScaleBigInt {
265    fn deserialize(reader: &mut impl Read, recursion_depth: u32) -> std::io::Result<Self> {
266        let first = u8::deserialize(reader, recursion_depth)?;
267        let mut res = ScaleBigInt([0u8; SCALE_MAX_BYTES]);
268        let top6bits = |b| (b & 0b1111_1100) >> 2;
269        let bot2bits = |b| (b & 0b0000_0011) << 6;
270        match first & 0b11 {
271            SCALE_ONE_BYTE_MARKER => res.0[0] = top6bits(first),
272            SCALE_TWO_BYTE_MARKER => {
273                let second = u8::deserialize(reader, recursion_depth)?;
274                if second == 0 {
275                    return Err(std::io::Error::new(
276                        std::io::ErrorKind::InvalidData,
277                        "non-canonical scale encoding",
278                    ));
279                }
280                res.0[0] = top6bits(first) | bot2bits(second);
281                res.0[1] = top6bits(second);
282            }
283            SCALE_FOUR_BYTE_MARKER => {
284                let second = u8::deserialize(reader, recursion_depth)?;
285                let third = u8::deserialize(reader, recursion_depth)?;
286                let fourth = u8::deserialize(reader, recursion_depth)?;
287                if third == 0 && fourth == 0 {
288                    return Err(std::io::Error::new(
289                        std::io::ErrorKind::InvalidData,
290                        "non-canonical scale encoding",
291                    ));
292                }
293                res.0[0] = top6bits(first) | bot2bits(second);
294                res.0[1] = top6bits(second) | bot2bits(third);
295                res.0[2] = top6bits(third) | bot2bits(fourth);
296                res.0[3] = top6bits(fourth);
297            }
298            SCALE_N_BYTE_MARKER => {
299                let n = top6bits(first) as usize + 4;
300                reader.read_exact(&mut res.0[..n])?;
301                // Trailing zeros imply this encoding isn't sufficiently compact.
302                // If n == 4, this integer should be *outside* the legal encoding for the 4-byte
303                // limit.
304                if res.0[n - 1] == 0 || (n == 4 && res.0[3] < 64) {
305                    return Err(std::io::Error::new(
306                        std::io::ErrorKind::InvalidData,
307                        "non-canonical scale encoding",
308                    ));
309                }
310            }
311            _ => unreachable!(),
312        }
313        Ok(res)
314    }
315}
316
317macro_rules! tuple_serializable {
318    (($a:tt, $aidx: tt)$(, ($as:tt, $asidx: tt))*) => {
319        impl<$a: Serializable,$($as: Serializable,)*> Serializable for ($a,$($as,)*) {
320            fn serialize(
321                &self,
322                writer: &mut impl std::io::Write,
323            ) -> std::io::Result<()> {
324                <$a as Serializable>::serialize(&(self.$aidx), writer)?;
325                $(<$as as Serializable>::serialize(&(self.$asidx), writer)?;)*
326                Ok(())
327            }
328
329            fn serialized_size(&self) -> usize {
330                <$a as Serializable>::serialized_size(&(self.$aidx)) $(+ <$as as Serializable>::serialized_size(&(self.$asidx)))*
331            }
332        }
333
334        impl<$a: Deserializable,$($as: Deserializable,)*> Deserializable for ($a,$($as,)*) {
335            fn deserialize(reader: &mut impl std::io::Read, mut recursion_depth: u32) -> std::io::Result<Self> {
336                <Self as Deserializable>::check_rec(&mut recursion_depth)?;
337                Ok((
338                <$a as Deserializable>::deserialize(reader, recursion_depth)?,
339                $(<$as as Deserializable>::deserialize(reader, recursion_depth)?,)*
340                ))
341            }
342        }
343
344        impl<$a: Tagged,$($as: Tagged,)*> Tagged for ($a, $($as,)*) {
345            fn tag() -> std::borrow::Cow<'static, str> {
346                let mut res = String::new();
347                res.push_str("(");
348                res.push_str(&$a::tag());
349                $(
350                    res.push_str(",");
351                    res.push_str(&$as::tag());
352                )*
353                res.push_str(")");
354                std::borrow::Cow::Owned(res)
355            }
356            fn tag_unique_factor() -> String {
357                let mut res = String::new();
358                res.push_str("(");
359                res.push_str(&$a::tag_unique_factor());
360                $(
361                    res.push_str(",");
362                    res.push_str(&$as::tag_unique_factor());
363                )*
364                res.push_str(")");
365                res
366            }
367        }
368    }
369}
370
371tuple_serializable!((A, 0));
372tuple_serializable!((A, 0), (B, 1));
373tuple_serializable!((A, 0), (B, 1), (C, 2));
374tuple_serializable!((A, 0), (B, 1), (C, 2), (D, 3));
375tuple_serializable!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4));
376tuple_serializable!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4), (F, 5));
377tuple_serializable!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4), (F, 5), (G, 6));
378tuple_serializable!(
379    (A, 0),
380    (B, 1),
381    (C, 2),
382    (D, 3),
383    (E, 4),
384    (F, 5),
385    (G, 6),
386    (H, 7)
387);
388tuple_serializable!(
389    (A, 0),
390    (B, 1),
391    (C, 2),
392    (D, 3),
393    (E, 4),
394    (F, 5),
395    (G, 6),
396    (H, 7),
397    (I, 8)
398);
399tuple_serializable!(
400    (A, 0),
401    (B, 1),
402    (C, 2),
403    (D, 3),
404    (E, 4),
405    (F, 5),
406    (G, 6),
407    (H, 7),
408    (I, 8),
409    (J, 9)
410);
411tuple_serializable!(
412    (A, 0),
413    (B, 1),
414    (C, 2),
415    (D, 3),
416    (E, 4),
417    (F, 5),
418    (G, 6),
419    (H, 7),
420    (I, 8),
421    (J, 9),
422    (K, 10)
423);
424tuple_serializable!(
425    (A, 0),
426    (B, 1),
427    (C, 2),
428    (D, 3),
429    (E, 4),
430    (F, 5),
431    (G, 6),
432    (H, 7),
433    (I, 8),
434    (J, 9),
435    (K, 10),
436    (L, 11)
437);
438tuple_serializable!(
439    (A, 0),
440    (B, 1),
441    (C, 2),
442    (D, 3),
443    (E, 4),
444    (F, 5),
445    (G, 6),
446    (H, 7),
447    (I, 8),
448    (J, 9),
449    (K, 10),
450    (L, 11),
451    (M, 12)
452);
453tuple_serializable!(
454    (A, 0),
455    (B, 1),
456    (C, 2),
457    (D, 3),
458    (E, 4),
459    (F, 5),
460    (G, 6),
461    (H, 7),
462    (I, 8),
463    (J, 9),
464    (K, 10),
465    (L, 11),
466    (M, 12),
467    (N, 13)
468);
469tuple_serializable!(
470    (A, 0),
471    (B, 1),
472    (C, 2),
473    (D, 3),
474    (E, 4),
475    (F, 5),
476    (G, 6),
477    (H, 7),
478    (I, 8),
479    (J, 9),
480    (K, 10),
481    (L, 11),
482    (M, 12),
483    (N, 13),
484    (O, 14)
485);
486tuple_serializable!(
487    (A, 0),
488    (B, 1),
489    (C, 2),
490    (D, 3),
491    (E, 4),
492    (F, 5),
493    (G, 6),
494    (H, 7),
495    (I, 8),
496    (J, 9),
497    (K, 10),
498    (L, 11),
499    (M, 12),
500    (N, 13),
501    (O, 14),
502    (P, 15)
503);
504
505impl Deserializable for String {
506    fn deserialize(reader: &mut impl Read, recursion_depth: u32) -> std::io::Result<Self> {
507        let vec = <Vec<u8>>::deserialize(reader, recursion_depth)?;
508        String::from_utf8(vec).map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
509    }
510}
511
512impl Tagged for String {
513    fn tag() -> std::borrow::Cow<'static, str> {
514        std::borrow::Cow::Borrowed("string")
515    }
516    fn tag_unique_factor() -> String {
517        "string".into()
518    }
519}
520
521impl Tagged for str {
522    fn tag() -> std::borrow::Cow<'static, str> {
523        std::borrow::Cow::Borrowed("string")
524    }
525    fn tag_unique_factor() -> String {
526        "string".into()
527    }
528}
529
530pub fn gen_static_serialize_file<T: Serializable + Tagged>(
531    value: &T,
532) -> Result<(), std::io::Error> {
533    let mut file = BufWriter::new(std::fs::File::create(format!("{}.bin", T::tag(),))?);
534    crate::tagged_serialize(&value, &mut file)
535}
536
537pub fn test_file_deserialize<T: Deserializable + Tagged>(
538    path: std::path::PathBuf,
539) -> Result<T, std::io::Error> {
540    let bytes = std::fs::read(path)?;
541    crate::tagged_deserialize(&mut bytes.as_slice())
542}
543
544#[cfg(feature = "proptest")]
545pub struct NoSearch<T>(T);
546
547#[cfg(feature = "proptest")]
548impl<T: Debug + Clone> ValueTree for NoSearch<T> {
549    type Value = T;
550
551    fn current(&self) -> T {
552        self.0.clone()
553    }
554
555    fn simplify(&mut self) -> bool {
556        false
557    }
558
559    fn complicate(&mut self) -> bool {
560        false
561    }
562}
563
564#[derive(Debug)]
565#[cfg(feature = "proptest")]
566pub struct NoStrategy<T>(pub PhantomData<T>);
567
568#[cfg(feature = "proptest")]
569impl<T: Debug + Clone> Strategy for NoStrategy<T>
570where
571    Standard: Distribution<T>,
572{
573    type Tree = NoSearch<T>;
574    type Value = T;
575
576    fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
577        Ok(NoSearch(runner.rng().r#gen()))
578    }
579}
580
581#[macro_export]
582macro_rules! tag_enforcement_test {
583    ($type:ident) => {
584        serialize::tag_enforcement_test!($type < >);
585    };
586    ($type:ident < $($targ:ty),* >) => {
587        #[cfg(test)]
588        ::pastey::paste! {
589            #[allow(non_snake_case)]
590            #[test]
591            fn [<tag_enforcement_test_ $type>]() {
592                let tag = <$type<$($targ),*> as serialize::Tagged>::tag();
593                println!("{tag}");
594                let unique_factor = <$type<$($targ),*> as serialize::Tagged>::tag_unique_factor();
595                let mut dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
596                dir.pop();
597                dir.push(".tag-decompositions");
598                ::std::fs::create_dir_all(&dir).unwrap();
599                let fpath = dir.join(tag.as_ref());
600                if ::std::fs::exists(&fpath).unwrap() {
601                    let read_factor = ::std::fs::read_to_string(&fpath).unwrap();
602                    assert_eq!(read_factor, unique_factor);
603                } else {
604                    ::std::fs::write(&fpath, unique_factor).unwrap();
605                }
606            }
607        }
608    };
609}
610
611#[macro_export]
612#[cfg(feature = "proptest")]
613macro_rules! randomised_tagged_serialization_test {
614    ($type:ident) => {
615        serialize::randomised_tagged_serialization_test!($type < >);
616    };
617    ($type:ident < $($targ:ty),* >) => {
618        #[cfg(test)]
619        ::pastey::paste! {
620            #[allow(non_snake_case)]
621            #[test]
622            fn [<proptest_deserialize_tagged_ $type>]() where $type<$($targ),*>: proptest::prelude::Arbitrary {
623                let mut runner = proptest::test_runner::TestRunner::default();
624
625                runner.run(&<$type<$($targ),*> as proptest::prelude::Arbitrary>::arbitrary(), |v| {
626                    let mut bytes: Vec<u8> = Vec::new();
627                    serialize::tagged_serialize(&v, &mut bytes).unwrap();
628                    let des_result: $type<$($targ),*> = serialize::tagged_deserialize(&mut bytes.as_slice()).unwrap();
629                    assert_eq!(des_result, v);
630
631                    Ok(())
632                }).unwrap();
633            }
634            serialize::randomised_serialization_test!($type<$($targ),*>);
635        }
636    }
637}
638
639#[macro_export]
640#[cfg(feature = "proptest")]
641macro_rules! randomised_serialization_test {
642    ($type:ident) => {
643        serialize::randomised_serialization_test!($type < >);
644    };
645    ($type:ident < $($targ:ty),* >) => {
646        #[cfg(test)]
647        ::pastey::paste! {
648            #[allow(non_snake_case)]
649            #[test]
650            fn [<proptest_deserialize_ $type>]() where $type<$($targ),*>: proptest::prelude::Arbitrary {
651                let mut runner = proptest::test_runner::TestRunner::default();
652
653                runner.run(&<$type<$($targ),*> as proptest::prelude::Arbitrary>::arbitrary(), |v| {
654                    let mut bytes: Vec<u8> = Vec::new();
655                    <$type<$($targ),*> as serialize::Serializable>::serialize(&v, &mut bytes).unwrap();
656                    let des_result: $type<$($targ),*> = <$type<$($targ),*> as serialize::Deserializable>::deserialize(&mut bytes.as_slice(), 0).unwrap();
657                    assert_eq!(des_result, v);
658
659                    Ok(())
660                }).unwrap();
661            }
662
663            #[allow(non_snake_case)]
664            #[test]
665            fn [<proptest_serialized_size_ $type>]() where $type<$($targ),*>: proptest::prelude::Arbitrary {
666                let mut runner = proptest::test_runner::TestRunner::default();
667
668                runner.run(&<$type<$($targ),*> as proptest::prelude::Arbitrary>::arbitrary(), |v| {
669                    let mut bytes: Vec<u8> = Vec::new();
670                    <$type<$($targ),*> as serialize::Serializable>::serialize(&v, &mut bytes).unwrap();
671                    assert_eq!(bytes.len(), <$type<$($targ),*> as serialize::Serializable>::serialized_size(&v));
672
673                    Ok(())
674                }).unwrap();
675            }
676
677            #[allow(non_snake_case)]
678            #[test]
679            fn [<proptest_random_data_deserialize_ $type>]() {
680                use rand::Rng;
681                let mut rng = rand::thread_rng();
682
683                for _ in 0..100 {
684                    let size: u8 = rng.r#gen();
685                    let mut bytes: Vec<u8> = Vec::new();
686                    for _i in 0..size {
687                        bytes.push(rng.r#gen())
688                    }
689                    let _ = <$type<$($targ),*> as serialize::Deserializable>::deserialize(&mut bytes.as_slice(), 0);
690                }
691            }
692        }
693    };
694}
695
696/// Produce a single arbitrary value without the ability to simplify or complicate
697#[macro_export]
698#[cfg(feature = "proptest")]
699macro_rules! simple_arbitrary {
700    ($type:ty) => {
701        impl Arbitrary for $type {
702            type Parameters = ();
703            type Strategy = NoStrategy<$type>;
704
705            fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
706                NoStrategy(PhantomData)
707            }
708        }
709    };
710}
711
712#[cfg(feature = "proptest")]
713#[allow(unused)]
714use crate as serialize;
715
716#[cfg(feature = "proptest")]
717randomised_serialization_test!(String);