Skip to main content

cyclone_runtime_rust/
codec.rs

1//! The traits a codec implements, and the two helpers that use them.
2//!
3//! The runtime knows nothing about how an implementation of these traits comes
4//! to exist. `#[derive(Network)]` writes one, the Cyclone CLI writes one into a
5//! `*.codec.rs` file, and writing one by hand is equally valid. All three are
6//! the same to this module.
7
8use crate::error::DecodeError;
9use crate::reader::Reader;
10use crate::writer::Writer;
11
12/// A type that can be written as Cyclone bytes.
13///
14/// The implementation is the schema: it decides which fields are written, in
15/// which order, and with which Cyclone type. Nothing here inspects the Rust
16/// type to work that out.
17///
18/// ```
19/// use cyclone_runtime::{Encode, Writer};
20///
21/// struct Item { id: u32, name: String }
22///
23/// impl Encode for Item {
24///     fn encode(&self, writer: &mut Writer) {
25///         writer.write_u32(self.id);
26///         writer.write_string(&self.name);
27///     }
28/// }
29///
30/// let mut writer = Writer::new();
31/// Item { id: 42, name: "Sword".to_owned() }.encode(&mut writer);
32/// assert_eq!(writer.len(), 13);
33/// ```
34pub trait Encode {
35    /// Appends the Cyclone encoding of `self` to `writer`.
36    ///
37    /// Fields go in declaration order with nothing between them: no padding,
38    /// no alignment, no field id, no header (RFC-0002 §5).
39    fn encode(&self, writer: &mut Writer);
40}
41
42/// A type that can be read back from Cyclone bytes.
43///
44/// The counterpart of [`Encode`], and the two must agree field for field: the
45/// byte stream carries no metadata to fall back on.
46pub trait Decode: Sized {
47    /// Reads one value from `reader`, advancing its cursor past it.
48    ///
49    /// # Errors
50    ///
51    /// Any [`DecodeError`] the underlying reads produce. On failure the cursor
52    /// is left where the failing read began.
53    fn decode(reader: &mut Reader<'_>) -> Result<Self, DecodeError>;
54}
55
56/// Encodes `value` into a fresh `Vec<u8>`.
57///
58/// ```
59/// # use cyclone_runtime::{Encode, Writer};
60/// # struct Item { id: u32 }
61/// # impl Encode for Item { fn encode(&self, w: &mut Writer) { w.write_u32(self.id); } }
62/// let bytes = cyclone_runtime::to_bytes(&Item { id: 42 });
63/// assert_eq!(bytes, [0x2A, 0x00, 0x00, 0x00]);
64/// ```
65///
66/// Use [`Writer`] directly when several values share one buffer, or when a
67/// pre-sized buffer avoids reallocation.
68pub fn to_bytes<T: Encode>(value: &T) -> Vec<u8> {
69    let mut writer = Writer::new();
70    value.encode(&mut writer);
71    writer.into_bytes()
72}
73
74/// Decodes a `T` from `bytes`.
75///
76/// ```
77/// # use cyclone_runtime::{DecodeError, Decode, Reader};
78/// # struct Item { id: u32 }
79/// # impl Decode for Item {
80/// #     fn decode(r: &mut Reader<'_>) -> Result<Self, DecodeError> { Ok(Item { id: r.read_u32()? }) }
81/// # }
82/// let item = cyclone_runtime::from_bytes::<Item>(&[0x2A, 0x00, 0x00, 0x00])?;
83/// assert_eq!(item.id, 42);
84/// # Ok::<(), DecodeError>(())
85/// ```
86///
87/// # Errors
88///
89/// Any [`DecodeError`] the decode produces.
90///
91/// # Trailing bytes
92///
93/// Bytes left over after the value are **not** an error here - this helper
94/// decodes one value and returns it. A stream that should end exactly at the
95/// value (RFC-0002 §9) needs the check made explicitly:
96///
97/// ```
98/// # use cyclone_runtime::{DecodeError, Decode, Reader};
99/// # struct Item { id: u32 }
100/// # impl Decode for Item {
101/// #     fn decode(r: &mut Reader<'_>) -> Result<Self, DecodeError> { Ok(Item { id: r.read_u32()? }) }
102/// # }
103/// # let bytes = [0x2A, 0x00, 0x00, 0x00];
104/// let mut reader = Reader::new(&bytes);
105/// let item = Item::decode(&mut reader)?;
106/// assert!(reader.is_empty(), "trailing bytes: the two ends disagree about the schema");
107/// # Ok::<(), DecodeError>(())
108/// ```
109///
110/// The same route applies when decoding untrusted input, which wants
111/// [`Reader::with_limits`] rather than the permissive default this helper uses.
112pub fn from_bytes<T: Decode>(bytes: &[u8]) -> Result<T, DecodeError> {
113    let mut reader = Reader::new(bytes);
114    T::decode(&mut reader)
115}