2 unstable releases
0.1.0 | Mar 15, 2022 |
---|---|
0.0.1 | Mar 8, 2022 |
#1581 in Rust patterns
Used in 3 crates
(via pk_compiler)
13KB
117 lines
bytecoding
Derive macro for encoding and decoding instructions and operands as bytecode.
Documentation
License
Licensed under either of Apache License, Version 2.0 or MIT License at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
lib.rs
:
Derive macro for encoding and decoding instructions and operands as bytecode.
Derive macro
Enum attributes
Attributes that can be used on enums.
-
type = ...
(required)Sets which type is used for the instruction code. Possible values are
u8
,u16
,u32
, andu64
.
Variant attributes
Attributes that can be used on enum variants.
-
code = ...
Sets the instruction codes for this enum variant. A code has to be specified for every instruction this variant generates. If the variant only generates one instruction, then a single number can be used for the
code
attribute (instead of a list of numbers).
Variant field attributes
Attributes that can be used on fields of enum variants.
-
flatten = [...]
Flattens the field into instruction codes for every specified value. This attribute is intended to be used for optimizing some values and falling back to using an operand for any non-specified value. If you want to flatten all values, use the
flatten_all
attribute instead.See the example below for more information on how to use this attribute.
-
flatten_all = [...]
Flattens the enum variant into instruction codes for every specified value. Note that every possible value has to be specified. If you only want to flatten some values, use the
flatten
attribute instead.See the example below for more information on how to use this attribute.
Field attributes
Attributes that can be used on struct fields or fields of enum variants.
-
skip
Skips encoding and decoding of the field. For decoding, the value from
std::default::Default
is used.
Example
use bytecoding::Bytecode;
#[derive(Debug, PartialEq, Eq, Bytecode)]
struct Operand {
value1: u8,
value2: u16,
}
#[derive(Debug, PartialEq, Eq, Bytecode)]
#[bytecode(type = u8)]
enum Instruction {
Add,
Sub,
Jump(u8),
Foo(Operand),
// This generates four instruction codes without an operand for the values 0 to 3, and one
// instruction code with an operand for all remaining values
Const {
#[bytecode(flatten = [0, 1, 2, 3])]
index: u16,
},
// This generates two instruction codes (without an operand):
// - The first code is for the value `true`
// - The second code is for the value `false`
Bool(#[bytecode(flatten_all = [true, false])] bool),
}
let instructions = vec![
Instruction::Sub,
Instruction::Add,
Instruction::Foo(Operand { value1: 20, value2: 30 }),
Instruction::Jump(42),
Instruction::Const { index: 0 },
Instruction::Const { index: 4 },
Instruction::Bool(true),
Instruction::Bool(false),
];
// Encoding
let mut buf = Vec::new();
for instruction in &instructions {
instruction.encode(&mut buf);
}
assert_eq!(buf, vec![
1, // Sub
0, // Add
3, 20, 0, 30, // Foo(Operand { value1: 20, value2: 30 })
2, 42, // Jump(42)
4, // Const { index: 0 }
8, 0, 4, // Const { index: 4 }
9, // Bool(true)
10, // Bool(false)
]);
// Decoding
let mut buf: &[u8] = &buf;
let mut decoded_instructions = Vec::new();
while !buf.is_empty() {
decoded_instructions.push(Instruction::decode(&mut buf)?);
}
assert_eq!(decoded_instructions, instructions);
Dependencies
~2.5MB
~51K SLoC