Skip to main content

codas/
types.rs

1//! Built-in data types and their in-memory
2//! representations.
3//!
4//! # Unstable
5//!
6//! The APIs exposed by this module are _primarily_
7//! used for code generation and dynamic data manipulation;
8//! the exact APIs are subject to change, and may
9//! not be well-optimized.
10use core::convert::Infallible;
11
12use alloc::{boxed::Box, vec, vec::Vec};
13
14use crate::codec::{
15    CodecError, DataFormat, DataHeader, Decodable, Encodable, FieldReader, Format, ReadsDecodable,
16    UnexpectedDataFormatSnafu, WritesEncodable,
17};
18
19pub mod binary;
20pub mod cryptography;
21pub mod dynamic;
22pub mod list;
23pub mod map;
24pub mod number;
25mod text;
26pub use binary::Array;
27pub use dynamic::Unspecified;
28pub use text::*;
29
30/// Enumeration of available built in types.
31#[non_exhaustive]
32#[derive(Default, Debug, Clone, PartialEq)]
33pub enum Type {
34    /// Unspecified data.
35    #[default]
36    Unspecified,
37
38    /// Unsigned (positive) 8-bit number.
39    U8,
40    /// Unsigned (positive) 16-bit number.
41    U16,
42    /// Unsigned (positive) 32-bit number.
43    U32,
44    /// Unsigned (positive) 64-bit number.
45    U64,
46
47    /// Signed (positive or negative) 8-bit number.
48    I8,
49    /// Signed (positive or negative) 16-bit number.
50    I16,
51    /// Signed (positive or negative) 32-bit number.
52    I32,
53    /// Signed (positive or negative) 64-bit number.
54    I64,
55
56    /// 32-bit floating point (decimal) number.
57    F32,
58    /// 64-bit floating point (decimal) number.
59    F64,
60
61    /// Boolean (true or false).
62    Bool,
63
64    /// UTF-8 encoded text.
65    Text,
66
67    /// Fixed-size sequence of a fixed-size element type.
68    ///
69    /// Elements of the array _must_ have a fixed size
70    /// (i.e., a [`Format::Blob`] format).
71    Array(u16, Box<Type>),
72
73    /// Data with [`DataType`].
74    Data(DataType),
75
76    /// Data with [`Type`] that's _semantically_ a list.
77    List(Box<Type>),
78
79    /// A mapping between data of two types.
80    Map(Box<(Type, Type)>),
81}
82
83impl Type {
84    // Wire ordinals for built-in types.
85    // Built-in ordinals count down from 255; user-defined count up from 1.
86    pub(crate) const UNSPECIFIED_ORDINAL: u8 = 0;
87    pub(crate) const U8_ORDINAL: u8 = 255;
88    pub(crate) const U16_ORDINAL: u8 = 254;
89    pub(crate) const U32_ORDINAL: u8 = 253;
90    pub(crate) const U64_ORDINAL: u8 = 252;
91    pub(crate) const I8_ORDINAL: u8 = 251;
92    pub(crate) const I16_ORDINAL: u8 = 250;
93    pub(crate) const I32_ORDINAL: u8 = 249;
94    pub(crate) const I64_ORDINAL: u8 = 248;
95    pub(crate) const F32_ORDINAL: u8 = 247;
96    pub(crate) const F64_ORDINAL: u8 = 246;
97    pub(crate) const BOOL_ORDINAL: u8 = 245;
98    pub(crate) const TEXT_ORDINAL: u8 = 244;
99    pub(crate) const ARRAY_ORDINAL: u8 = 243;
100    pub(crate) const LIST_ORDINAL: u8 = 242;
101    pub(crate) const MAP_ORDINAL: u8 = 241;
102
103    /// Returns the wire ordinal for this type.
104    pub const fn ordinal(&self) -> u8 {
105        match self {
106            Type::Unspecified => Self::UNSPECIFIED_ORDINAL,
107            Type::U8 => Self::U8_ORDINAL,
108            Type::U16 => Self::U16_ORDINAL,
109            Type::U32 => Self::U32_ORDINAL,
110            Type::U64 => Self::U64_ORDINAL,
111            Type::I8 => Self::I8_ORDINAL,
112            Type::I16 => Self::I16_ORDINAL,
113            Type::I32 => Self::I32_ORDINAL,
114            Type::I64 => Self::I64_ORDINAL,
115            Type::F32 => Self::F32_ORDINAL,
116            Type::F64 => Self::F64_ORDINAL,
117            Type::Bool => Self::BOOL_ORDINAL,
118            Type::Text => Self::TEXT_ORDINAL,
119            Type::Array(..) => Self::ARRAY_ORDINAL,
120            Type::Data(data) => data.format.as_data_format().ordinal,
121            Type::List(_) => Self::LIST_ORDINAL,
122            Type::Map(_) => Self::MAP_ORDINAL,
123        }
124    }
125
126    /// Returns the type corresponding to `ordinal`.
127    ///
128    /// Iff ordinal does not correspond to a built-in-type,
129    /// `None` is returned.
130    ///
131    /// List and Map return placeholder inner types
132    /// ([`Type::Unspecified`]), and Array returns a
133    /// placeholder count of `0`, since the ordinal alone
134    /// doesn't describe them.
135    pub fn from_ordinal(ordinal: u8) -> Option<Self> {
136        match ordinal {
137            Self::UNSPECIFIED_ORDINAL => Some(Type::Unspecified),
138            Self::U8_ORDINAL => Some(Type::U8),
139            Self::U16_ORDINAL => Some(Type::U16),
140            Self::U32_ORDINAL => Some(Type::U32),
141            Self::U64_ORDINAL => Some(Type::U64),
142            Self::I8_ORDINAL => Some(Type::I8),
143            Self::I16_ORDINAL => Some(Type::I16),
144            Self::I32_ORDINAL => Some(Type::I32),
145            Self::I64_ORDINAL => Some(Type::I64),
146            Self::F32_ORDINAL => Some(Type::F32),
147            Self::F64_ORDINAL => Some(Type::F64),
148            Self::BOOL_ORDINAL => Some(Type::Bool),
149            Self::TEXT_ORDINAL => Some(Type::Text),
150            Self::ARRAY_ORDINAL => Some(Type::Array(0, Type::Unspecified.into())),
151            Self::LIST_ORDINAL => Some(Type::List(Type::Unspecified.into())),
152            Self::MAP_ORDINAL => Some(Type::Map((Type::Unspecified, Type::Unspecified).into())),
153            _ => None,
154        }
155    }
156
157    /// The type's encoding format.
158    pub const fn format(&self) -> Format {
159        match self {
160            Type::Unspecified => Format::Fluid,
161            Type::U8 => u8::FORMAT,
162            Type::U16 => u16::FORMAT,
163            Type::U32 => u32::FORMAT,
164            Type::U64 => u64::FORMAT,
165            Type::I8 => i8::FORMAT,
166            Type::I16 => i16::FORMAT,
167            Type::I32 => i32::FORMAT,
168            Type::I64 => i64::FORMAT,
169            Type::F32 => f32::FORMAT,
170            Type::F64 => f64::FORMAT,
171            Type::Bool => bool::FORMAT,
172            Type::Text => Text::FORMAT,
173            Type::Array(count, elem) => match elem.format() {
174                Format::Blob(size) => {
175                    let total = *count as u32 * size as u32;
176                    assert!(
177                        total <= u16::MAX as u32,
178                        "array size exceeds maximum blob size (u16::MAX)"
179                    );
180                    Format::Blob(total as u16)
181                }
182                _ => panic!("array elements must have a fixed size"),
183            },
184            Type::Data(data) => data.format,
185            Type::List(typing) => typing.format().as_sequence(),
186
187            // Maps are formatted as a list of keys
188            // followed by a list of values.
189            Type::Map(..) => DataFormat {
190                blob_size: 0,
191                data_fields: 2,
192                ordinal: 0,
193            }
194            .as_format(),
195        }
196    }
197
198    /// Returns the type with `name`.
199    ///
200    /// This function assumes `name` is in ASCII lowercase.
201    pub fn from_name(name: &str) -> Option<Self> {
202        match name {
203            "unspecified" => Some(Type::Unspecified),
204            "u8" => Some(Type::U8),
205            "u16" => Some(Type::U16),
206            "u32" => Some(Type::U32),
207            "u64" => Some(Type::U64),
208            "i8" => Some(Type::I8),
209            "i16" => Some(Type::I16),
210            "i32" => Some(Type::I32),
211            "i64" => Some(Type::I64),
212            "f32" => Some(Type::F32),
213            "f64" => Some(Type::F64),
214            "bool" => Some(Type::Bool),
215            "text" => Some(Type::Text),
216            _ => None,
217        }
218    }
219}
220
221/// In-memory representation of a coda.
222#[derive(Default, Debug, Clone, PartialEq)]
223pub struct Coda {
224    /// The coda's full name, including any
225    /// hierarchical components and separators.
226    pub global_name: Text,
227
228    /// The final component of [`Self::global_name`]
229    /// that does not describe a hierarchy.
230    pub local_name: Text,
231
232    pub docs: Option<Text>,
233
234    /// Data in ascending order by ordinal.
235    pub(crate) data: Vec<DataType>,
236}
237
238impl Coda {
239    /// Returns a new coda containing `data`.
240    pub fn new(global_name: Text, local_name: Text, docs: Option<Text>, data: &[DataType]) -> Self {
241        Self {
242            global_name,
243            local_name,
244            docs,
245            data: Vec::from(data),
246        }
247    }
248
249    /// Returns an iterator over all data types in the coda.
250    ///
251    /// The implicit [`crate::types::Unspecified`] data type
252    /// is _not_ included in the returned iterator.
253    pub fn iter(&self) -> impl Iterator<Item = &DataType> {
254        self.data.iter()
255    }
256
257    /// Returns the data type with `name`,
258    /// if it is known by the coda.
259    #[cfg(feature = "parse")]
260    pub(crate) fn type_from_name(&self, name: &str) -> Option<Type> {
261        for data in self.data.iter() {
262            if data.name.eq_ignore_ascii_case(name) {
263                return Some(Type::Data(data.clone()));
264            }
265        }
266
267        Type::from_name(name)
268    }
269}
270
271/// Data containing a structured set of [`DataField`]s.
272#[derive(Default, Debug, Clone, PartialEq)]
273pub struct DataType {
274    /// The name of the data type.
275    ///
276    /// TODO: We've been structuring names similar
277    /// to fully-qualified Rust type names (like `my::data::TypeName`).
278    /// We should standardize on a language-neutral naming
279    /// convention; perhaps HTTP-style URLs (like `/my/data/TypeName`)
280    /// so downstream tools have an easy way to map hierarchical
281    /// names back to native type names as appropriate.
282    pub name: Text,
283
284    /// Markdown-formatted documentation of the data type.
285    pub docs: Option<Text>,
286
287    /// Ordered set of [`Format::Blob`]
288    /// fields in the data type.
289    blob_fields: Vec<DataField>,
290
291    /// Ordered set of [`Format::Data`]
292    /// fields in the data type.
293    ///
294    /// These fields are always encoded, in
295    /// order, _after_ all [`Self::blob_fields`].
296    data_fields: Vec<DataField>,
297
298    /// The encoding format of data with this type.
299    format: Format,
300}
301
302impl DataType {
303    /// Returns a new fixed data type with
304    /// `name`, `ordinal`, `blob_fields`, and `data_fields`.
305    pub fn new(
306        name: Text,
307        docs: Option<Text>,
308        ordinal: u8,
309        blob_fields: &[DataField],
310        data_fields: &[DataField],
311    ) -> Self {
312        // Build a new encoding format for the data.
313        let mut format = Format::data(ordinal);
314
315        // Add blob fields to the format.
316        let mut i = 0;
317        while i < blob_fields.len() {
318            let field = &blob_fields[i];
319            format = format.with(field.typing.format());
320            i += 1;
321        }
322
323        // Add data fields to the format.
324        let mut i = 0;
325        while i < data_fields.len() {
326            let field = &data_fields[i];
327            format = format.with(field.typing.format());
328            i += 1;
329        }
330
331        Self {
332            name,
333            docs,
334            blob_fields: Vec::from(blob_fields),
335            data_fields: Vec::from(data_fields),
336            format,
337        }
338    }
339
340    /// Returns a new data type with a fluid format.
341    pub const fn new_fluid(name: Text, docs: Option<Text>) -> Self {
342        Self {
343            name,
344            docs,
345            blob_fields: vec![],
346            data_fields: vec![],
347            format: Format::Fluid,
348        }
349    }
350
351    /// Returns an iterator over all fields within the type.
352    pub fn iter(&self) -> impl Iterator<Item = &DataField> {
353        self.blob_fields.iter().chain(self.data_fields.iter())
354    }
355
356    /// Adds a new `field` to the type.
357    pub fn with(mut self, field: DataField) -> Self {
358        if matches!(self.format, Format::Fluid) {
359            todo!("it should be an error to add fields to a type defined as fluid")
360        }
361
362        let field_format = field.format();
363        self.format = self.format.with(field_format);
364        match field_format {
365            Format::Blob(..) => self.blob_fields.push(field),
366            Format::Data(..) | Format::Sequence(..) | Format::Fluid => self.data_fields.push(field),
367        };
368
369        self
370    }
371
372    /// Returns the type's encoding format.
373    pub const fn format(&self) -> &Format {
374        &self.format
375    }
376}
377
378/// A field in a [`DataType`].
379#[derive(Default, Clone, Debug, PartialEq)]
380pub struct DataField {
381    /// Name of the field.
382    pub name: Text,
383
384    /// Markdown-formatted documentation of the field.
385    pub docs: Option<Text>,
386
387    /// Type of the field.
388    pub typing: Type,
389
390    /// True if the field is semantically optional.
391    pub optional: bool,
392
393    /// True if the field is semantically flattened.
394    ///
395    /// This property has _no_ effect on the encoding,
396    /// decoding, or in-language representation of
397    /// a field; it's an informational marker that some
398    /// marshallers (like JSON) may use to enable
399    /// compatibility between coda-defined data and
400    /// legacy systems.
401    pub flattened: bool,
402}
403
404impl DataField {
405    /// Returns the encoding format of this field: a
406    /// [`Format::as_sequence`] its [`Self::typing`]
407    /// if optional, otherwise its typing.
408    fn format(&self) -> Format {
409        let format = self.typing.format();
410        if self.optional {
411            format.as_sequence()
412        } else {
413            format
414        }
415    }
416}
417
418/// A thing that _might_ contain data with a
419/// specific format `D`.
420///
421/// This trait is mainly intended for use with the
422/// enums auto-generated for [`Coda`]s
423pub trait TryAsFormat<D> {
424    /// Type of error returned when `self`
425    /// doesn't contain data of format `D`.
426    ///
427    /// This error should be the ordinal
428    /// identifier of the _actual_ data in `D`,
429    /// or [`Infallible`].
430    type Error;
431
432    /// Returns a `D`-formatted reference to the data.
433    fn try_as_format(&self) -> Result<&D, Self::Error>;
434}
435
436/// Every data format can be interpreted as itself.
437impl<T> TryAsFormat<T> for T {
438    type Error = Infallible;
439
440    fn try_as_format(&self) -> Result<&T, Self::Error> {
441        Ok(self)
442    }
443}
444
445// Codecs /////////////////////////////////////////////////
446
447impl Encodable for Type {
448    const FORMAT: Format = Format::Fluid;
449
450    fn encode(&self, writer: &mut (impl WritesEncodable + ?Sized)) -> Result<(), CodecError> {
451        match self {
452            Type::Array(count, elem) => {
453                writer.write_data(count)?;
454                writer.write_data(elem.as_ref())
455            }
456            Type::Data(typing) => writer.write_data(typing),
457            Type::List(typing) => writer.write_data(typing.as_ref()),
458            Type::Map(typing) => {
459                writer.write_data(&typing.as_ref().0)?;
460                writer.write_data(&typing.as_ref().1)?;
461                Ok(())
462            }
463
464            // Only array and data types contain additional encoded info.
465            _ => Ok(()),
466        }
467    }
468
469    fn encode_header(
470        &self,
471        writer: &mut (impl WritesEncodable + ?Sized),
472    ) -> Result<(), CodecError> {
473        let format = match self {
474            Type::Map(_) => Format::data(self.ordinal())
475                .with(Type::FORMAT)
476                .with(Type::FORMAT)
477                .as_data_format(),
478            Type::Data(..) | Type::List(_) => Format::data(self.ordinal())
479                .with(Type::FORMAT)
480                .as_data_format(),
481            Type::Array(..) => Format::data(self.ordinal())
482                .with(u16::FORMAT)
483                .with(Type::FORMAT)
484                .as_data_format(),
485            _ => Format::data(self.ordinal()).as_data_format(),
486        };
487
488        DataHeader { count: 1, format }.encode(writer)
489    }
490}
491
492impl Decodable for Type {
493    fn decode(
494        &mut self,
495        reader: &mut (impl ReadsDecodable + ?Sized),
496        header: Option<DataHeader>,
497    ) -> Result<(), CodecError> {
498        let header = header.ok_or_else(|| {
499            UnexpectedDataFormatSnafu {
500                expected: Self::FORMAT,
501                actual: None::<DataHeader>,
502            }
503            .build()
504        })?;
505
506        // Type is always encoded with count=1.
507        if header.count != 1 {
508            return UnexpectedDataFormatSnafu {
509                expected: Self::FORMAT,
510                actual: Some(header),
511            }
512            .fail();
513        }
514
515        match header.format.ordinal {
516            Self::ARRAY_ORDINAL => {
517                // Array: blob_size=2 (u16 count), data_fields=1 (element Type).
518                if header.format.blob_size != 2 || header.format.data_fields != 1 {
519                    return UnexpectedDataFormatSnafu {
520                        expected: Self::FORMAT,
521                        actual: Some(header),
522                    }
523                    .fail();
524                }
525                let mut count = 0u16;
526                reader.read_data_into(&mut count)?;
527                let mut elem = Type::default();
528                reader.read_data_into(&mut elem)?;
529                *self = Type::Array(count, elem.into());
530            }
531            Self::LIST_ORDINAL => {
532                // List: blob_size=0, data_fields=1 (inner Type).
533                if header.format.blob_size != 0 || header.format.data_fields != 1 {
534                    return UnexpectedDataFormatSnafu {
535                        expected: Self::FORMAT,
536                        actual: Some(header),
537                    }
538                    .fail();
539                }
540                let mut typing = Type::default();
541                reader.read_data_into(&mut typing)?;
542                *self = Type::List(typing.into());
543            }
544            Self::MAP_ORDINAL => {
545                // Map: blob_size=0, data_fields=2 (key Type + value Type).
546                if header.format.blob_size != 0 || header.format.data_fields != 2 {
547                    return UnexpectedDataFormatSnafu {
548                        expected: Self::FORMAT,
549                        actual: Some(header),
550                    }
551                    .fail();
552                }
553                let mut key_typing = Type::default();
554                reader.read_data_into(&mut key_typing)?;
555                let mut value_typing = Type::default();
556                reader.read_data_into(&mut value_typing)?;
557                *self = Type::Map((key_typing, value_typing).into());
558            }
559            ordinal => match Type::from_ordinal(ordinal) {
560                // Scalars: blob_size=0, data_fields=0 (no payload).
561                Some(simple) => {
562                    if header.format.blob_size != 0 || header.format.data_fields != 0 {
563                        return UnexpectedDataFormatSnafu {
564                            expected: Self::FORMAT,
565                            actual: Some(header),
566                        }
567                        .fail();
568                    }
569                    *self = simple;
570                }
571                // Any unknown ordinal is a data type descriptor.
572                None => {
573                    // Data: blob_size=0, data_fields=1 (inner DataType).
574                    if header.format.blob_size != 0 || header.format.data_fields != 1 {
575                        return UnexpectedDataFormatSnafu {
576                            expected: Self::FORMAT,
577                            actual: Some(header),
578                        }
579                        .fail();
580                    }
581                    let mut typing = DataType::default();
582                    reader.read_data_into(&mut typing)?;
583                    *self = Type::Data(typing);
584                }
585            },
586        }
587
588        Ok(())
589    }
590}
591
592impl Encodable for Coda {
593    const FORMAT: crate::codec::Format = Format::data(1)
594        .with(Text::FORMAT)
595        .with(Text::FORMAT)
596        .with(Text::FORMAT)
597        .with(Vec::<DataType>::FORMAT);
598
599    fn encode(
600        &self,
601        writer: &mut (impl crate::codec::WritesEncodable + ?Sized),
602    ) -> Result<(), crate::codec::CodecError> {
603        writer.write_data(&self.global_name)?;
604        writer.write_data(&self.local_name)?;
605        writer.write_data(&self.docs)?;
606        writer.write_data(&self.data)?;
607        Ok(())
608    }
609}
610
611impl Decodable for Coda {
612    fn decode(
613        &mut self,
614        reader: &mut (impl crate::codec::ReadsDecodable + ?Sized),
615        header: Option<crate::codec::DataHeader>,
616    ) -> Result<(), crate::codec::CodecError> {
617        let header = Self::ensure_header(header)?;
618        let mut fields = FieldReader::new(reader, header);
619        fields.read(&mut self.global_name)?;
620        fields.read(&mut self.local_name)?;
621        fields.read(&mut self.docs)?;
622        fields.read(&mut self.data)?;
623        fields.finish()
624    }
625}
626
627impl Encodable for DataType {
628    const FORMAT: Format = Format::data(2)
629        .with(Text::FORMAT)
630        .with(Option::<Text>::FORMAT)
631        .with(Vec::<DataField>::FORMAT)
632        .with(Vec::<DataField>::FORMAT)
633        .with(Format::FORMAT);
634
635    fn encode(&self, writer: &mut (impl WritesEncodable + ?Sized)) -> Result<(), CodecError> {
636        writer.write_data(&self.name)?;
637        writer.write_data(&self.docs)?;
638        writer.write_data(&self.blob_fields)?;
639        writer.write_data(&self.data_fields)?;
640        writer.write_data(&self.format)?;
641        Ok(())
642    }
643}
644
645impl Decodable for DataType {
646    fn decode(
647        &mut self,
648        reader: &mut (impl ReadsDecodable + ?Sized),
649        header: Option<DataHeader>,
650    ) -> Result<(), CodecError> {
651        let header = Self::ensure_header(header)?;
652        let mut fields = FieldReader::new(reader, header);
653        fields.read(&mut self.name)?;
654        fields.read(&mut self.docs)?;
655        fields.read(&mut self.blob_fields)?;
656        fields.read(&mut self.data_fields)?;
657        fields.read(&mut self.format)?;
658        fields.finish()
659    }
660}
661
662impl Encodable for DataField {
663    const FORMAT: Format = Format::data(3)
664        .with(bool::FORMAT)
665        .with(bool::FORMAT)
666        .with(Text::FORMAT)
667        .with(Option::<Text>::FORMAT)
668        .with(Type::FORMAT);
669
670    fn encode(&self, writer: &mut (impl WritesEncodable + ?Sized)) -> Result<(), CodecError> {
671        writer.write_data(&self.optional)?;
672        writer.write_data(&self.flattened)?;
673        writer.write_data(&self.name)?;
674        writer.write_data(&self.docs)?;
675        writer.write_data(&self.typing)?;
676        Ok(())
677    }
678}
679
680impl Decodable for DataField {
681    fn decode(
682        &mut self,
683        reader: &mut (impl ReadsDecodable + ?Sized),
684        header: Option<DataHeader>,
685    ) -> Result<(), CodecError> {
686        let header = Self::ensure_header(header)?;
687        let mut fields = FieldReader::new(reader, header);
688        fields.read(&mut self.optional)?;
689        fields.read(&mut self.flattened)?;
690        fields.read(&mut self.name)?;
691        fields.read(&mut self.docs)?;
692        fields.read(&mut self.typing)?;
693        fields.finish()
694    }
695}
696
697impl<T> Encodable for Option<T>
698where
699    T: Default + Encodable + 'static,
700{
701    /// Encoded as a [`Format::as_sequence`] of zero
702    /// (`None`) or one (`Some`) `T`, identically to
703    /// a [`Vec<T>`] of the same length.
704    const FORMAT: Format = T::FORMAT.as_sequence();
705
706    fn encode(&self, writer: &mut (impl WritesEncodable + ?Sized)) -> Result<(), CodecError> {
707        match self {
708            None => Ok(()),
709            Some(value) => writer.write_sequence_data(value),
710        }
711    }
712
713    fn encode_header(
714        &self,
715        writer: &mut (impl WritesEncodable + ?Sized),
716    ) -> Result<(), CodecError> {
717        DataHeader {
718            count: if self.is_some() { 1 } else { 0 },
719            format: Self::FORMAT.as_data_format(),
720        }
721        .encode(writer)
722    }
723}
724
725impl<T> Decodable for Option<T>
726where
727    T: Decodable + Default + 'static,
728{
729    fn decode(
730        &mut self,
731        reader: &mut (impl ReadsDecodable + ?Sized),
732        header: Option<DataHeader>,
733    ) -> Result<(), CodecError> {
734        let header = Self::ensure_header(header)?;
735
736        match header.count {
737            0 => *self = None,
738            1 => {
739                let value = self.get_or_insert_with(T::default);
740                reader.read_next_data_into(header, value)?;
741            }
742            count => return crate::codec::UnsupportedCountSnafu { count }.fail(),
743        }
744
745        Ok(())
746    }
747}
748
749#[cfg(test)]
750mod tests {
751    use crate::codec::{Decodable, WritesEncodable};
752
753    use super::*;
754
755    /// Sample data structure for testing type manipulation APIs.
756    #[derive(Clone, Debug, Default, PartialEq)]
757    pub struct TestData {
758        pub number: i32,
759        pub floaty: f64,
760        pub text_list: Vec<Text>,
761        pub text: Text,
762        pub nested: NestedTestData,
763        pub two_d: Vec<Vec<Text>>,
764    }
765
766    impl TestData {
767        pub fn typing() -> DataType {
768            let blob_fields = vec![
769                DataField {
770                    name: Text::from("number"),
771                    docs: None,
772                    typing: Type::I32,
773                    optional: false,
774                    flattened: false,
775                },
776                DataField {
777                    name: Text::from("floaty"),
778                    docs: None,
779                    typing: Type::F64,
780                    optional: false,
781                    flattened: false,
782                },
783            ];
784
785            let data_fields = vec![
786                DataField {
787                    name: Text::from("text_list"),
788                    docs: None,
789                    typing: Type::List(Type::Text.into()),
790                    optional: false,
791                    flattened: false,
792                },
793                DataField {
794                    name: Text::from("text"),
795                    docs: None,
796                    typing: Type::Text,
797                    optional: false,
798                    flattened: false,
799                },
800                DataField {
801                    name: Text::from("nested"),
802                    docs: None,
803                    typing: Type::Data(NestedTestData::typing()),
804                    optional: false,
805                    flattened: false,
806                },
807                DataField {
808                    name: Text::from("two_d"),
809                    docs: None,
810                    typing: Type::List(Type::List(Type::Text.into()).into()),
811                    optional: false,
812                    flattened: false,
813                },
814            ];
815
816            let typing = DataType::new(Text::from("Testdata"), None, 1, &blob_fields, &data_fields);
817
818            assert_eq!(Self::FORMAT, *typing.format());
819
820            typing
821        }
822    }
823
824    impl Encodable for TestData {
825        const FORMAT: Format = Format::data(1)
826            .with(i32::FORMAT)
827            .with(f64::FORMAT)
828            .with(Vec::<Text>::FORMAT)
829            .with(Text::FORMAT)
830            .with(NestedTestData::FORMAT)
831            .with(Vec::<Vec<Text>>::FORMAT);
832
833        fn encode(&self, writer: &mut (impl WritesEncodable + ?Sized)) -> Result<(), CodecError> {
834            writer.write_data(&self.number)?;
835            writer.write_data(&self.floaty)?;
836            writer.write_data(&self.text_list)?;
837            writer.write_data(&self.text)?;
838            writer.write_data(&self.nested)?;
839            writer.write_data(&self.two_d)?;
840            Ok(())
841        }
842    }
843
844    impl Decodable for TestData {
845        fn decode(
846            &mut self,
847            reader: &mut (impl ReadsDecodable + ?Sized),
848            header: Option<DataHeader>,
849        ) -> Result<(), CodecError> {
850            let header = Self::ensure_header(header)?;
851            let mut fields = FieldReader::new(reader, header);
852            fields.read(&mut self.number)?;
853            fields.read(&mut self.floaty)?;
854            fields.read(&mut self.text_list)?;
855            fields.read(&mut self.text)?;
856            fields.read(&mut self.nested)?;
857            fields.read(&mut self.two_d)?;
858            fields.finish()
859        }
860    }
861
862    /// Simple data structure intended for nesting
863    /// inside of a [`TestData`].
864    #[derive(Clone, Debug, Default, PartialEq)]
865    pub struct NestedTestData {
866        pub boolean: bool,
867    }
868
869    impl NestedTestData {
870        pub fn typing() -> DataType {
871            let blob_fields = vec![DataField {
872                name: Text::from("boolean"),
873                docs: None,
874                typing: Type::Bool,
875                optional: false,
876                flattened: false,
877            }];
878
879            let data_fields = vec![];
880
881            let typing = DataType::new(
882                Text::from("NestedTestdata"),
883                None,
884                2,
885                &blob_fields,
886                &data_fields,
887            );
888
889            assert_eq!(Self::FORMAT, *typing.format());
890
891            typing
892        }
893    }
894
895    impl Encodable for NestedTestData {
896        const FORMAT: Format = Format::data(2).with(bool::FORMAT);
897
898        fn encode(&self, writer: &mut (impl WritesEncodable + ?Sized)) -> Result<(), CodecError> {
899            writer.write_data(&self.boolean)?;
900            Ok(())
901        }
902    }
903
904    impl Decodable for NestedTestData {
905        fn decode(
906            &mut self,
907            reader: &mut (impl ReadsDecodable + ?Sized),
908            header: Option<DataHeader>,
909        ) -> Result<(), CodecError> {
910            let header = Self::ensure_header(header)?;
911            let mut fields = FieldReader::new(reader, header);
912            fields.read(&mut self.boolean)?;
913            fields.finish()
914        }
915    }
916
917    /// [`NestedTestData`] with fields appended.
918    #[derive(Clone, Debug, Default, PartialEq)]
919    pub struct EvolvedNestedTestData {
920        pub boolean: bool,
921        pub extra_number: u16,
922        pub extra_text: Text,
923        pub extra_optional: Option<u32>,
924    }
925
926    impl Encodable for EvolvedNestedTestData {
927        const FORMAT: Format = Format::data(2)
928            .with(bool::FORMAT)
929            .with(u16::FORMAT)
930            .with(Text::FORMAT)
931            .with(Option::<u32>::FORMAT);
932
933        fn encode(&self, writer: &mut (impl WritesEncodable + ?Sized)) -> Result<(), CodecError> {
934            writer.write_data(&self.boolean)?;
935            writer.write_data(&self.extra_number)?;
936            writer.write_data(&self.extra_text)?;
937            writer.write_data(&self.extra_optional)?;
938            Ok(())
939        }
940    }
941
942    impl Decodable for EvolvedNestedTestData {
943        fn decode(
944            &mut self,
945            reader: &mut (impl ReadsDecodable + ?Sized),
946            header: Option<DataHeader>,
947        ) -> Result<(), CodecError> {
948            let header = Self::ensure_header(header)?;
949            let mut fields = FieldReader::new(reader, header);
950            fields.read(&mut self.boolean)?;
951            fields.read(&mut self.extra_number)?;
952            fields.read(&mut self.extra_text)?;
953            fields.read(&mut self.extra_optional)?;
954            fields.finish()
955        }
956    }
957
958    #[test]
959    pub fn data_type_codec() {
960        let data_type = TestData::typing();
961
962        let mut encoded_data_type = vec![];
963        encoded_data_type.write_data(&data_type).unwrap();
964        let decoded_data_type = encoded_data_type.as_slice().read_data().unwrap();
965
966        assert_eq!(data_type, decoded_data_type);
967    }
968
969    #[test]
970    fn schema_formats_match_runtime_formats() {
971        use alloc::collections::BTreeMap;
972
973        fn check<T: Encodable>(typing: Type) {
974            assert_eq!(T::FORMAT, typing.format(), "{typing:?}");
975        }
976
977        fn check_optional<T: Encodable + Default + 'static>(typing: Type) {
978            let field = DataField {
979                name: Text::from("field"),
980                docs: None,
981                typing: typing.clone(),
982                optional: true,
983                flattened: false,
984            };
985            assert_eq!(Option::<T>::FORMAT, field.format(), "optional {typing:?}");
986        }
987
988        let data = || Type::Data(TestData::typing());
989        let map = || Type::Map((Type::Text, Type::F32).into());
990
991        check::<u8>(Type::U8);
992        check::<u16>(Type::U16);
993        check::<u32>(Type::U32);
994        check::<u64>(Type::U64);
995        check::<i8>(Type::I8);
996        check::<i16>(Type::I16);
997        check::<i32>(Type::I32);
998        check::<i64>(Type::I64);
999        check::<f32>(Type::F32);
1000        check::<f64>(Type::F64);
1001        check::<bool>(Type::Bool);
1002        check::<Text>(Type::Text);
1003        check::<Unspecified>(Type::Unspecified);
1004        check::<Array<u8, 32>>(Type::Array(32, Type::U8.into()));
1005        check::<Array<Array<f32, 3>, 3>>(Type::Array(3, Type::Array(3, Type::F32.into()).into()));
1006        check::<TestData>(data());
1007        check::<BTreeMap<Text, f32>>(map());
1008
1009        check::<Vec<u32>>(Type::List(Type::U32.into()));
1010        check::<Vec<Text>>(Type::List(Type::Text.into()));
1011        check::<Vec<Vec<Text>>>(Type::List(Type::List(Type::Text.into()).into()));
1012        check::<Vec<Unspecified>>(Type::List(Type::Unspecified.into()));
1013        check::<Vec<Array<f32, 3>>>(Type::List(Type::Array(3, Type::F32.into()).into()));
1014        check::<Vec<TestData>>(Type::List(data().into()));
1015        check::<Vec<BTreeMap<Text, f32>>>(Type::List(map().into()));
1016
1017        check_optional::<u32>(Type::U32);
1018        check_optional::<Text>(Type::Text);
1019        check_optional::<Unspecified>(Type::Unspecified);
1020        check_optional::<Array<u8, 48>>(Type::Array(48, Type::U8.into()));
1021        check_optional::<TestData>(data());
1022        check_optional::<BTreeMap<Text, f32>>(map());
1023        check_optional::<Vec<u32>>(Type::List(Type::U32.into()));
1024        check_optional::<Vec<TestData>>(Type::List(data().into()));
1025    }
1026
1027    /// Options encode identically to lists
1028    /// of zero or one data.
1029    #[test]
1030    fn options_are_short_lists() -> Result<(), CodecError> {
1031        fn check<T>(some: T) -> Result<(), CodecError>
1032        where
1033            T: Decodable + Default + Clone + PartialEq + core::fmt::Debug + 'static,
1034        {
1035            for (option, list) in [(None, vec![]), (Some(some.clone()), vec![some])] {
1036                let mut option_bytes = vec![];
1037                option_bytes.write_data(&option)?;
1038                let mut list_bytes = vec![];
1039                list_bytes.write_data(&list)?;
1040                assert_eq!(option_bytes, list_bytes);
1041
1042                assert_eq!(option, option_bytes.as_slice().read_data::<Option<T>>()?);
1043                assert_eq!(list, list_bytes.as_slice().read_data::<Vec<T>>()?);
1044                assert_eq!(list, option_bytes.as_slice().read_data::<Vec<T>>()?);
1045                assert_eq!(option, list_bytes.as_slice().read_data::<Option<T>>()?);
1046            }
1047
1048            // Longer lists aren't options.
1049            let mut list_bytes = vec![];
1050            list_bytes.write_data(&vec![T::default(), T::default()])?;
1051            assert!(matches!(
1052                list_bytes.as_slice().read_data::<Option<T>>(),
1053                Err(CodecError::UnsupportedCount { count: 2 })
1054            ));
1055
1056            Ok(())
1057        }
1058
1059        check(7u32)?;
1060        check(Text::from("seven"))?;
1061        check(NestedTestData { boolean: true })?;
1062        check(vec![7u32])?;
1063        check(Some(7u32))?;
1064        Ok(())
1065    }
1066
1067    #[test]
1068    fn named_data_are_packed() -> Result<(), CodecError> {
1069        let list = vec![
1070            NestedTestData { boolean: true },
1071            NestedTestData { boolean: false },
1072            NestedTestData { boolean: true },
1073        ];
1074
1075        let mut encoded = vec![];
1076        encoded.write_data(&list)?;
1077        assert_eq!(8 + 3, encoded.len(), "one header, then packed data");
1078        assert_eq!(
1079            [3, 0, 0, 0, 1, 0, 0, 2, 1, 0, 1],
1080            encoded.as_slice(),
1081            "count=3, blob_size=1, data_fields=0, ordinal=2, then bools"
1082        );
1083        let decoded: Vec<NestedTestData> = encoded.as_slice().read_data()?;
1084        assert_eq!(list, decoded);
1085
1086        let optional = Some(NestedTestData { boolean: true });
1087        let mut encoded = vec![];
1088        encoded.write_data(&optional)?;
1089        assert_eq!(8 + 1, encoded.len(), "one header, then the packed data");
1090        let decoded: Option<NestedTestData> = encoded.as_slice().read_data()?;
1091        assert_eq!(optional, decoded);
1092
1093        // A named data with a count other than 1 can't be
1094        // decoded as a single data.
1095        let mut encoded = vec![];
1096        encoded.write_data(&list)?;
1097        assert!(matches!(
1098            encoded.as_slice().read_data::<NestedTestData>(),
1099            Err(CodecError::UnsupportedCount { count: 3 })
1100        ));
1101
1102        Ok(())
1103    }
1104
1105    #[test]
1106    fn evolved_data_decode() -> Result<(), CodecError> {
1107        let old = NestedTestData { boolean: true };
1108        let new = EvolvedNestedTestData {
1109            boolean: true,
1110            extra_number: 9001,
1111            extra_text: "extra".into(),
1112            extra_optional: Some(7),
1113        };
1114
1115        // Newer data decodes into an older type by
1116        // skipping the fields the older type doesn't know.
1117        let mut encoded = vec![];
1118        encoded.write_data(&new)?;
1119        encoded.write_data(&42u8)?; // Sentinel after the data.
1120        let mut reader = encoded.as_slice();
1121        let decoded: NestedTestData = reader.read_data()?;
1122        assert_eq!(old, decoded);
1123        assert_eq!(42u8, reader.read_data()?, "skipped to the sentinel");
1124
1125        // Older data decodes into a newer type by
1126        // defaulting the fields the older data lacks;
1127        // stale values in the reused instance are reset.
1128        let mut encoded = vec![];
1129        encoded.write_data(&old)?;
1130        let mut decoded = new.clone();
1131        encoded.as_slice().read_data_into(&mut decoded)?;
1132        assert_eq!(
1133            EvolvedNestedTestData {
1134                boolean: true,
1135                ..Default::default()
1136            },
1137            decoded
1138        );
1139
1140        // The same holds for packed sequences of data.
1141        let news = vec![new.clone(), new.clone()];
1142        let mut encoded = vec![];
1143        encoded.write_data(&news)?;
1144        encoded.write_data(&42u8)?;
1145        let mut reader = encoded.as_slice();
1146        let decoded: Vec<NestedTestData> = reader.read_data()?;
1147        assert_eq!(vec![old.clone(), old.clone()], decoded);
1148        assert_eq!(42u8, reader.read_data()?, "skipped to the sentinel");
1149
1150        let olds = vec![old.clone(), old.clone()];
1151        let mut encoded = vec![];
1152        encoded.write_data(&olds)?;
1153        let decoded: Vec<EvolvedNestedTestData> = encoded.as_slice().read_data()?;
1154        assert_eq!(
1155            vec![
1156                EvolvedNestedTestData {
1157                    boolean: true,
1158                    ..Default::default()
1159                };
1160                2
1161            ],
1162            decoded
1163        );
1164
1165        // And for optional data.
1166        let mut encoded = vec![];
1167        encoded.write_data(&Some(new.clone()))?;
1168        let decoded: Option<NestedTestData> = encoded.as_slice().read_data()?;
1169        assert_eq!(Some(old), decoded);
1170
1171        Ok(())
1172    }
1173
1174    #[test]
1175    fn invalid_utf8_is_an_error() {
1176        let mut encoded = vec![];
1177        encoded.write_data(&Text::from("ok")).unwrap();
1178        encoded[8] = 0xFF;
1179        assert!(matches!(
1180            encoded.as_slice().read_data::<Text>(),
1181            Err(CodecError::InvalidUtf8)
1182        ));
1183    }
1184
1185    #[test]
1186    fn array_type_codec() {
1187        // Array types round-trip through the Type codec,
1188        // preserving their count and element type.
1189        let typing = Type::Array(4096, Type::U8.into());
1190        let mut encoded = vec![];
1191        encoded.write_data(&typing).unwrap();
1192        let decoded: Type = encoded.as_slice().read_data().unwrap();
1193        assert_eq!(typing, decoded);
1194
1195        // Nested arrays round-trip, too.
1196        let typing = Type::Array(3, Type::Array(3, Type::F32.into()).into());
1197        assert_eq!(Format::Blob(36), typing.format());
1198        let mut encoded = vec![];
1199        encoded.write_data(&typing).unwrap();
1200        let decoded: Type = encoded.as_slice().read_data().unwrap();
1201        assert_eq!(typing, decoded);
1202
1203        // Data types containing array fields round-trip, too.
1204        let data_type = DataType::new(Text::from("Blobby"), None, 1, &[], &[]).with(DataField {
1205            name: Text::from("hash"),
1206            docs: None,
1207            typing: Type::Array(32, Type::U8.into()),
1208            optional: false,
1209            flattened: false,
1210        });
1211        assert_eq!(Format::data(1).with(Format::Blob(32)), *data_type.format());
1212
1213        let mut encoded = vec![];
1214        encoded.write_data(&data_type).unwrap();
1215        let decoded: DataType = encoded.as_slice().read_data().unwrap();
1216        assert_eq!(data_type, decoded);
1217    }
1218
1219    /// Sample data structure containing a fixed-size array
1220    /// field, mirroring the code generated for a coda with
1221    /// an `array of 16 u8` field.
1222    #[derive(Clone, Debug, Default, PartialEq)]
1223    struct BlobTestData {
1224        id: u32,
1225        hash: Array<u8, 16>,
1226        text: Text,
1227    }
1228
1229    impl Encodable for BlobTestData {
1230        const FORMAT: Format = Format::data(1)
1231            .with(u32::FORMAT)
1232            .with(Array::<u8, 16>::FORMAT)
1233            .with(Text::FORMAT);
1234
1235        fn encode(&self, writer: &mut (impl WritesEncodable + ?Sized)) -> Result<(), CodecError> {
1236            writer.write_data(&self.id)?;
1237            writer.write_data(&self.hash)?;
1238            writer.write_data(&self.text)?;
1239            Ok(())
1240        }
1241    }
1242
1243    impl Decodable for BlobTestData {
1244        fn decode(
1245            &mut self,
1246            reader: &mut (impl ReadsDecodable + ?Sized),
1247            header: Option<DataHeader>,
1248        ) -> Result<(), CodecError> {
1249            let _ = Self::ensure_header(header)?;
1250            reader.read_data_into(&mut self.id)?;
1251            reader.read_data_into(&mut self.hash)?;
1252            reader.read_data_into(&mut self.text)?;
1253            Ok(())
1254        }
1255    }
1256
1257    #[test]
1258    fn blob_fields_encode_into_blob_section() {
1259        // The blob field contributes to the data's blob
1260        // section instead of its data fields.
1261        assert_eq!(
1262            Format::Data(DataFormat {
1263                blob_size: 4 + 16,
1264                data_fields: 1,
1265                ordinal: 1,
1266            }),
1267            BlobTestData::FORMAT
1268        );
1269
1270        let data = BlobTestData {
1271            id: 9001,
1272            hash: Array([7; 16]),
1273            text: "blobby!".into(),
1274        };
1275        let mut encoded = vec![];
1276        encoded.write_data(&data).unwrap();
1277
1278        // Wire layout: header(8) + id(4) + hash(16) +
1279        // text header(8) + text bytes.
1280        assert_eq!(8 + 4 + 16 + 8 + data.text.len(), encoded.len());
1281
1282        // The hash's bytes are stored raw in the blob
1283        // section, with no header, directly after `id`.
1284        assert_eq!(&[7; 16], &encoded[12..28]);
1285
1286        let decoded: BlobTestData = encoded.as_slice().read_data().unwrap();
1287        assert_eq!(data, decoded);
1288    }
1289
1290    #[test]
1291    fn blob_field_lists_encode_homogeneously() {
1292        // Lists of fixed-size byte arrays encode as a
1293        // single header followed by tightly-packed
1294        // elements (stride = the array size).
1295        let list: Vec<[u8; 4]> = vec![[1; 4], [2; 4], [3; 4]];
1296        let mut encoded = vec![];
1297        encoded.write_data(&list).unwrap();
1298        assert_eq!(8 + 3 * 4, encoded.len());
1299
1300        let decoded: Vec<[u8; 4]> = encoded.as_slice().read_data().unwrap();
1301        assert_eq!(list, decoded);
1302    }
1303
1304    #[test]
1305    fn codes_unstructured_optionals() {
1306        let option: Option<u32> = Some(1337u32);
1307        let mut data = vec![];
1308        data.write_data(&option).expect("encoded");
1309        println!("encoded");
1310        let decoded_option = data.as_slice().read_data().expect("decoded");
1311        assert_eq!(option, decoded_option);
1312
1313        // Do None values decode as None?
1314        let option: Option<u32> = None;
1315        let mut data = vec![];
1316        data.write_data(&option).expect("encoded");
1317        let decoded_option = data.as_slice().read_data().expect("decoded");
1318        assert_eq!(option, decoded_option);
1319
1320        // Default values round-trip as Some(default).
1321        let option: Option<u32> = Some(0);
1322        let mut data = vec![];
1323        data.write_data(&option).expect("encoded");
1324        let decoded_option: Option<u32> = data.as_slice().read_data().expect("decoded");
1325        assert_eq!(Some(0), decoded_option);
1326    }
1327
1328    #[test]
1329    fn codes_structured_optionals() {
1330        let option: Option<Text> = Some("Hello, World!".into());
1331        let mut data = vec![];
1332        data.write_data(&option).expect("encoded");
1333        println!("encoded");
1334        let decoded_option = data.as_slice().read_data().expect("decoded");
1335        assert_eq!(option, decoded_option);
1336
1337        // Do None values decode as None?
1338        let option: Option<Text> = None;
1339        let mut data = vec![];
1340        data.write_data(&option).expect("encoded");
1341        let decoded_option = data.as_slice().read_data().expect("decoded");
1342        assert_eq!(option, decoded_option);
1343
1344        // Default values round-trip as Some(default).
1345        let option: Option<Text> = Some("".into());
1346        let mut data = vec![];
1347        data.write_data(&option).expect("encoded");
1348        let decoded_option: Option<Text> = data.as_slice().read_data().expect("decoded");
1349        assert_eq!(Some("".into()), decoded_option);
1350    }
1351
1352    #[test]
1353    fn codes_nested_optionals() {
1354        // None
1355        let option: Option<Option<u32>> = None;
1356        let mut data = vec![];
1357        data.write_data(&option).expect("encoded");
1358        let decoded: Option<Option<u32>> = data.as_slice().read_data().expect("decoded");
1359        assert_eq!(option, decoded);
1360
1361        // Some(None)
1362        let option: Option<Option<u32>> = Some(None);
1363        let mut data = vec![];
1364        data.write_data(&option).expect("encoded");
1365        let decoded: Option<Option<u32>> = data.as_slice().read_data().expect("decoded");
1366        assert_eq!(option, decoded);
1367
1368        // Some(Some(0)) — the previously unrepresentable case
1369        let option: Option<Option<u32>> = Some(Some(0));
1370        let mut data = vec![];
1371        data.write_data(&option).expect("encoded");
1372        let decoded: Option<Option<u32>> = data.as_slice().read_data().expect("decoded");
1373        assert_eq!(option, decoded);
1374
1375        // Some(Some(42))
1376        let option: Option<Option<u32>> = Some(Some(42));
1377        let mut data = vec![];
1378        data.write_data(&option).expect("encoded");
1379        let decoded: Option<Option<u32>> = data.as_slice().read_data().expect("decoded");
1380        assert_eq!(option, decoded);
1381    }
1382
1383    #[test]
1384    fn codes_optional_vec() {
1385        // None
1386        let option: Option<Vec<u16>> = None;
1387        let mut data = vec![];
1388        data.write_data(&option).expect("encoded");
1389        let decoded: Option<Vec<u16>> = data.as_slice().read_data().expect("decoded");
1390        assert_eq!(option, decoded);
1391
1392        // Some(vec![])
1393        let option: Option<Vec<u16>> = Some(vec![]);
1394        let mut data = vec![];
1395        data.write_data(&option).expect("encoded");
1396        let decoded: Option<Vec<u16>> = data.as_slice().read_data().expect("decoded");
1397        assert_eq!(option, decoded);
1398
1399        // Some(vec![42])
1400        let option: Option<Vec<u16>> = Some(vec![42]);
1401        let mut data = vec![];
1402        data.write_data(&option).expect("encoded");
1403        let decoded: Option<Vec<u16>> = data.as_slice().read_data().expect("decoded");
1404        assert_eq!(option, decoded);
1405    }
1406
1407    /// Verifies that `ordinal()` and `from_ordinal()` are consistent:
1408    /// for every ordinal 0–255, if `from_ordinal` returns `Some(t)`,
1409    /// then `t.ordinal()` equals the original ordinal.
1410    #[test]
1411    fn ordinal_round_trip() {
1412        for ordinal in 0..=255u8 {
1413            if let Some(typ) = Type::from_ordinal(ordinal) {
1414                assert_eq!(
1415                    ordinal,
1416                    typ.ordinal(),
1417                    "from_ordinal({ordinal}) returned {typ:?} with ordinal {}",
1418                    typ.ordinal()
1419                );
1420            }
1421        }
1422    }
1423}