Skip to main content

ridl_rt/
encoding.rs

1//! The payload encodings (ADR-0020 decisions 1 and 5).
2//!
3//! An encoding is a marker type. A payload type implements `Payload<E>` once
4//! for each encoding its package was built with, so one type can carry several
5//! codecs. The set of encodings is closed: [`Encoding`] is sealed, so a new
6//! encoding is a decision recorded in an ADR and not an `impl` in another
7//! crate.
8//!
9//! The marker types do not depend on a cargo feature. A runtime can name every
10//! encoding without linking a codec.
11
12use crate::contract::EncodedSizes;
13
14mod sealed {
15    pub trait Sealed {}
16}
17
18/// A payload encoding. Only the three marker types of this module implement
19/// it.
20///
21/// A crate outside `ridl-rt` names an encoding through this trait:
22///
23/// ```
24/// fn name<E: ridl_rt::encoding::Encoding>() -> &'static str {
25///     E::NAME
26/// }
27/// assert_eq!(name::<ridl_rt::encoding::ReprC>(), "repr-c");
28/// ```
29///
30/// and cannot add an encoding:
31///
32/// ```compile_fail,E0277
33/// struct Json;
34///
35/// impl ridl_rt::encoding::Encoding for Json {
36///     const NAME: &'static str = "json";
37///     fn max_size(sizes: &ridl_rt::contract::EncodedSizes) -> Option<u32> {
38///         sizes.proto3
39///     }
40/// }
41/// ```
42///
43/// and cannot implement the sealing trait, because its module is private:
44///
45/// ```compile_fail,E0603
46/// struct Json;
47///
48/// impl ridl_rt::encoding::sealed::Sealed for Json {}
49/// ```
50pub trait Encoding: sealed::Sealed + 'static {
51    /// The encoding's name, spelled as its cargo feature is spelled.
52    const NAME: &'static str;
53
54    /// This encoding's field of `sizes`: a payload's largest encoded size in
55    /// this encoding, or `None` when the toolchain cannot size it
56    /// ([`EncodedSizes`]).
57    ///
58    /// A required item, so an encoding added without saying which field it
59    /// reads does not compile.
60    fn max_size(sizes: &EncodedSizes) -> Option<u32>;
61}
62
63/// FlatBuffers.
64#[derive(Clone, Copy, Debug, PartialEq, Eq)]
65pub struct FlatBuffers;
66
67/// proto3.
68#[derive(Clone, Copy, Debug, PartialEq, Eq)]
69pub struct Proto3;
70
71/// `repr(C)`, the fixed-layout encoding of ADR-0020 decision 1.
72#[derive(Clone, Copy, Debug, PartialEq, Eq)]
73pub struct ReprC;
74
75impl sealed::Sealed for FlatBuffers {}
76impl sealed::Sealed for Proto3 {}
77impl sealed::Sealed for ReprC {}
78
79impl Encoding for FlatBuffers {
80    const NAME: &'static str = "flatbuffers";
81
82    fn max_size(sizes: &EncodedSizes) -> Option<u32> {
83        sizes.flatbuffers
84    }
85}
86
87impl Encoding for Proto3 {
88    const NAME: &'static str = "proto3";
89
90    fn max_size(sizes: &EncodedSizes) -> Option<u32> {
91        sizes.proto3
92    }
93}
94
95impl Encoding for ReprC {
96    const NAME: &'static str = "repr-c";
97
98    fn max_size(sizes: &EncodedSizes) -> Option<u32> {
99        sizes.repr_c
100    }
101}
102
103#[cfg(test)]
104mod tests {
105    use super::{sealed, Encoding, FlatBuffers, Proto3, ReprC};
106    use crate::contract::EncodedSizes;
107
108    /// A fourth encoding, for this test only. It implements every required
109    /// item of `Encoding`, so a required item added to the trait fails to
110    /// compile this module.
111    struct Fourth;
112
113    impl sealed::Sealed for Fourth {}
114
115    impl Encoding for Fourth {
116        const NAME: &'static str = "fourth";
117
118        fn max_size(_: &EncodedSizes) -> Option<u32> {
119            None
120        }
121    }
122
123    const SIZES: EncodedSizes = EncodedSizes {
124        proto3: Some(1),
125        flatbuffers: Some(2),
126        repr_c: Some(3),
127    };
128
129    #[test]
130    fn name_and_max_size_are_the_only_required_items() {
131        assert_eq!(Fourth::NAME, "fourth");
132        assert_eq!(Fourth::max_size(&SIZES), None);
133    }
134
135    /// `EncodedSizes` holds one field per core encoding, and each encoding
136    /// reads its own.
137    #[test]
138    fn each_encoding_reads_its_own_size_field() {
139        assert_eq!(Proto3::max_size(&SIZES), Some(1));
140        assert_eq!(FlatBuffers::max_size(&SIZES), Some(2));
141        assert_eq!(ReprC::max_size(&SIZES), Some(3));
142    }
143
144    #[test]
145    fn each_name_is_the_cargo_feature_name() {
146        assert_eq!(FlatBuffers::NAME, "flatbuffers");
147        assert_eq!(Proto3::NAME, "proto3");
148        assert_eq!(ReprC::NAME, "repr-c");
149    }
150}