platform_serialization/
lib.rs

1pub mod de;
2pub mod enc;
3mod features;
4
5use bincode::config::Config;
6use bincode::de::read::Reader;
7use bincode::de::{read, DecoderImpl};
8use bincode::enc::write::Writer;
9use bincode::enc::{write, EncoderImpl};
10pub use enc::PlatformVersionEncode;
11pub use features::platform_encode_to_vec;
12
13/// Alias for the decoding context used across this crate.
14pub type BincodeContext = ();
15
16pub use de::DefaultBorrowDecode;
17pub use de::DefaultDecode;
18pub use de::PlatformVersionedBorrowDecode;
19pub use de::PlatformVersionedDecode;
20
21pub use bincode::enc::Encode;
22pub use bincode::error;
23pub use de::BorrowDecode;
24pub use de::Decode;
25use platform_version::version::PlatformVersion;
26
27extern crate alloc;
28extern crate std;
29
30/// Encode the given value into the given slice. Returns the amount of bytes that have been written.
31///
32/// See the [config] module for more information on configurations.
33///
34/// [config]: config/index.html
35pub fn platform_encode_into_slice<E: PlatformVersionEncode, C: Config>(
36    val: E,
37    dst: &mut [u8],
38    config: C,
39    platform_version: &PlatformVersion,
40) -> Result<usize, error::EncodeError> {
41    let writer = write::SliceWriter::new(dst);
42    let mut encoder = EncoderImpl::<_, C>::new(writer, config);
43    val.platform_encode(&mut encoder, platform_version)?;
44    Ok(encoder.into_writer().bytes_written())
45}
46
47/// Encode the given value into a custom [Writer].
48///
49/// See the [config] module for more information on configurations.
50///
51/// [config]: config/index.html
52pub fn encode_into_writer<E: PlatformVersionEncode, W: Writer, C: Config>(
53    val: E,
54    writer: W,
55    config: C,
56    platform_version: &PlatformVersion,
57) -> Result<(), error::EncodeError> {
58    let mut encoder = EncoderImpl::<_, C>::new(writer, config);
59    val.platform_encode(&mut encoder, platform_version)
60}
61
62/// Attempt to decode a given type `D` from the given slice. Returns the decoded output and the amount of bytes read.
63///
64/// See the [config] module for more information on configurations.
65///
66/// [config]: config/index.html
67pub fn platform_versioned_decode_from_slice<D: PlatformVersionedDecode, C: Config>(
68    src: &[u8],
69    config: C,
70    platform_version: &PlatformVersion,
71) -> Result<D, error::DecodeError> {
72    let reader = read::SliceReader::new(src);
73    let mut decoder = DecoderImpl::<_, C, crate::BincodeContext>::new(reader, config, ());
74    D::platform_versioned_decode(&mut decoder, platform_version)
75}
76
77/// Attempt to decode a given type `D` from the given slice. Returns the decoded output and the amount of bytes read.
78///
79/// See the [config] module for more information on configurations.
80///
81/// [config]: config/index.html
82pub fn platform_versioned_borrow_decode_from_slice<
83    'a,
84    D: PlatformVersionedBorrowDecode<'a>,
85    C: Config,
86>(
87    src: &'a [u8],
88    config: C,
89    platform_version: &PlatformVersion,
90) -> Result<D, error::DecodeError> {
91    let reader = read::SliceReader::new(src);
92    let mut decoder = DecoderImpl::<_, C, crate::BincodeContext>::new(reader, config, ());
93    D::platform_versioned_borrow_decode(&mut decoder, platform_version)
94}
95
96/// Attempt to decode a given type `D` from the given [Reader].
97///
98/// See the [config] module for more information on configurations.
99///
100/// [config]: config/index.html
101pub fn platform_versioned_decode_from_reader<D: PlatformVersionedDecode, R: Reader, C: Config>(
102    reader: R,
103    config: C,
104    platform_version: &PlatformVersion,
105) -> Result<D, error::DecodeError> {
106    let mut decoder = DecoderImpl::<_, C, crate::BincodeContext>::new(reader, config, ());
107    D::platform_versioned_decode(&mut decoder, platform_version)
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113    use bincode::config;
114    use platform_version::version::PlatformVersion;
115
116    fn cfg() -> impl Config {
117        config::standard().with_big_endian().with_no_limit()
118    }
119
120    fn pv() -> &'static PlatformVersion {
121        PlatformVersion::first()
122    }
123
124    // -----------------------------------------------------------------------
125    // Top-level encode/decode round-trip functions
126    // -----------------------------------------------------------------------
127
128    #[test]
129    fn encode_into_slice_and_decode_round_trip() {
130        let value: u32 = 42;
131        let mut buf = [0u8; 64];
132        let written = platform_encode_into_slice(value, &mut buf, cfg(), pv()).unwrap();
133        assert!(written > 0);
134
135        let decoded: u32 =
136            platform_versioned_decode_from_slice(&buf[..written], cfg(), pv()).unwrap();
137        assert_eq!(decoded, value);
138    }
139
140    #[test]
141    fn encode_into_slice_too_small_returns_error() {
142        let value: u64 = u64::MAX;
143        let mut buf = [0u8; 1]; // too small for a u64
144        let result = platform_encode_into_slice(value, &mut buf, cfg(), pv());
145        assert!(result.is_err());
146    }
147
148    #[test]
149    fn encode_into_writer_round_trip() {
150        let value: u16 = 1234;
151        let mut writer = enc::VecWriter::default();
152        encode_into_writer(value, &mut writer, cfg(), pv()).unwrap();
153
154        let encoded = platform_encode_to_vec(value, cfg(), pv()).unwrap();
155        let decoded: u16 = platform_versioned_decode_from_slice(&encoded, cfg(), pv()).unwrap();
156        assert_eq!(decoded, value);
157    }
158
159    #[test]
160    fn borrow_decode_from_slice_str() {
161        let value = "hello world";
162        let encoded = platform_encode_to_vec(value, cfg(), pv()).unwrap();
163
164        let decoded: &str =
165            platform_versioned_borrow_decode_from_slice(&encoded, cfg(), pv()).unwrap();
166        assert_eq!(decoded, value);
167    }
168
169    #[test]
170    fn decode_from_reader() {
171        let value: i64 = -99999;
172        let encoded = platform_encode_to_vec(value, cfg(), pv()).unwrap();
173
174        let reader = bincode::de::read::SliceReader::new(&encoded);
175        let decoded: i64 = platform_versioned_decode_from_reader(reader, cfg(), pv()).unwrap();
176        assert_eq!(decoded, value);
177    }
178
179    #[test]
180    fn decode_from_slice_empty_input_fails() {
181        let result = platform_versioned_decode_from_slice::<u32, _>(&[], cfg(), pv());
182        assert!(result.is_err());
183    }
184
185    #[test]
186    fn decode_from_slice_truncated_input_fails() {
187        let encoded = platform_encode_to_vec(42u32, cfg(), pv()).unwrap();
188        // only give half the bytes
189        let result = platform_versioned_decode_from_slice::<u32, _>(
190            &encoded[..encoded.len() / 2],
191            cfg(),
192            pv(),
193        );
194        assert!(result.is_err());
195    }
196}