rustyapple/util.rs

170 lines
3.7 KiB
Rust

//
// sprocketnes/util.rs
//
// Author: Patrick Walton
//
use std::io::File;
use std::libc::{c_int, c_void, time_t};
use std::ptr::null;
//
// A tiny custom serialization infrastructure, used for savestates.
//
// TODO: Use the standard library's ToBytes and add a FromBytes -- or don't; this is such a small
// amount of code it barely seems worth it.
//
pub trait Save {
fn save(&mut self, fd: &mut File);
fn load(&mut self, fd: &mut File);
}
impl Save for u8 {
fn save(&mut self, fd: &mut File) { fd.write([ *self ]) }
fn load(&mut self, fd: &mut File) { let mut buf = [ 0 ]; fd.read(buf); *self = buf[0]; }
}
impl Save for u16 {
fn save(&mut self, fd: &mut File) { fd.write([ *self as u8, (*self >> 8) as u8 ]) }
fn load(&mut self, fd: &mut File) {
let mut buf = [ 0, 0 ];
fd.read(buf);
*self = (buf[0] as u16) | ((buf[1] as u16) << 8);
}
}
impl Save for u64 {
fn save(&mut self, fd: &mut File) {
let mut buf = [ 0, ..8 ];
for i in range(0, 8) {
buf[i] = ((*self) >> (i * 8)) as u8;
}
fd.write(buf);
}
fn load(&mut self, fd: &mut File) {
let mut buf = [ 0, ..8 ];
fd.read(buf);
*self = 0;
for i in range(0, 8) {
*self = *self | (buf[i] as u64 << (i * 8));
}
}
}
impl<'a> Save for &'a mut [u8] {
fn save(&mut self, fd: &mut File) {
fd.write(*self);
}
fn load(&mut self, fd: &mut File) {
fd.read(*self);
}
}
impl Save for bool {
fn save(&mut self, fd: &mut File) { fd.write([ if *self { 0 } else { 1 } ]) }
fn load(&mut self, fd: &mut File) {
let mut val: [u8, ..1] = [ 0 ];
fd.read(val);
*self = val[0] != 0
}
}
// A convenience macro to save and load entire structs.
macro_rules! save_struct(
($name:ident { $($field:ident),* }) => (
impl Save for $name {
fn save(&mut self, fd: &mut File) {
$(self.$field.save(fd);)*
}
fn load(&mut self, fd: &mut File) {
$(self.$field.load(fd);)*
}
}
)
)
macro_rules! save_enum(
($name:ident { $val_0:ident, $val_1:ident }) => (
impl Save for $name {
fn save(&mut self, fd: &mut File) {
let mut val: u8 = match *self { $val_0 => 0, $val_1 => 1 };
val.save(fd)
}
fn load(&mut self, fd: &mut File) {
let mut val: u8 = 0;
val.load(fd);
*self = if val == 0 { $val_0 } else { $val_1 };
}
}
)
)
//
// Random number generation
//
pub struct Xorshift {
x: u32,
y: u32,
z: u32,
w: u32,
}
impl Xorshift {
pub fn new() -> Xorshift {
Xorshift { x: 123456789, y: 362436069, z: 521288629, w: 88675123 }
}
pub fn next(&mut self) -> u32 {
let t = self.x ^ (self.x << 11);
self.x = self.y; self.y = self.z; self.z = self.w;
self.w = self.w ^ (self.w >> 19) ^ (t ^ (t >> 8));
self.w
}
}
//
// Simple assertions
//
#[cfg(debug)]
pub fn debug_assert(cond: bool, msg: &str) {
if !cond {
println(msg);
}
}
#[cfg(not(debug))]
pub fn debug_assert(_: bool, _: &str) {}
#[cfg(debug)]
pub fn debug_print(msg: &str) {
println(msg);
}
#[cfg(not(debug))]
pub fn debug_print(_: &str) {}
//
// Bindings for `gettimeofday(2)`
//
struct timeval {
tv_sec: time_t,
tv_usec: u32,
}
extern {
fn gettimeofday(tp: *mut timeval, tzp: *c_void) -> c_int;
}
pub fn current_time_millis() -> u64 {
unsafe {
let mut tv = timeval { tv_sec: 0, tv_usec: 0 };
gettimeofday(&mut tv, null());
(tv.tv_sec as u64) * 1000 + (tv.tv_usec as u64) / 1000
}
}