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}