bytecoding/
lib.rs

1//! Derive macro for encoding and decoding instructions and operands as bytecode.
2//!
3//! # Derive macro
4//!
5//! ## Enum attributes
6//!
7//! Attributes that can be used on enums.
8//!
9//! - `type = ...` (required)
10//!
11//!     Sets which type is used for the instruction code. Possible values are `u8`, `u16`, `u32`,
12//!     and `u64`.
13//!
14//! ## Variant attributes
15//!
16//! Attributes that can be used on enum variants.
17//!
18//! - `code = ...`
19//!
20//!     Sets the instruction codes for this enum variant. A code has to be specified for every
21//!     instruction this variant generates. If the variant only generates one instruction, then a
22//!     single number can be used for the `code` attribute (instead of a list of numbers).
23//!
24//! ## Variant field attributes
25//!
26//! Attributes that can be used on fields of enum variants.
27//!
28//! - `flatten = [...]`
29//!
30//!     Flattens the field into instruction codes for every specified value. This attribute is
31//!     intended to be used for optimizing some values and falling back to using an operand for any
32//!     non-specified value. If you want to flatten all values, use the `flatten_all` attribute
33//!     instead.
34//!
35//!     See the [example](#example) below for more information on how to use this attribute.
36//!
37//! - `flatten_all = [...]`
38//!
39//!     Flattens the enum variant into instruction codes for every specified value. Note that every
40//!     possible value has to be specified. If you only want to flatten some values, use the
41//!     `flatten` attribute instead.
42//!
43//!     See the [example](#example) below for more information on how to use this attribute.
44//!
45//! ## Field attributes
46//!
47//! Attributes that can be used on struct fields or fields of enum variants.
48//!
49//! - `skip`
50//!
51//!     Skips encoding and decoding of the field. For decoding, the value from
52//!     `std::default::Default` is used.
53//!
54//! # Example
55//!
56//! ```rust
57//! use bytecoding::Bytecode;
58//!
59//! #[derive(Debug, PartialEq, Eq, Bytecode)]
60//! struct Operand {
61//!     value1: u8,
62//!     value2: u16,
63//! }
64//!
65//! #[derive(Debug, PartialEq, Eq, Bytecode)]
66//! #[bytecode(type = u8)]
67//! enum Instruction {
68//!     Add,
69//!     Sub,
70//!     Jump(u8),
71//!     Foo(Operand),
72//!
73//!     // This generates four instruction codes without an operand for the values 0 to 3, and one
74//!     // instruction code with an operand for all remaining values
75//!     Const {
76//!         #[bytecode(flatten = [0, 1, 2, 3])]
77//!         index: u16,
78//!     },
79//!
80//!     // This generates two instruction codes (without an operand):
81//!     // - The first code is for the value `true`
82//!     // - The second code is for the value `false`
83//!     Bool(#[bytecode(flatten_all = [true, false])] bool),
84//! }
85//!
86//! # fn main() -> Result<(), bytecoding::DecodeError> {
87//! let instructions = vec![
88//!     Instruction::Sub,
89//!     Instruction::Add,
90//!     Instruction::Foo(Operand { value1: 20, value2: 30 }),
91//!     Instruction::Jump(42),
92//!     Instruction::Const { index: 0 },
93//!     Instruction::Const { index: 4 },
94//!     Instruction::Bool(true),
95//!     Instruction::Bool(false),
96//! ];
97//!
98//! // Encoding
99//! let mut buf = Vec::new();
100//! for instruction in &instructions {
101//!     instruction.encode(&mut buf);
102//! }
103//! assert_eq!(buf, vec![
104//!     1, // Sub
105//!     0, // Add
106//!     3, 20, 0, 30, // Foo(Operand { value1: 20, value2: 30 })
107//!     2, 42, // Jump(42)
108//!     4, // Const { index: 0 }
109//!     8, 0, 4, // Const { index: 4 }
110//!     9, // Bool(true)
111//!     10, // Bool(false)
112//! ]);
113//!
114//! // Decoding
115//! let mut buf: &[u8] = &buf;
116//! let mut decoded_instructions = Vec::new();
117//! while !buf.is_empty() {
118//!     decoded_instructions.push(Instruction::decode(&mut buf)?);
119//! }
120//! assert_eq!(decoded_instructions, instructions);
121//! # Ok(())
122//! # }
123
124use bytes::{Buf, BufMut};
125use core::fmt;
126use paste::paste;
127use std::error::Error;
128
129/// Derive macro for [`Bytecode`].
130///
131/// See the [module-level documentation](crate) for more information.
132pub use bytecoding_derive::Bytecode;
133
134#[doc(hidden)]
135pub use bytes;
136
137/// Error that can occur while decoding the bytecode.
138#[derive(Debug, Clone, PartialEq, Eq, Hash)]
139pub enum DecodeError {
140    InvalidValue(Box<[u8]>),
141    UnexpectedEnd,
142}
143
144impl Error for DecodeError {}
145
146impl fmt::Display for DecodeError {
147    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148        match self {
149            Self::InvalidValue(v) => write!(f, "Invalid value `{:?}`", v),
150            Self::UnexpectedEnd => f.write_str("Unexpected end"),
151        }
152    }
153}
154
155/// Encode and decode instructions and operands.
156pub trait Bytecode: Sized {
157    /// Encodes the instruction or the operand.
158    ///
159    /// # Example
160    ///
161    /// ```rust
162    /// use bytecoding::Bytecode;
163    ///
164    /// #[derive(Bytecode)]
165    /// #[bytecode(type = u8)]
166    /// enum Instruction {
167    ///     Add,
168    ///     Sub,
169    ///     Jump(u8),
170    /// }
171    ///
172    /// let mut buf = Vec::new();
173    /// Instruction::Sub.encode(&mut buf);
174    /// Instruction::Add.encode(&mut buf);
175    /// Instruction::Jump(42).encode(&mut buf);
176    ///
177    /// assert_eq!(buf, vec![1, 0, 2, 42]);
178    /// ```
179    fn encode<B: BufMut>(&self, buf: &mut B);
180
181    /// Decodes a instruction or an operand from the given buffer.
182    ///
183    /// Advances the buffer to the next instruction.
184    ///
185    /// # Example
186    ///
187    /// ```rust
188    /// use bytecoding::Bytecode;
189    ///
190    /// #[derive(Debug, PartialEq, Eq, Bytecode)]
191    /// #[bytecode(type = u8)]
192    /// enum Instruction {
193    ///     Add,
194    ///     Sub,
195    ///     Jump(u8),
196    /// }
197    ///
198    /// # fn main() -> Result<(), bytecoding::DecodeError> {
199    /// let mut buf: &[u8] = &[1, 0, 2, 42];
200    /// let instructions = [
201    ///     Instruction::decode(&mut buf)?,
202    ///     Instruction::decode(&mut buf)?,
203    ///     Instruction::decode(&mut buf)?,
204    /// ];
205    ///
206    /// assert_eq!(instructions, [Instruction::Sub, Instruction::Add, Instruction::Jump(42)]);
207    /// # Ok(())
208    /// # }
209    /// ```
210    fn decode<B: Buf>(buf: &mut B) -> Result<Self, DecodeError>;
211}
212
213macro_rules! impl_integer_bytecode {
214    ($($type_ident:ident),*) => {
215        $(impl Bytecode for $type_ident {
216            fn encode<B: BufMut>(&self, buf: &mut B) {
217                paste! { buf.[<put_ $type_ident>](*self); }
218            }
219
220            fn decode<B: Buf>(buf: &mut B) -> Result<Self, DecodeError> {
221                const NUM_BYTES: usize = ($type_ident::BITS / 8) as usize;
222                if buf.remaining() < NUM_BYTES {
223                    return Err(DecodeError::UnexpectedEnd);
224                }
225                Ok(paste! { buf.[<get_ $type_ident>]() })
226            }
227        })*
228    };
229}
230
231impl_integer_bytecode!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128);