#![forbid(unsafe_code)]
use glsp::{bail, Engine, EngineBuilder, Expander, GResult, RFn, RGlobal, Root, Sym};
use std::{i32, thread};
use std::collections::{hash_map::DefaultHasher, HashMap};
use std::hash::{Hash, Hasher};
use std::time::{Duration};
#[cfg(not(target_arch = "wasm32"))]
use std::time::{Instant, SystemTime};
mod class;
mod collections;
mod iter;
mod macros;
mod misc;
mod num;
mod pat;
pub(crate) struct Std {
setters: HashMap<Sym, (Sym, bool)>,
opt_setters: HashMap<Sym, (Sym, bool)>,
classmacros: HashMap<Sym, Expander>,
rng: Rng,
ord_rfn: Option<Root<RFn>>,
#[cfg(not(target_arch = "wasm32"))]
start_time: Instant
}
impl RGlobal for Std { }
impl Std {
fn new() -> GResult<Std> {
Ok(Std {
setters: HashMap::new(),
opt_setters: HashMap::new(),
classmacros: HashMap::new(),
rng: Rng::seeded(),
ord_rfn: None,
#[cfg(not(target_arch = "wasm32"))]
start_time: std::time::Instant::now()
})
}
}
#[cfg(not(target_arch = "wasm32"))]
pub fn time() -> f32 {
let std = Std::borrow();
Instant::now().duration_since(std.start_time).as_secs_f32()
}
pub fn sleep(secs: f32) -> GResult<()> {
if secs.is_infinite() || secs.is_nan() || secs < 0.0 || secs as i32 > i32::MAX {
bail!("{} is not an appropriate duration", secs);
}
thread::sleep(Duration::from_secs_f32(secs));
Ok(())
}
pub(crate) struct Rng {
x: u32,
y: u32,
z: u32,
w: u32
}
impl Rng {
fn seeded() -> Rng {
let mut rng = Rng {
x: 0,
y: 0,
z: 0,
w: 0
};
let mut hasher = DefaultHasher::default();
#[cfg(target_arch = "wasm32")] {
42u8.hash(&mut hasher);
}
#[cfg(not(target_arch = "wasm32"))] {
let time = SystemTime::now();
time.hash(&mut hasher);
}
rng.reseed(hasher.finish() as u32 as i32);
rng
}
fn reseed(&mut self, mut seed: i32) {
if seed == 0 {
seed = 1
}
let x = seed as u32;
let y = x.wrapping_mul(48271).wrapping_rem(0x7fffffff);
let z = y.wrapping_mul(48271).wrapping_rem(0x7fffffff);
let w = z.wrapping_mul(48271).wrapping_rem(0x7fffffff);
*self = Rng { x, y, z, w };
for _ in 0 .. 8 {
self.gen_u32();
}
}
fn gen_u32(&mut self) -> u32 {
let Rng { x, y, z, w } = *self;
let t = x ^ x.wrapping_shl(11);
let new_w = w ^ w.wrapping_shr(19) ^ (t ^ t.wrapping_shr(8));
self.x = y;
self.y = z;
self.z = w;
self.w = new_w;
new_w
}
}
pub fn rand_i32() -> i32 {
Std::borrow_mut().rng.gen_u32() as i32
}
pub fn rand_f32() -> f32 {
let rand_u32 = Std::borrow_mut().rng.gen_u32() >> 8;
(rand_u32 as f32) / 16777215.0f32
}
pub fn rand_bool() -> bool {
let rand_u32 = Std::borrow_mut().rng.gen_u32();
let to_shift = (rand_u32 & 0xf) + 4; ((rand_u32 >> (to_shift as usize)) & 1) == 1
}
pub fn rand_reseed(seed: i32) {
Std::borrow_mut().rng.reseed(seed)
}
pub struct Runtime(Engine);
impl Runtime {
pub fn new() -> Runtime {
RuntimeBuilder::new().build()
}
fn with_settings(sandboxed: bool, engine: Engine) -> Runtime {
engine.run(|| {
init_stdlib(sandboxed)
}).unwrap();
Runtime(engine)
}
pub fn run<F, R>(&self, f: F) -> Option<R>
where
F: FnOnce() -> GResult<R>
{
self.0.run(f)
}
}
pub struct RuntimeBuilder {
sandboxed: bool,
engine_builder: EngineBuilder
}
impl RuntimeBuilder {
pub fn new() -> RuntimeBuilder {
RuntimeBuilder {
sandboxed: false,
engine_builder: EngineBuilder::new()
}
}
pub fn sandboxed(self, sandboxed: bool) -> RuntimeBuilder {
RuntimeBuilder {
sandboxed,
..self
}
}
pub fn build(self) -> Runtime {
Runtime::with_settings(self.sandboxed, self.engine_builder.build())
}
}
fn init_stdlib(sandboxed: bool) -> GResult<()> {
glsp::add_rglobal(Std::new()?);
class::init(sandboxed)?;
collections::init(sandboxed)?;
iter::init(sandboxed)?;
macros::init(sandboxed)?;
misc::init(sandboxed)?;
num::init(sandboxed)?;
Std::borrow_mut().ord_rfn = Some(glsp::global("ord")?);
glsp::freeze_transform_fns();
Ok(())
}