diff --git a/examples/basic.rs b/examples/basic.rs index 76d3730..2c59592 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -1,9 +1,16 @@ +use std::env; use slipwave::time::{State, Loop}; +use slipwave::log::{Logger}; +use slipwave::vcr::{ComputeObject}; fn main() { println!("Slipwave Engine | 2021 | Skye Terran"); + // Create a logger + let log_time = Logger::new("time"); + // create a sim loop + log_time.print("Creating sim loop..."); let mut sim = Loop::new(); // set the loop update interval @@ -15,18 +22,24 @@ fn main() { // datastream let mut x: i32 = 0; + // Create a compute object + let args: Vec = env::args().collect(); + let file_path: &String = &args[1]; + // execute the sim loop + log_time.print("Executing loop..."); loop { + // step the sim forward sim.step(); // update logic goes here if sim.is_awake() { - - //x += 1; - //println!("x: {}", x); + // Create and execute a compute object + let mut vm = ComputeObject::from_file(file_path); + println!("{:?}", vm.execute()); } - sim.get_state().debug_time(); + //sim.get_state().debug_time(); // display logic goes here // problem: the timestep is not what we want here. we need to get the elapsed time diff --git a/src/lib.rs b/src/lib.rs index 6241673..6935fc2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,3 @@ pub mod time; -pub mod log; \ No newline at end of file +pub mod log; +pub mod vcr; \ No newline at end of file diff --git a/src/log.rs b/src/log.rs index 2f7e8c9..6767cb7 100644 --- a/src/log.rs +++ b/src/log.rs @@ -1,11 +1,13 @@ pub struct Logger { - categories: Vec + name: String } impl Logger { - pub fn print(self, output: &String, category: &String) { - if self.categories.contains(category) { - println!(output); - } + pub fn new(name: &str) -> Logger { + Logger { name: name.to_string() } + } + + pub fn print(&self, output: &str) { + println!("[{}] {}", self.name, output); } } \ No newline at end of file diff --git a/src/vcr.rs b/src/vcr.rs index e69de29..1dc9bb4 100644 --- a/src/vcr.rs +++ b/src/vcr.rs @@ -0,0 +1,202 @@ +use std::io; +use std::fs; +use std::fs::File; +use std::io::Read; + +enum VCROperationKind { + Generic, + Type, + Value +} + +pub struct ComputeObject { + instructions: Vec, + values: Vec +} + +impl ComputeObject { + pub fn from_file(file_path: &String) -> ComputeObject { + ComputeObject { + instructions: get_file_as_byte_vec(file_path), + values: vec![] + } + } + + pub fn execute(&mut self) -> &Vec { + //println!("Executing bytecode instructions...\n"); + let mut iter = self.instructions.iter(); + + // Handle literals + let mut op_type = VCROperationKind::Generic; + let mut literal = [0u8; 4]; + let mut lit_digit = 0; + + // Handle each opcode in order + loop { + let byte_opt = iter.next(); + + // Contextually handle opcodes depending on their type + match op_type { + // Treat the opcode as a literal type declaration + VCROperationKind::Type => { + // Consume the literal type + let byte = byte_opt.unwrap(); + + // The following opcodes are expected to be a literal value + op_type = VCROperationKind::Value; + }, + // Treat the opcode as a literal value + VCROperationKind::Value => { + if byte_opt.is_some() { + let byte = byte_opt.unwrap(); + // Record another of the literal's bytes + literal[lit_digit] = *byte; + + // Continue consuming the literal + if lit_digit >= 3 { + let num = f32::from_bits(as_u32_be(&literal)); + self.values.push(num); + //println!("LIT {:?}", num); + //println!("Values: {:?}\n", self.values); + op_type = VCROperationKind::Generic; + lit_digit = 0; + } else { + lit_digit += 1; + } + } else { + break; + } + }, + // Treat the opcode as a generic command + _ => { + if byte_opt.is_some() { + let byte = byte_opt.unwrap(); + match byte { + 0x01 => op_type = VCROperationKind::Type, + 0x02 => swap(&mut self.values), + 0x03 => del(&mut self.values), + 0x04 => copy(&mut self.values), + 0x10 => add(&mut self.values), + 0x11 => sub(&mut self.values), + 0x12 => mul(&mut self.values), + 0x19 => floor(&mut self.values), + _ => break + } + // DEBUG - show the value stack upon every generic command + if let VCROperationKind::Generic = op_type { + //println!("Values: {:?}\n", self.values); + } + } else { + break; + } + } + } + } + self.instructions.clear(); + &self.values + } +} + + +fn add(values: &mut Vec) { + //println!("ADD"); + let b_opt = values.pop(); + let a_opt = values.pop(); + if a_opt.is_some() && b_opt.is_some() { + let a = a_opt.unwrap(); + let b = b_opt.unwrap(); + values.push(a + b); + } else { + //println!("Not enough values."); + } +} + +fn sub(values: &mut Vec) { + //println!("SUB"); + let b_opt = values.pop(); + let a_opt = values.pop(); + if a_opt.is_some() && b_opt.is_some() { + let a = a_opt.unwrap(); + let b = b_opt.unwrap(); + values.push(a - b); + } else { + //println!("Not enough values."); + } +} + +fn mul(values: &mut Vec) { + //println!("MUL"); + let b_opt = values.pop(); + let a_opt = values.pop(); + if a_opt.is_some() && b_opt.is_some() { + let a = a_opt.unwrap(); + let b = b_opt.unwrap(); + values.push(a * b); + } else { + //println!("Not enough values."); + } +} + +fn del(values: &mut Vec) { + //println!("DEL"); + values.pop(); +} + +fn copy(values: &mut Vec) { + //println!("COPY"); + let a_opt = values.pop(); + if a_opt.is_some() { + let a = a_opt.unwrap(); + values.push(a); + values.push(a); + } else { + //println!("Not enough values."); + } +} + +fn swap(values: &mut Vec) { + //println!("SWAP"); + let b_opt = values.pop(); + let a_opt = values.pop(); + if a_opt.is_some() && b_opt.is_some() { + let a = a_opt.unwrap(); + let b = b_opt.unwrap(); + values.push(b); + values.push(a); + } else { + //println!("Not enough values."); + } +} + +fn floor(values: &mut Vec) { + //println!("FLOOR"); + let a_opt = values.pop(); + if a_opt.is_some() { + let a = a_opt.unwrap(); + let a = a.floor(); + values.push(a); + } +} + +fn as_u32_be(array: &[u8; 4]) -> u32 { + ((array[0] as u32) << 24) + + ((array[1] as u32) << 16) + + ((array[2] as u32) << 8) + + ((array[3] as u32) << 0) +} + +fn as_u32_le(array: &[u8; 4]) -> u32 { + ((array[0] as u32) << 0) + + ((array[1] as u32) << 8) + + ((array[2] as u32) << 16) + + ((array[3] as u32) << 24) +} + +fn get_file_as_byte_vec(filename: &String) -> Vec { + let mut f = File::open(&filename).expect("no file found"); + let metadata = fs::metadata(&filename).expect("unable to read metadata"); + let mut buffer = vec![0; metadata.len() as usize]; + f.read(&mut buffer).expect("buffer overflow"); + + buffer +} \ No newline at end of file