206 lines
5.7 KiB
Rust
206 lines
5.7 KiB
Rust
|
use crate::value::Value;
|
||
|
use crate::vm::{Creature, Panic};
|
||
|
use ran::ran_u8;
|
||
|
use std::collections::{HashMap, VecDeque};
|
||
|
|
||
|
const ANIMALS: [&str; 24] = [
|
||
|
"turtle",
|
||
|
"tortoise",
|
||
|
"hare",
|
||
|
"squirrel",
|
||
|
"hawk",
|
||
|
"woodpecker",
|
||
|
"cardinal",
|
||
|
"coyote",
|
||
|
"raccoon",
|
||
|
"rat",
|
||
|
"axolotl",
|
||
|
"cormorant",
|
||
|
"duck",
|
||
|
"orca",
|
||
|
"humbpack",
|
||
|
"tern",
|
||
|
"quokka",
|
||
|
"koala",
|
||
|
"kangaroo",
|
||
|
"zebra",
|
||
|
"hyena",
|
||
|
"giraffe",
|
||
|
"leopard",
|
||
|
"lion",
|
||
|
];
|
||
|
|
||
|
#[derive(Debug, Clone, PartialEq)]
|
||
|
enum Status {
|
||
|
Empty,
|
||
|
Borrowed,
|
||
|
Nested(Creature),
|
||
|
}
|
||
|
|
||
|
#[derive(Debug, Clone, PartialEq)]
|
||
|
struct Zoo {
|
||
|
procs: Vec<Status>,
|
||
|
empty: Vec<usize>,
|
||
|
ids: HashMap<&'static str, usize>,
|
||
|
dead: Vec<&'static str>,
|
||
|
}
|
||
|
|
||
|
impl Zoo {
|
||
|
pub fn new() -> Zoo {
|
||
|
Zoo {
|
||
|
procs: vec![],
|
||
|
empty: vec![],
|
||
|
ids: HashMap::new(),
|
||
|
dead: vec![],
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn put(&mut self, mut proc: Creature) -> &'static str {
|
||
|
if self.empty.is_empty() {
|
||
|
let rand = ran_u8() as usize % 24;
|
||
|
let idx = self.procs.len();
|
||
|
let id = format!("{}_{idx}", ANIMALS[rand]).leak();
|
||
|
proc.id = id;
|
||
|
self.procs.push(Status::Nested(proc));
|
||
|
self.ids.insert(id, idx);
|
||
|
id
|
||
|
} else {
|
||
|
let idx = self.empty.pop().unwrap();
|
||
|
let rand = ran_u8() as usize % 24;
|
||
|
let id = format!("{}_{idx}", ANIMALS[rand]).leak();
|
||
|
proc.id = id;
|
||
|
self.ids.insert(id, idx);
|
||
|
self.procs[idx] = Status::Nested(proc);
|
||
|
id
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn kill(&mut self, id: &'static str) {
|
||
|
if let Some(idx) = self.ids.get(id) {
|
||
|
self.procs[*idx] = Status::Empty;
|
||
|
self.empty.push(*idx);
|
||
|
self.ids.remove(&id);
|
||
|
self.dead.push(id);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn catch(&mut self, id: &'static str) -> Creature {
|
||
|
if let Some(idx) = self.ids.get(id) {
|
||
|
let mut proc = Status::Borrowed;
|
||
|
std::mem::swap(&mut proc, &mut self.procs[*idx]);
|
||
|
let Status::Nested(proc) = proc else {
|
||
|
unreachable!("tried to borrow an empty or already-borrowed process");
|
||
|
};
|
||
|
proc
|
||
|
} else {
|
||
|
unreachable!("tried to borrow a non-existent process");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn release(&mut self, proc: Creature) {
|
||
|
let id = proc.id;
|
||
|
if let Some(idx) = self.ids.get(id) {
|
||
|
let mut proc = Status::Nested(proc);
|
||
|
std::mem::swap(&mut proc, &mut self.procs[*idx]);
|
||
|
} else {
|
||
|
unreachable!("tried to return a process the world doesn't know about");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub struct World {
|
||
|
procs: Zoo,
|
||
|
mbxes: HashMap<String, VecDeque<Value>>,
|
||
|
active: Creature,
|
||
|
// TODO: we need a lifetime here
|
||
|
main: &'static str,
|
||
|
}
|
||
|
|
||
|
impl World {
|
||
|
pub fn new(proc: Creature) -> World {
|
||
|
let mut creatures = Zoo::new();
|
||
|
let id = creatures.put(proc);
|
||
|
let caught = creatures.catch(id);
|
||
|
World {
|
||
|
procs: creatures,
|
||
|
mbxes: HashMap::new(),
|
||
|
active: caught,
|
||
|
main: id,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn spawn(&mut self, proc: Creature) -> Value {
|
||
|
let id = self.procs.put(proc);
|
||
|
Value::Keyword(id)
|
||
|
}
|
||
|
|
||
|
pub fn send_msg(&mut self, id: &'static str, msg: Value) {
|
||
|
let mbx = self.mbxes.get_mut(id).unwrap();
|
||
|
mbx.push_back(msg);
|
||
|
}
|
||
|
|
||
|
pub fn sleep(&mut self, id: &'static str) {
|
||
|
// check if the id is the actually active process
|
||
|
// return it to the nursery
|
||
|
// get the next process from the nursery
|
||
|
}
|
||
|
|
||
|
pub fn get_msg(&self, id: &'static str) -> Option<(usize, Value)> {
|
||
|
// check if the id is of the active process
|
||
|
todo!()
|
||
|
}
|
||
|
|
||
|
pub fn match_msg(&mut self, id: &'static str, idx: usize) {
|
||
|
// again, check for activity
|
||
|
// delete the message at idx, which we gave along with the value as the tuple in get_msg
|
||
|
}
|
||
|
|
||
|
pub fn r#yield(&mut self, id: &'static str) {
|
||
|
// check if the id is active
|
||
|
// swap out the currently active process for the next one
|
||
|
}
|
||
|
|
||
|
pub fn panic(&mut self, id: &'static str) {
|
||
|
// TODO: devise some way of linking processes (study the BEAM on this)
|
||
|
// check if the id is active
|
||
|
// check if the process is `main`, and crash the program if it is
|
||
|
// kill the process
|
||
|
// swap out this process for the next one
|
||
|
}
|
||
|
|
||
|
pub fn complete(&mut self, id: &'static str, value: Value) {
|
||
|
// check if the id is active
|
||
|
// check if the process is main
|
||
|
// if it is: stash the value somehow and exit the program cleanly
|
||
|
}
|
||
|
|
||
|
pub fn run(&mut self) -> Result<Value, Panic> {
|
||
|
todo!()
|
||
|
}
|
||
|
|
||
|
// TODO:
|
||
|
// * [ ] Maybe I need to write this from the bottom up?
|
||
|
// What do processes need to do?
|
||
|
// - [ ] send a message to another process
|
||
|
// - [ ] tell the world to spawn a new process, get the pid back
|
||
|
// - [ ] receive its messages (always until something matches, or sleep if nothing matches)
|
||
|
// - [ ] delete a message from the mbx if it's a match (by idx)
|
||
|
// - [ ] yield
|
||
|
// - [ ] panic
|
||
|
// - [ ] complete
|
||
|
// Thus the other side of this looks like:
|
||
|
// * [x] Spawn a process
|
||
|
// * [x]
|
||
|
}
|
||
|
|
||
|
// Okay, some more thinking
|
||
|
// The world and process can't have mutable references to one another
|
||
|
// They will each need an Rc<RefCell<PostOffice>>
|
||
|
// All the message passing and world/proc communication will happen through there
|
||
|
// And ownership goes World -> Process A -> World -> Process B
|
||
|
|
||
|
// Both the world and a process will have an endless `loop`.
|
||
|
// But I already have three terms: Zoo, Creature, and World
|
||
|
// That should be enough indirection?
|
||
|
// To solve tomorrow.
|