use serde::{Deserialize, Serialize};
use std::rc::Rc;
use crate::bytecode::Instruction;
use crate::error::*;
use crate::value::Value;
use crate::var::Variable;
use crate::vm::Vm;
pub const LV2_MAGIC_NUMBER: &[u8] = &[0x7f, b'L', b'V', b'2'];
pub type CallableRef = Rc<dyn CallProtocol>;
pub trait CallProtocol: std::fmt::Debug {
fn module(&self) -> Option<String> {
None
}
fn run(&self, vm: &mut Vm) -> Lovm2Result<()>;
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct CodeObject {
pub name: String,
#[serde(skip_deserializing)]
#[serde(skip_serializing)]
pub loc: Option<String>,
pub uses: Vec<String>,
pub entries: Vec<(usize, usize)>,
pub consts: Vec<Value>,
pub idents: Vec<Variable>,
pub code: Vec<Instruction>,
}
impl CallProtocol for CodeObject {
fn module(&self) -> Option<String> {
Some(self.name.clone())
}
fn run(&self, vm: &mut Vm) -> Lovm2Result<()> {
vm.run_bytecode(&self, 0)
}
}
impl std::default::Default for CodeObject {
fn default() -> Self {
Self {
name: String::new(),
loc: None,
uses: vec![],
entries: vec![],
consts: vec![],
idents: vec![],
code: vec![],
}
}
}
impl CodeObject {
pub fn new() -> Self {
Self::default()
}
pub fn load_from_file<T>(path: T) -> Lovm2Result<Self>
where
T: AsRef<std::path::Path>,
{
use bincode::Options;
use std::fs::File;
use std::io::Read;
let name = path
.as_ref()
.file_stem()
.unwrap()
.to_str()
.unwrap()
.to_string();
let loc = path.as_ref().to_str().unwrap().to_string();
let mut file = File::open(path).or_else(err_from_string)?;
let mut buffer = vec![];
file.read_to_end(&mut buffer).unwrap();
let mut co: CodeObject = bincode::options()
.with_varint_encoding()
.deserialize(&buffer[4..])
.or_else(err_from_string)?;
co.name = name;
co.loc = Some(loc);
Ok(co)
}
pub fn to_bytes(&self) -> Lovm2Result<Vec<u8>> {
use bincode::Options;
let mut buffer = Vec::from(LV2_MAGIC_NUMBER);
let obj: Vec<u8> = bincode::options()
.with_varint_encoding()
.serialize(self)
.or_else(err_from_string)?;
buffer.extend(obj);
Ok(buffer)
}
pub fn store_to_file<T>(&self, path: T) -> Lovm2Result<()>
where
T: AsRef<std::path::Path>,
{
use std::fs::File;
use std::io::Write;
let mut file = File::create(path).or_else(err_from_string)?;
let bytes = self.to_bytes()?;
file.write_all(&bytes).or_else(err_from_string)
}
}
#[derive(Debug)]
pub struct CodeObjectFunction {
offset: usize,
on: Rc<CodeObject>,
}
impl CodeObjectFunction {
pub fn from(on: Rc<CodeObject>, offset: usize) -> Self {
Self { offset, on }
}
}
impl CallProtocol for CodeObjectFunction {
fn module(&self) -> Option<String> {
Some(self.on.name.clone())
}
fn run(&self, vm: &mut Vm) -> Lovm2Result<()> {
vm.run_bytecode(&self.on, self.offset)
}
}