vest_lib/core/exec/serializer.rs
1//! Executable serializer traits.
2use crate::core::exec::output::*;
3use crate::core::spec::{
4 Consistency, GoodSerializer, MinMaxByteLen, SpecByteLen, SpecSerializer, StaticByteLen,
5 ValueByteLen,
6};
7use core::fmt;
8use core::marker::PhantomData;
9
10#[cfg(feature = "alloc")]
11use alloc::vec::Vec;
12
13use vstd::prelude::*;
14
15verus! {
16
17/// An executable serializer targeting `Output`.
18pub trait Serializer<Output, T> where
19 Output: OutputBuf,
20 Self: SpecByteLen<T = T::V> + SpecSerializer<SVal = T::V> + Consistency<Val = T::V>,
21 T: DeepView + ?Sized,
22 {
23 #[verifier::prophetic]
24 open spec fn exec_inv(&self) -> bool {
25 true
26 }
27
28 /// Serializes the value `v` into the output buffer `obuf` by (logically) appending the serialized bytes to the end of `obuf`.
29 /// This view has two main benefits:
30 /// 1. It matches the [specification](SpecSerializer) of the serializer closely, which simplifies the proofs;
31 /// 2. It is general enough to support both fixed-size (e.g., `&mut [u8]`) and growable (e.g., `Vec<u8>`) output buffers (see [`OutputBuf`]).
32 ///
33 /// ## Preconditions
34 ///
35 /// - The serializer's execution invariant holds (mainly used for [`super::fns::FnSerializer`], usually trivial for most combinators).
36 /// - The value `v` is [compliant](Consistency) with the format specification.
37 /// - The output buffer has enough space to hold the serialized value.
38 ///
39 /// ## Postconditions
40 ///
41 /// - The output buffer's contents are extended by the serialized value.
42 /// - The output buffer's remaining capacity is reduced by the serialized value's length.
43 /// - The output buffer's destination remains the same.
44 fn serialize_into(&self, v: &T, obuf: &mut Output)
45 requires
46 self.exec_inv(),
47 self.consistent(v.deep_view()),
48 old(obuf).fits(self.byte_len(v.deep_view())),
49 ensures
50 final(obuf)@ == old(obuf)@ + self.spec_serialize(v.deep_view()),
51 forall|n| old(obuf).fits(self.byte_len(v.deep_view()) + n) <==> final(obuf).fits(n),
52 old(obuf).same_destination(final(obuf)),
53 ;
54}
55
56/// Convenience entry points for the two standard output destinations.
57pub trait SerializerExt<T> where
58 Self: SpecByteLen<T = T::V> + SpecSerializer<SVal = T::V> + Consistency<Val = T::V>,
59 T: DeepView + ?Sized,
60 {
61 /// Serializes into an exactly-sized caller-provided slice without allocating.
62 fn serialize<'a>(&self, v: &T, obuf: &'a mut [u8]) where Self: Serializer<OutputSlice<'a>, T>
63 requires
64 self.exec_inv(),
65 self.consistent(v.deep_view()),
66 obuf@.len() == self.byte_len(v.deep_view()),
67 ensures
68 final(obuf)@ == self.spec_serialize(v.deep_view()),
69 {
70 let mut output = OutputSlice::new(obuf);
71 self.serialize_into(v, &mut output);
72 proof {
73 assert(output.fits(0));
74 assert(!output.fits(1));
75 assert(output.pos == output.obuf@.len());
76 }
77 }
78
79 /// Serializes by appending to a growable Vec (though the Vec can be preallocated with [`Prepare`]/[`ByteLen`]).
80 #[cfg(feature = "alloc")]
81 fn serialize_with_vec(&self, v: &T, obuf: &mut Vec<u8>) where Self: Serializer<Vec<u8>, T>
82 requires
83 self.exec_inv(),
84 self.consistent(v.deep_view()),
85 ensures
86 final(obuf)@ == old(obuf)@ + self.spec_serialize(v.deep_view()),
87 {
88 self.serialize_into(v, obuf);
89 }
90}
91
92impl<T: DeepView + ?Sized, S> SerializerExt<T> for S where
93 S: SpecByteLen<T = T::V> + SpecSerializer<SVal = T::V> + Consistency<Val = T::V>,
94 {
95
96}
97
98#[derive(Debug, Copy, Clone, PartialEq, Eq)]
99/// Why a value does not satisfy a format's specification.
100pub enum ComplianceErrorKind {
101 /// A stored or derived length does not match the corresponding value.
102 LengthInconsistent,
103 /// A tag is outside the domain accepted by the format.
104 InvalidTag,
105 /// A [`Refined`](crate::combinators::Refined) predicate rejected the value.
106 PredicateFailed,
107 /// A conditional combinator is disabled for this value.
108 CondRejected,
109 /// A recursive value exceeds the format's configured recursion limit.
110 RecursionLimitExceeded,
111 /// No branch of a choice accepts the value.
112 InvalidChoice,
113 /// A format-specific consistency error.
114 Custom(&'static str),
115}
116
117#[derive(Debug, Copy, Clone, PartialEq, Eq)]
118/// Top-level reason that preparation failed.
119pub enum PreSerializeErrorKind {
120 /// The exact serialized length cannot be represented by `usize`.
121 LengthTooLarge,
122 /// The value is not accepted by the format.
123 NotCompliant(ComplianceErrorKind),
124}
125
126#[derive(Debug, PartialEq, Eq)]
127/// Error returned by [`Prepare::prepare`].
128///
129/// `failed_format` identifies the innermost named format that attached
130/// context. With the `error-trace` feature, `format_stack` retains the complete
131/// format trace.
132pub struct PreSerializeError {
133 /// The underlying failure category.
134 pub kind: PreSerializeErrorKind,
135 /// The innermost named format that reported the failure, if available.
136 pub failed_format: Option<&'static str>,
137 #[cfg(feature = "error-trace")]
138 /// Nested format names collected while propagating the error.
139 pub format_stack: Vec<&'static str>,
140}
141
142impl Clone for PreSerializeError {
143 fn clone(&self) -> Self {
144 Self {
145 kind: self.kind,
146 failed_format: self.failed_format,
147 #[cfg(feature = "error-trace")]
148 format_stack: self.format_stack.clone(),
149 }
150 }
151}
152
153impl PreSerializeError {
154 /// Creates an error without attached format context.
155 pub fn new(kind: PreSerializeErrorKind) -> Self {
156 Self {
157 kind,
158 failed_format: None,
159 #[cfg(feature = "error-trace")]
160 format_stack: Vec::new(),
161 }
162 }
163
164 /// Creates a serialized-length overflow error.
165 pub fn length_too_large() -> Self {
166 Self::new(PreSerializeErrorKind::LengthTooLarge)
167 }
168
169 /// Creates a value-compliance error.
170 pub fn not_compliant(kind: ComplianceErrorKind) -> Self {
171 Self::new(PreSerializeErrorKind::NotCompliant(kind))
172 }
173
174 /// Creates a format-specific value-compliance error.
175 pub fn custom(msg: &'static str) -> Self {
176 Self::new(PreSerializeErrorKind::NotCompliant(ComplianceErrorKind::Custom(msg)))
177 }
178
179 /// Adds a named format to the error's propagation trace.
180 pub fn push_format(self, current_format: &'static str) -> Self {
181 let mut err = self;
182 if err.failed_format.is_none() {
183 err.failed_format = Some(current_format);
184 }
185 #[cfg(feature = "error-trace")]
186 {
187 err.format_stack.push(current_format);
188 }
189 err
190 }
191
192 /// Returns the innermost named format that attached context.
193 pub fn failed_format(&self) -> Option<&'static str> {
194 self.failed_format
195 }
196
197 /// Returns the collected format trace, or an empty slice without `error-trace`.
198 pub fn format_trace(&self) -> &[&'static str] {
199 #[cfg(feature = "error-trace")]
200 { self.format_stack.as_slice() }
201 #[cfg(not(feature = "error-trace"))]
202 { &[] }
203 }
204}
205
206/// Checks that a value can be serialized and computes its exact output length.
207///
208/// Call this before allocating an output or invoking [`SerializerExt::serialize`]
209/// on a value whose consistency has not already been established.
210pub trait Prepare<T>: SpecByteLen<T = T::V> + Consistency<Val = T::V> where T: DeepView + ?Sized {
211 /// Extra invariant required by the executable preparation implementation.
212 open spec fn exec_inv(&self) -> bool {
213 true
214 }
215
216 /// Validates `v` and returns its exact serialized length.
217 fn prepare(&self, v: &T) -> (checked: Result<usize, PreSerializeError>)
218 requires
219 self.exec_inv(),
220 ensures
221 checked matches Ok(len) ==> {
222 &&& self.consistent(v.deep_view())
223 &&& len == self.byte_len(v.deep_view())
224 },
225 ;
226}
227
228/// Computes the exact serialized length of a value already known to fit `usize`.
229///
230/// Unlike [`Prepare`], this operation does not check the format's consistency
231/// predicate. Use `Prepare::prepare` for untrusted or newly constructed values.
232pub trait ByteLen<T> where Self: SpecByteLen<T = T::V>, T: DeepView + ?Sized {
233 /// Extra invariant required by the executable length implementation.
234 open spec fn exec_inv(&self) -> bool {
235 true
236 }
237
238 /// Returns the exact number of bytes produced by serialization.
239 fn length(&self, v: &T) -> (len: usize)
240 requires
241 self.exec_inv(),
242 self.byte_len(v.deep_view()) <= usize::MAX,
243 ensures
244 len == self.byte_len(v.deep_view()),
245 ;
246}
247
248impl<T: ?Sized, S> Prepare<T> for &S where T: DeepView, S: Prepare<T> {
249 open spec fn exec_inv(&self) -> bool {
250 (*self).exec_inv()
251 }
252
253 fn prepare(&self, v: &T) -> (checked: Result<usize, PreSerializeError>) {
254 (*self).prepare(v)
255 }
256}
257
258impl<T: ?Sized, S> ByteLen<T> for &S where T: DeepView, S: ByteLen<T> {
259 open spec fn exec_inv(&self) -> bool {
260 (*self).exec_inv()
261 }
262
263 fn length(&self, v: &T) -> (len: usize) {
264 (*self).length(v)
265 }
266}
267
268impl<S: SpecSerializer> SpecSerializer for &S {
269 type SVal = S::SVal;
270
271 open spec fn spec_serialize(&self, v: Self::SVal) -> Seq<u8> {
272 (*self).spec_serialize(v)
273 }
274}
275
276impl<S: SpecByteLen> SpecByteLen for &S {
277 type T = S::T;
278
279 open spec fn byte_len(&self, v: Self::T) -> nat {
280 (*self).byte_len(v)
281 }
282}
283
284impl<S: StaticByteLen> StaticByteLen for &S {
285 open spec fn static_byte_len() -> nat {
286 S::static_byte_len()
287 }
288
289 proof fn lemma_static_len_matches_byte_len(&self, v: Self::T) {
290 (*self).lemma_static_len_matches_byte_len(v);
291 }
292}
293
294impl<S: ValueByteLen> ValueByteLen for &S {
295 open spec fn value_byte_len(v: Self::T) -> nat {
296 S::value_byte_len(v)
297 }
298
299 proof fn lemma_value_len_matches_byte_len(&self, v: Self::T) {
300 (*self).lemma_value_len_matches_byte_len(v);
301 }
302}
303
304impl<S: MinMaxByteLen> MinMaxByteLen for &S {
305 open spec fn min(&self) -> nat {
306 (*self).min()
307 }
308
309 open spec fn max(&self) -> nat {
310 (*self).max()
311 }
312
313 proof fn lemma_min_max_byte_len(&self, v: Self::T) {
314 (*self).lemma_min_max_byte_len(v);
315 }
316}
317
318impl<S: GoodSerializer> GoodSerializer for &S {
319 open spec fn serialize_inv(&self) -> bool {
320 (*self).serialize_inv()
321 }
322
323 proof fn lemma_serialize_len(&self, v: Self::SVal) {
324 (*self).lemma_serialize_len(v)
325 }
326}
327
328impl<S: Consistency> Consistency for &S {
329 type Val = S::Val;
330
331 open spec fn consistent(&self, v: Self::Val) -> bool {
332 (*self).consistent(v)
333 }
334}
335
336impl<Output, T, S> Serializer<Output, T> for &S where
337 Output: OutputBuf,
338 T: DeepView + ?Sized,
339 S: Serializer<Output, T>,
340 {
341 #[verifier::prophetic]
342 open spec fn exec_inv(&self) -> bool {
343 (*self).exec_inv()
344 }
345
346 fn serialize_into(&self, v: &T, obuf: &mut Output) {
347 (*self).serialize_into(v, obuf)
348 }
349}
350
351// pub trait ByteLen<Fmt> where
352// Self: DeepView,
353// Fmt: ValueByteLen<T = Self::V> + Consistency<Val = Self::V>,
354// {
355// fn byte_len_for(&self, binary_fmt: &Fmt) -> (len: usize)
356// requires
357// binary_fmt.consistent(self.deep_view()),
358// binary_fmt.byte_len(self.deep_view())
359// <= usize::MAX,
360// // Fmt::value_byte_len(self.deep_view()) <= usize::MAX,
361// ensures
362// binary_fmt.consistent(self.deep_view()),
363// len == binary_fmt.byte_len(
364// self.deep_view(),
365// ),
366// // len == Fmt::value_byte_len(self.deep_view()),
367// ;
368// }
369// impl ByteLen<U8> for u8 {
370// fn byte_len_for(&self, _binary_fmt: &U8) -> usize {
371// 1
372// }
373// }
374// impl ByteLen<U16Be> for u16 {
375// fn byte_len_for(&self, _binary_fmt: &U16Be) -> usize {
376// 2
377// }
378// }
379// impl ByteLen<U16Le> for u16 {
380// fn byte_len_for(&self, _binary_fmt: &U16Le) -> usize {
381// 2
382// }
383// }
384// impl ByteLen<Const<U8, u8>> for u8 {
385// fn byte_len_for(&self, _binary_fmt: &Const<U8, u8>) -> usize {
386// 1
387// }
388// }
389// impl<'x, const N: usize> ByteLen<Fixed<N>> for &'x [u8] {
390// fn byte_len_for(&self, _binary_fmt: &Fixed<N>) -> usize {
391// N
392// }
393// }
394// impl<'x, Len: AsLen> ByteLen<Varied<Len>> for &'x [u8] {
395// fn byte_len_for(&self, _binary_fmt: &Varied<Len>) -> usize {
396// self.len()
397// }
398// }
399// impl<FmtA, FmtB, A, B> ByteLen<Pair<FmtA, FmtB>> for (A, B) where
400// A: ByteLen<FmtA>,
401// B: ByteLen<FmtB>,
402// FmtA: ValueByteLen<T = A::V>,
403// FmtB: ValueByteLen<T = B::V>,
404// {
405// fn byte_len_for(&self, binary_fmt: &Pair<FmtA, FmtB>) -> usize {
406// self.0.byte_len_for(&binary_fmt.0) + self.1.byte_len_for(&binary_fmt.1)
407// }
408// }
409// // impl<FmtA, FmtB, A, B> ByteLen<Preceded<FmtA, A, FmtB>> for B where
410// // A: ByteLen<FmtA>,
411// // B: ByteLen<FmtB>,
412// // FmtA: ValueByteLen<T = A::V>,
413// // FmtB: ValueByteLen<T = B::V>,
414// // {
415// // fn byte_len_for(&self, binary_fmt: &Preceded<FmtA, A, FmtB>) -> usize {
416// // self.byte_len_for(&binary_fmt.b)
417// // }
418// // }
419// impl<FmtA, FmtB, A, B> ByteLen<Choice<FmtA, FmtB>> for Sum<A, B> where
420// A: ByteLen<FmtA>,
421// B: ByteLen<FmtB>,
422// FmtA: ValueByteLen<T = A::V>,
423// FmtB: ValueByteLen<T = B::V>,
424// {
425// fn byte_len_for(&self, binary_fmt: &Choice<FmtA, FmtB>) -> usize {
426// match self {
427// Sum::Inl(a) => a.byte_len_for(&binary_fmt.0),
428// Sum::Inr(b) => b.byte_len_for(&binary_fmt.1),
429// }
430// }
431// }
432// impl<Fmt, Predicate, T> ByteLen<Refined<Fmt, Predicate>> for T where
433// T: ByteLen<Fmt>,
434// Fmt: ValueByteLen<T = T::V>,
435// Predicate: Pred<T>,
436// {
437// fn byte_len_for(&self, binary_fmt: &Refined<Fmt, Predicate>) -> usize {
438// self.byte_len_for(&binary_fmt.0)
439// }
440// }
441// impl<Fmt, Map, T> ByteLen<Mapped<Fmt, Map>> for T where
442// T: DeepView<V = Map::Out>,
443// Fmt: ValueByteLen<T = Map::In>,
444// Map: for <'i>Mapper<&'i [u8], SOut = T>,
445// for <'i><Map as Mapper<&'i [u8]>>::SIn: ByteLen<Fmt>,
446// {
447// fn byte_len_for(&self, binary_fmt: &Mapped<Fmt, Map>) -> usize {
448// let mapped_in = Map::map_rev(self);
449// mapped_in.byte_len_for(&binary_fmt.inner)
450// }
451// }
452// #[verifier::allow_in_spec]
453// pub fn small_nonzero(value: &u16) -> bool
454// returns
455// *value != 0,
456// {
457// *value != 0
458// }
459// struct SmallNonZero;
460// impl SpecPred<u16> for SmallNonZero {
461// open spec fn apply(&self, value: u16) -> bool {
462// small_nonzero(&value)
463// }
464// }
465// impl Pred<u16> for SmallNonZero {
466// fn test(&self, value: &u16) -> (ok: bool) {
467// small_nonzero(value)
468// }
469// }
470// pub struct Triple {
471// pub a: u8,
472// pub b: u16,
473// pub c: u8,
474// }
475// impl DeepView for Triple {
476// type V = Self;
477// open spec fn deep_view(&self) -> Self::V {
478// *self
479// }
480// }
481// pub struct TripleMapper;
482// impl SpecMapper for TripleMapper {
483// type In = (u8, (u16, u8));
484// type Out = Triple;
485// open spec fn spec_map(i: Self::In) -> Self::Out {
486// Triple { a: i.0, b: i.1.0, c: i.1.1 }
487// }
488// open spec fn spec_map_rev(o: Self::Out) -> Self::In {
489// (o.a, (o.b, o.c))
490// }
491// }
492// impl Mapper<&[u8]> for TripleMapper {
493// type PIn = (u8, (u16, u8));
494// type POut = Triple;
495// type SIn = (u8, (u16, u8));
496// type SOut = Triple;
497// fn map(i: Self::PIn) -> Self::POut {
498// Triple { a: i.0, b: i.1.0, c: i.1.1 }
499// }
500// fn map_rev(o: &Self::SOut) -> Self::SIn {
501// (o.a, (o.b, o.c))
502// }
503// }
504// pub struct TrippleRefView {
505// pub a: u8,
506// pub b: u16,
507// pub c: Seq<u8>,
508// }
509// pub struct TripleRef<'i> {
510// pub a: u8,
511// pub b: u16,
512// pub c: &'i [u8],
513// }
514// impl DeepView for TripleRef<'_> {
515// type V = TrippleRefView;
516// open spec fn deep_view(&self) -> Self::V {
517// TrippleRefView { a: self.a, b: self.b, c: self.c.deep_view() }
518// }
519// }
520// pub struct TripleRefMapper;
521// impl SpecMapper for TripleRefMapper {
522// type In = (u8, (u16, Seq<u8>));
523// type Out = TrippleRefView;
524// open spec fn spec_map(i: Self::In) -> Self::Out {
525// TrippleRefView { a: i.0, b: i.1.0, c: i.1.1 }
526// }
527// open spec fn spec_map_rev(o: Self::Out) -> Self::In {
528// (o.a, (o.b, o.c))
529// }
530// }
531// impl<'i> Mapper<&'i [u8]> for TripleRefMapper {
532// type PIn = (u8, (u16, &'i [u8]));
533// type POut = TripleRef<'i>;
534// type SIn = (u8, (u16, &'i [u8]));
535// type SOut = TripleRef<'i>;
536// fn map(i: Self::PIn) -> Self::POut {
537// TripleRef { a: i.0, b: i.1.0, c: i.1.1 }
538// }
539// fn map_rev(o: &Self::SOut) -> Self::SIn {
540// (o.a, (o.b, o.c))
541// }
542// }
543// fn test_fmt_len() {
544// // let x = (0u8, (2u16, 4u8));
545// // let my_fmt = Pair(U8, Pair(Refined(U16Le, SmallNonZero), U8));
546// // let x = Triple { a: 0u8, b: 2u16, c: 4u8 };
547// // let my_fmt = Mapped {
548// // inner: Pair(U8, Pair(Refined(U16Le, SmallNonZero), U8)),
549// // mapper: TripleMapper,
550// // };
551// let arr = [1u8, 0u8, 2u8, 4u8];
552// let x = TripleRef { a: 0u8, b: 2u16, c: &arr };
553// let my_fmt = Mapped {
554// inner: Pair(
555// Const(U8, 0),
556// Pair(Refined(U16Le, SmallNonZero), Fixed::<4>),
557// ),
558// mapper: TripleRefMapper,
559// };
560// let len = x.byte_len_for(&my_fmt);
561// assert(len == 1 + 2 + 4);
562// }
563// pub trait ByteLen<Fmt> where Self: DeepView, Fmt: ValueByteLen<T = Self::V>, {
564// fn length(&self) -> (len: usize)
565// requires
566// Fmt::value_byte_len(self.deep_view()) <= usize::MAX,
567// ensures
568// len == Fmt::value_byte_len(self.deep_view()),
569// ;
570// }
571// use crate::combinators::{U8, U16Le, U16Be, Pair};
572// impl ByteLen<U8> for u8 {
573// fn length(&self) -> usize {
574// 1
575// }
576// }
577// impl ByteLen<U16Be> for u16 {
578// fn length(&self) -> usize {
579// 2
580// }
581// }
582// impl ByteLen<U16Le> for u16 {
583// fn length(&self) -> usize {
584// 2
585// }
586// }
587// impl<FmtA, FmtB, A, B> ByteLen<Pair<FmtA, FmtB>> for (A, B) where
588// A: ByteLen<FmtA>,
589// B: ByteLen<FmtB>,
590// FmtA: ValueByteLen<T = A::V>,
591// FmtB: ValueByteLen<T = B::V>,
592// {
593// fn length(&self) -> usize {
594// self.0.length() + self.1.length()
595// }
596// }
597// fn test_fmt_len() {
598// let x = (0u8, 0u16);
599// let len = <_ as ByteLen<Pair<U8, U16Le>>>::length(&x);
600// assert(len == 3);
601// }
602} // verus!
603impl fmt::Display for ComplianceErrorKind {
604 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
605 match self {
606 ComplianceErrorKind::LengthInconsistent => {
607 f.write_str("value length does not match the format's declared length")
608 }
609 ComplianceErrorKind::InvalidTag => {
610 f.write_str("value does not match the required tag or discriminant")
611 }
612 ComplianceErrorKind::PredicateFailed => {
613 f.write_str("value failed a refinement predicate")
614 }
615 ComplianceErrorKind::CondRejected => {
616 f.write_str("conditional format rejected this value")
617 }
618 ComplianceErrorKind::RecursionLimitExceeded => f.write_str("recursion limit exceeded"),
619 ComplianceErrorKind::InvalidChoice => {
620 f.write_str("value does not match any choice branch")
621 }
622 ComplianceErrorKind::Custom(s) => f.write_str(s),
623 }
624 }
625}
626
627impl fmt::Display for PreSerializeErrorKind {
628 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
629 match self {
630 PreSerializeErrorKind::LengthTooLarge => {
631 f.write_str("computed encoded length exceeds usize::MAX")
632 }
633 PreSerializeErrorKind::NotCompliant(kind) => write!(f, "{}", kind),
634 }
635 }
636}
637
638impl fmt::Display for PreSerializeError {
639 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
640 let format_trace = self.format_trace();
641 if !format_trace.is_empty() {
642 write!(f, "{} while preparing format stack ", self.kind)?;
643 for (i, format_name) in format_trace.iter().rev().enumerate() {
644 if i > 0 {
645 f.write_str(" -> ")?;
646 }
647 write!(f, "`{}`", format_name)?;
648 }
649 Ok(())
650 } else {
651 match self.failed_format {
652 Some(current_format) => {
653 write!(
654 f,
655 "{} while preparing format `{}`",
656 self.kind, current_format
657 )
658 }
659 None => write!(f, "{}", self.kind),
660 }
661 }
662 }
663}
664
665#[cfg(feature = "std")]
666impl std::error::Error for PreSerializeError {}