Generic mutation scheduling system

IO adapted to use it
Also, Atoms can now dispatch type-erased requests
This commit is contained in:
2023-09-14 22:54:42 +01:00
parent 8c866967a9
commit 3c0056c2db
51 changed files with 991 additions and 379 deletions

119
src/systems/io/service.rs Normal file
View File

@@ -0,0 +1,119 @@
#[allow(unused)] // for doc
use std::io::{BufReader, Read, Write};
use rust_embed::RustEmbed;
use trait_set::trait_set;
use super::bindings::io_bindings;
use super::flow::{IOCmd, IOCmdHandlePack};
use super::instances::{ReadCmd, Sink, Source, WriteCmd};
use crate::facade::{IntoSystem, System};
use crate::foreign::cps_box::{init_cps, CPSBox};
use crate::foreign::Atomic;
use crate::interpreter::HandlerTable;
use crate::pipeline::file_loader::embed_to_map;
use crate::sourcefile::{FileEntry, FileEntryKind, Import};
use crate::systems::codegen::call;
use crate::systems::scheduler::{SeqScheduler, SharedHandle};
use crate::Location;
/// A shared type for sinks and sources
pub enum Stream {
/// A Source, aka. a BufReader
Source(Source),
/// A Sink, aka. a Writer
Sink(Sink),
}
trait_set! {
/// The table of default streams to be overlain on the I/O module, typicially
/// stdin, stdout, stderr.
pub trait StreamTable<'a> = IntoIterator<Item = (&'a str, Stream)>
}
#[derive(RustEmbed)]
#[folder = "src/systems/io"]
#[prefix = "system/"]
#[include = "*.orc"]
struct IOEmbed;
/// A streaming I/O service for interacting with Rust's [Write] and [Read]
/// traits.
pub struct Service<'a, ST: IntoIterator<Item = (&'a str, Stream)>> {
scheduler: SeqScheduler,
global_streams: ST,
}
impl<'a, ST: IntoIterator<Item = (&'a str, Stream)>> Service<'a, ST> {
/// Construct a new instance of the service
pub fn new(scheduler: SeqScheduler, global_streams: ST) -> Self {
Self { scheduler, global_streams }
}
}
impl<'a, ST: IntoIterator<Item = (&'a str, Stream)>> IntoSystem<'static>
for Service<'a, ST>
{
fn into_system(self, i: &crate::Interner) -> crate::facade::System<'static> {
let scheduler = self.scheduler.clone();
let mut handlers = HandlerTable::new();
handlers.register(move |cps: &CPSBox<IOCmdHandlePack<ReadCmd>>| {
let (IOCmdHandlePack { cmd, handle }, succ, fail, tail) = cps.unpack3();
let (cmd, succ1, fail1) = (*cmd, succ.clone(), fail.clone());
let result = scheduler.schedule(
handle.clone(),
move |mut stream, cancel| {
let ret = cmd.execute(&mut stream, cancel);
(stream, ret)
},
move |stream, res, _cancel| (stream, res.dispatch(succ1, fail1)),
|stream| (stream, Vec::new()),
);
match result {
Ok(cancel) =>
Ok(call(tail.clone(), vec![init_cps(1, cancel).wrap()]).wrap()),
Err(e) => Ok(call(fail.clone(), vec![e.atom_exi()]).wrap()),
}
});
let scheduler = self.scheduler.clone();
handlers.register(move |cps: &CPSBox<IOCmdHandlePack<WriteCmd>>| {
let (IOCmdHandlePack { cmd, handle }, succ, fail, tail) = cps.unpack3();
let (cmd, succ1, fail1) = (cmd.clone(), succ.clone(), fail.clone());
let result = scheduler.schedule(
handle.clone(),
move |mut stream, cancel| {
let ret = cmd.execute(&mut stream, cancel);
(stream, ret)
},
move |stream, res, _cancel| (stream, res.dispatch(succ1, fail1)),
|stream| (stream, Vec::new()),
);
match result {
Ok(cancel) =>
Ok(call(tail.clone(), vec![init_cps(1, cancel).wrap()]).wrap()),
Err(e) => Ok(call(fail.clone(), vec![e.atom_exi()]).wrap()),
}
});
let streams = self.global_streams.into_iter().map(|(n, stream)| {
let handle = match stream {
Stream::Sink(sink) =>
Box::new(SharedHandle::wrap(sink)) as Box<dyn Atomic>,
Stream::Source(source) => Box::new(SharedHandle::wrap(source)),
};
(n, handle)
});
System {
handlers,
name: vec!["system".to_string(), "io".to_string()],
constants: io_bindings(i, streams).unwrap_tree(),
code: embed_to_map::<IOEmbed>(".orc", i),
prelude: vec![FileEntry {
locations: vec![Location::Unknown],
kind: FileEntryKind::Import(vec![Import {
location: Location::Unknown,
path: vec![i.i("system"), i.i("io"), i.i("prelude")],
name: None,
}]),
}],
}
}
}