#instructions #codec #bytecode #decoding #operands #macro #enums

bytecoding

Derive macro for encoding and decoding instructions and operands as bytecode

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)

Apache-2.0 OR MIT

13KB
117 lines

bytecoding

Crate Docs License

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, and u64.

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