use std::cell::RefCell;
use std::cmp::Reverse;
use std::future::Future;
use std::rc::Rc;
use std::sync::Arc;
use std::task::{Context, Waker};
use rand::rngs::StdRng;
use rand::{RngCore, SeedableRng};
use crate::event::{new_event, EventAwaitable, EventTrigger};
use crate::executor::{make_waker, ProcessEntry, SimState};
use crate::process::{spawn_with_handle, ProcessHandle};
use crate::rng::RandomSource;
use crate::timeout::Timeout;
type SharedRng = Rc<RefCell<Box<dyn RandomSource>>>;
pub struct SimEnv {
state: Rc<RefCell<SimState>>,
rng: SharedRng,
}
#[derive(Clone)]
pub struct EnvHandle {
state: Rc<RefCell<SimState>>,
rng: SharedRng,
}
impl Default for SimEnv {
fn default() -> Self {
Self::new()
}
}
impl std::fmt::Debug for SimEnv {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut d = f.debug_struct("SimEnv");
if let Ok(state) = self.state.try_borrow() {
let live = state.processes.iter().filter(|p| p.is_some()).count();
d.field("now", &state.current_time)
.field("queued_events", &state.event_queue.len())
.field("processes", &live);
}
d.finish_non_exhaustive()
}
}
impl std::fmt::Debug for EnvHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut d = f.debug_struct("EnvHandle");
if let Ok(state) = self.state.try_borrow() {
d.field("now", &state.current_time);
}
d.finish_non_exhaustive()
}
}
impl SimEnv {
#[must_use]
pub fn new() -> Self {
SimEnv::from_source(Box::new(StdRng::from_os_rng()))
}
#[must_use]
pub fn with_seed(seed: u64) -> Self {
SimEnv::from_source(Box::new(StdRng::seed_from_u64(seed)))
}
#[must_use]
pub fn with_source<R: RandomSource + 'static>(source: R) -> Self {
SimEnv::from_source(Box::new(source))
}
fn from_source(source: Box<dyn RandomSource>) -> Self {
SimEnv {
state: Rc::new(RefCell::new(SimState::new())),
rng: Rc::new(RefCell::new(source)),
}
}
pub fn set_seed(&mut self, seed: u64) {
self.rng.borrow_mut().reseed(seed);
}
#[must_use]
pub fn handle(&self) -> EnvHandle {
EnvHandle {
state: Rc::clone(&self.state),
rng: Rc::clone(&self.rng),
}
}
#[must_use]
pub fn now(&self) -> f64 {
self.state.borrow().current_time
}
pub fn spawn<F>(&self, future: F) -> ProcessHandle<F::Output>
where
F: Future + 'static,
F::Output: 'static,
{
self.handle().spawn(future)
}
#[must_use = "futures do nothing unless awaited"]
pub fn timeout(&self, delay: f64) -> Timeout {
self.handle().timeout(delay)
}
#[must_use]
pub fn event(&self) -> (EventTrigger, EventAwaitable) {
new_event()
}
pub fn run(&mut self) {
self.drain_pending_spawns();
self.poll_ready();
loop {
let next = self.state.borrow_mut().event_queue.pop();
match next {
None => break,
Some(Reverse(entry)) => {
self.state.borrow_mut().current_time = entry.time;
entry.waker.wake();
self.drain_pending_spawns();
self.poll_ready();
}
}
}
}
pub fn run_until(&mut self, until: f64) {
self.drain_pending_spawns();
self.poll_ready();
loop {
let should_stop = {
let state = self.state.borrow();
state
.event_queue
.peek()
.is_none_or(|Reverse(e)| e.time > until)
};
if should_stop {
let mut state = self.state.borrow_mut();
state.current_time = until.max(state.current_time);
break;
}
let next = self.state.borrow_mut().event_queue.pop();
if let Some(Reverse(entry)) = next {
self.state.borrow_mut().current_time = entry.time;
entry.waker.wake();
self.drain_pending_spawns();
self.poll_ready();
}
}
}
fn drain_pending_spawns(&self) {
let spawns: Vec<_> = std::mem::take(&mut self.state.borrow_mut().pending_spawns);
if spawns.is_empty() {
return;
}
let ids: Vec<usize> = spawns.iter().map(|(id, _)| *id).collect();
{
let mut state = self.state.borrow_mut();
let ready_queue = Arc::clone(&state.ready_queue);
for (id, future) in spawns {
let waker = make_waker(id, Arc::clone(&ready_queue));
if id >= state.processes.len() {
state.processes.resize_with(id + 1, || None);
}
state.processes[id] = Some(ProcessEntry { future, waker });
}
}
let rq = Arc::clone(&self.state.borrow().ready_queue);
rq.lock().unwrap().extend(ids);
}
fn poll_ready(&self) {
let ready_queue = Arc::clone(&self.state.borrow().ready_queue);
loop {
let ready: Vec<usize> = std::mem::take(&mut *ready_queue.lock().unwrap());
if ready.is_empty() {
break;
}
for id in ready {
let entry = self.state.borrow_mut().processes[id].take();
if let Some(mut entry) = entry {
let mut cx = Context::from_waker(&entry.waker);
if entry.future.as_mut().poll(&mut cx).is_pending() {
self.state.borrow_mut().processes[id] = Some(entry);
}
self.drain_pending_spawns();
}
}
}
}
}
impl Drop for SimEnv {
fn drop(&mut self) {
let leftovers = self.state.try_borrow_mut().ok().map(|mut state| {
(
std::mem::take(&mut state.processes),
std::mem::take(&mut state.pending_spawns),
)
});
drop(leftovers);
}
}
impl EnvHandle {
#[must_use]
pub fn now(&self) -> f64 {
self.state.borrow().current_time
}
#[must_use = "an RngGuard holds a mutable borrow of the env RNG; bind or use it directly"]
pub fn rng(&self) -> impl rand::RngCore + '_ {
RngGuard(self.rng.borrow_mut())
}
#[must_use = "futures do nothing unless awaited"]
pub fn timeout(&self, delay: f64) -> Timeout {
assert!(
delay >= 0.0 && delay.is_finite(),
"timeout delay must be finite and non-negative (got {delay})"
);
let deadline = self.state.borrow().current_time + delay;
Timeout::new(deadline, self.clone())
}
#[must_use]
pub fn event(&self) -> (EventTrigger, EventAwaitable) {
new_event()
}
pub fn spawn<F>(&self, future: F) -> ProcessHandle<F::Output>
where
F: Future + 'static,
F::Output: 'static,
{
let (wrapped, handle) = spawn_with_handle(future);
let mut state = self.state.borrow_mut();
let id = state.alloc_process_id();
state.pending_spawns.push((id, wrapped));
handle
}
pub(crate) fn schedule_wakeup(&self, deadline: f64, waker: Waker) {
self.state.borrow_mut().schedule_wakeup(deadline, waker);
}
}
struct RngGuard<'a>(std::cell::RefMut<'a, Box<dyn RandomSource>>);
impl RngCore for RngGuard<'_> {
fn next_u32(&mut self) -> u32 {
(**self.0).next_u32()
}
fn next_u64(&mut self) -> u64 {
(**self.0).next_u64()
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
(**self.0).fill_bytes(dest)
}
}