Hello!
I made a Rust proc-macro which will compile and parse your enums and structs to and from a bytecode for you!!!
Check it out and star it if you think it is interesting!
Why
Consider you are writing a VM, and need a bytecode representation for your opcodes, to store it in the VM's memory. You might consider something like this :
pub enum Register{
AX,
BX,
...
}
pub enum Opcode{
Nop,
Hlt,
Add(Register,Register),
AddI(Register,u16),
...
}
If you try to write functions to compile and parse these two enums to a simple bytecode, it would be something like this :
impl Register{
...
fn compile(&self)->Vec<u8>{
match self{
Register::AX => vec![0],
Register::BX => vec![1],
...
}
}
fn parse(bytes:&[u8])->Result<Self,&str>{
match bytes[0]{
1 => Ok(Register::AX),
2 => Ok(Register::BX),
...
_ => Err("Invalid opcode")
}
}
...
}
impl Opcode{
...
fn compile(&self)->Vec<u8>{
match self{
Opcode::Nop => vec![0],
Opcode::Hlt => vec![1],
Opcode::Add(r1,r2) => {
let mut v = Vec::with_capacity(2);
v.extend(&r1.compile());
v.extend(&r2.compile());
v
}
Opcode::AddI(r1,v1) =>{
let mut v = Vec::with_capacity(3);
v.extend(&r1.compile());
v.extend(&v1.to_le_bytes());
v
}
...
}
}
fn parse(bytes:&[u8])->Result<Self,&str>{
match bytes[0]{
1 => Ok(Opcode::Nop),
2 => Ok(Opcode::Hlt),
3 =>{
let r1 = Register::parse(&bytes[1..])?;
...
}
...
_ => Err("Invalid opcode")
}
}
}
Even for the two instructions I have shown, this is pretty long, tedious and boring.
And now consider doing this for at least 25 to upto 100-ish opcodes, as you might need. 😟 😰
And now consider you want to remove a variant or add a variant in the middle of an enum 😰 😱
You will need to shift all the values accordingly, manually.
Not Fun.
The macro will do this for you, and let you concentrate on implementing your VM.
Fun. (hopefully).
Links
The GitHub contains more information and detailed example of usage, so go check it out and ⭐ it !
YJDoc2 / Bytecode
A Rust proc-macro crate which derives functions to compile and parse back enums and structs to and from a bytecode representation
Bytecode
A simple way to derive bytecode for you Enums and Structs.
What is this
This is a crate that provides a proc macro which will derive bytecode representation of your enums and structs, and provides compile and parse functions to convert to and from the bytecode. This also provides necessary traits to do so, in case you want to do it manually.
Note : The values of the fields are compiled as little-endian values, so in the bytecode the smallest byte is at smallest location. The bytecode itself is Big-endian for certain reasons.
Example
Cargo.toml
...
[dependencies]
...
bytecode = {git = "https://github.com/YJDoc2/Bytecode" }
...
Code
use bytecode::{Bytecodable, Bytecode};
#[derive(Bytecode, Debug, PartialEq, Eq)]
pub enum Register {
AX,
BX,
CX,
DX,
}
#[derive
…Thank you!
Top comments (0)