Separated orchid-host and orchid-extension
This is an architectural change that allows me to implment specifics first and generalize along observed symmetries in orchid-base
This commit is contained in:
@@ -1,44 +0,0 @@
|
||||
use std::io::{self, Read, Write};
|
||||
use std::sync::Mutex;
|
||||
use std::{mem, process};
|
||||
|
||||
pub struct SharedChild {
|
||||
child: process::Child,
|
||||
stdin: Mutex<process::ChildStdin>,
|
||||
stdout: Mutex<process::ChildStdout>,
|
||||
}
|
||||
impl SharedChild {
|
||||
pub fn new(cmd: &mut process::Command) -> io::Result<Self> {
|
||||
let mut child = cmd.stdin(process::Stdio::piped()).stdout(process::Stdio::piped()).spawn()?;
|
||||
let stdin = Mutex::new(child.stdin.take().expect("Piped stdin above"));
|
||||
let stdout = Mutex::new(child.stdout.take().expect("Piped stdout above"));
|
||||
Ok(Self { stdin, stdout, child })
|
||||
}
|
||||
|
||||
pub fn send_msg(&self, msg: &[u8]) -> io::Result<()> {
|
||||
send_msg(&mut *self.stdin.lock().unwrap(), msg)
|
||||
}
|
||||
|
||||
pub fn recv_msg(&self) -> io::Result<Vec<u8>> { recv_msg(&mut *self.stdout.lock().unwrap()) }
|
||||
}
|
||||
impl Drop for SharedChild {
|
||||
fn drop(&mut self) { mem::drop(self.child.kill()) }
|
||||
}
|
||||
|
||||
pub fn send_msg(write: &mut impl Write, msg: &[u8]) -> io::Result<()> {
|
||||
write.write_all(&(u32::try_from(msg.len()).unwrap()).to_be_bytes())?;
|
||||
write.write_all(msg)?;
|
||||
write.flush()
|
||||
}
|
||||
|
||||
pub fn recv_msg(read: &mut impl Read) -> io::Result<Vec<u8>> {
|
||||
let mut len = [0u8; 4];
|
||||
read.read_exact(&mut len)?;
|
||||
let len = u32::from_be_bytes(len);
|
||||
let mut msg = vec![0u8; len as usize];
|
||||
read.read_exact(&mut msg)?;
|
||||
Ok(msg)
|
||||
}
|
||||
|
||||
pub fn send_parent_msg(msg: &[u8]) -> io::Result<()> { send_msg(&mut io::stdout().lock(), msg) }
|
||||
pub fn recv_parent_msg() -> io::Result<Vec<u8>> { recv_msg(&mut io::stdin().lock()) }
|
||||
@@ -5,8 +5,6 @@ use orchid_api::expr::{Clause, Expr};
|
||||
use orchid_api::location::Location;
|
||||
|
||||
use super::traits::{GenClause, Generable};
|
||||
use crate::expr::RtExpr;
|
||||
use crate::host::AtomHand;
|
||||
use crate::intern::{deintern, intern};
|
||||
|
||||
fn safely_reinterpret<In: 'static, Out: 'static>(x: In) -> Result<Out, In> {
|
||||
@@ -24,7 +22,7 @@ impl GenClause for Expr {
|
||||
fn generate<T: super::traits::Generable>(&self, ctx: T::Ctx<'_>, pop: &impl Fn() -> T) -> T {
|
||||
match &self.clause {
|
||||
Clause::Arg(arg) => T::arg(ctx, deintern(*arg).as_str()),
|
||||
Clause::Atom(atom) => T::atom(ctx, AtomHand::from_api(atom.clone())),
|
||||
Clause::Atom(atom) => T::atom(ctx, atom.clone()),
|
||||
Clause::Call(f, x) => T::apply(ctx, |c| f.generate(c, pop), |c| x.generate(c, pop)),
|
||||
Clause::Lambda(arg, b) => T::lambda(ctx, deintern(*arg).as_str(), |ctx| b.generate(ctx, pop)),
|
||||
Clause::Seq(n1, n2) => T::seq(ctx, |c| n1.generate(c, pop), |c| n2.generate(c, pop)),
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
//! Various elemental components to build expression trees that all implement
|
||||
//! [GenClause].
|
||||
|
||||
use orchid_api::atom::Atom;
|
||||
|
||||
use super::traits::{GenClause, Generable};
|
||||
use crate::host::AtomHand;
|
||||
|
||||
/// A trivial atom
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SysAtom(pub AtomHand);
|
||||
pub struct SysAtom(pub Atom);
|
||||
impl GenClause for SysAtom {
|
||||
fn generate<T: Generable>(&self, ctx: T::Ctx<'_>, _: &impl Fn() -> T) -> T {
|
||||
T::atom(ctx, self.0.clone())
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::fmt;
|
||||
|
||||
use crate::host::AtomHand;
|
||||
use orchid_api::atom::Atom;
|
||||
|
||||
/// Representations of the Orchid expression tree that can describe basic
|
||||
/// language elements.
|
||||
@@ -13,7 +13,7 @@ pub trait Generable: Sized + 'static {
|
||||
/// Context information defined by parents. Generators just forward this.
|
||||
type Ctx<'a>: Sized;
|
||||
/// Wrap external data.
|
||||
fn atom(ctx: Self::Ctx<'_>, a: AtomHand) -> Self;
|
||||
fn atom(ctx: Self::Ctx<'_>, a: Atom) -> Self;
|
||||
/// Generate a reference to a constant
|
||||
fn constant<'a>(ctx: Self::Ctx<'_>, name: impl IntoIterator<Item = &'a str>) -> Self;
|
||||
/// Generate a function call given the function and its argument
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
use std::fmt;
|
||||
|
||||
use dyn_clone::{clone_box, DynClone};
|
||||
use orchid_api::atom::Atom;
|
||||
use orchid_api::expr::Expr;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use super::tpl;
|
||||
use super::traits::{Gen, GenClause};
|
||||
use crate::combine::Combine;
|
||||
use crate::host::AtomHand;
|
||||
use crate::tree::{ModEntry, ModMember, TreeConflict};
|
||||
|
||||
trait_set! {
|
||||
@@ -64,14 +64,14 @@ pub fn ent<K: AsRef<str>>(
|
||||
|
||||
/// Describe an [Atomic]
|
||||
#[must_use]
|
||||
pub fn atom_leaf(atom: AtomHand) -> ConstTree { leaf(tpl::SysAtom(atom)) }
|
||||
pub fn atom_leaf(atom: Atom) -> ConstTree { leaf(tpl::SysAtom(atom)) }
|
||||
|
||||
/// Describe an [Atomic] which appears as an entry in a [ConstTree::tree]
|
||||
///
|
||||
/// The unarray is used to trick rustfmt into breaking the atom into a block
|
||||
/// without breaking this call into a block
|
||||
#[must_use]
|
||||
pub fn atom_ent<K: AsRef<str>>(key: K, [atom]: [AtomHand; 1]) -> (K, ConstTree) {
|
||||
pub fn atom_ent<K: AsRef<str>>(key: K, [atom]: [Atom; 1]) -> (K, ConstTree) {
|
||||
(key, atom_leaf(atom))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
pub mod boxed_iter;
|
||||
pub mod child;
|
||||
pub mod msg;
|
||||
pub mod clone;
|
||||
pub mod combine;
|
||||
pub mod event;
|
||||
pub mod expr;
|
||||
pub mod gen;
|
||||
// pub mod gen;
|
||||
pub mod intern;
|
||||
pub mod location;
|
||||
pub mod name;
|
||||
|
||||
16
orchid-base/src/msg.rs
Normal file
16
orchid-base/src/msg.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
use std::io;
|
||||
|
||||
pub fn send_msg(write: &mut impl io::Write, msg: &[u8]) -> io::Result<()> {
|
||||
write.write_all(&(u32::try_from(msg.len()).unwrap()).to_be_bytes())?;
|
||||
write.write_all(msg)?;
|
||||
write.flush()
|
||||
}
|
||||
|
||||
pub fn recv_msg(read: &mut impl io::Read) -> io::Result<Vec<u8>> {
|
||||
let mut len = [0u8; 4];
|
||||
read.read_exact(&mut len)?;
|
||||
let len = u32::from_be_bytes(len);
|
||||
let mut msg = vec![0u8; len as usize];
|
||||
read.read_exact(&mut msg)?;
|
||||
Ok(msg)
|
||||
}
|
||||
@@ -6,13 +6,13 @@ use std::sync::{Arc, Mutex};
|
||||
|
||||
use dyn_clone::{clone_box, DynClone};
|
||||
use hashbrown::HashMap;
|
||||
use orchid_api_traits::{Coding, Decode, Encode, MsgSet, Request};
|
||||
use orchid_api_traits::{Channel, Coding, Decode, Encode, MsgSet, Request};
|
||||
use trait_set::trait_set;
|
||||
|
||||
trait_set! {
|
||||
pub trait SendFn<T: MsgSet> = for<'a> FnMut(&'a [u8], ReqNot<T>) + DynClone + Send + 'static;
|
||||
pub trait ReqFn<T: MsgSet> = FnMut(RequestHandle<T>) + Send + 'static;
|
||||
pub trait NotifFn<T: MsgSet> = for<'a> FnMut(T::InNot, ReqNot<T>) + Send + Sync + 'static;
|
||||
pub trait NotifFn<T: MsgSet> = for<'a> FnMut(<T::In as Channel>::Notif, ReqNot<T>) + Send + Sync + 'static;
|
||||
}
|
||||
|
||||
fn get_id(message: &[u8]) -> (u64, &[u8]) {
|
||||
@@ -21,14 +21,14 @@ fn get_id(message: &[u8]) -> (u64, &[u8]) {
|
||||
|
||||
pub struct RequestHandle<T: MsgSet> {
|
||||
id: u64,
|
||||
message: T::InReq,
|
||||
message: <T::In as Channel>::Req,
|
||||
send: Box<dyn SendFn<T>>,
|
||||
parent: ReqNot<T>,
|
||||
fulfilled: AtomicBool,
|
||||
}
|
||||
impl<MS: MsgSet> RequestHandle<MS> {
|
||||
pub fn reqnot(&self) -> ReqNot<MS> { self.parent.clone() }
|
||||
pub fn req(&self) -> &MS::InReq { &self.message }
|
||||
pub fn req(&self) -> &<MS::In as Channel>::Req { &self.message }
|
||||
fn respond(&self, response: &impl Encode) {
|
||||
assert!(!self.fulfilled.swap(true, Ordering::Relaxed), "Already responded");
|
||||
let mut buf = (!self.id).to_be_bytes().to_vec();
|
||||
@@ -78,21 +78,21 @@ impl<T: MsgSet> ReqNot<T> {
|
||||
let mut g = self.0.lock().unwrap();
|
||||
let (id, payload) = get_id(&message[..]);
|
||||
if id == 0 {
|
||||
(g.notif)(T::InNot::decode(&mut &payload[..]), self.clone())
|
||||
(g.notif)(<T::In as Channel>::Notif::decode(&mut &payload[..]), self.clone())
|
||||
} else if 0 < id.bitand(1 << 63) {
|
||||
let sender = g.responses.remove(&!id).expect("Received response for invalid message");
|
||||
sender.send(message).unwrap();
|
||||
} else {
|
||||
let send = clone_box(&*g.send);
|
||||
let message = T::InReq::decode(&mut &payload[..]);
|
||||
let message = <T::In as Channel>::Req::decode(&mut &payload[..]);
|
||||
(g.req)(RequestHandle { id, message, send, fulfilled: false.into(), parent: self.clone() })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn notify<N: Coding + Into<T::OutNot>>(&self, notif: N) {
|
||||
pub fn notify<N: Coding + Into<<T::Out as Channel>::Notif>>(&self, notif: N) {
|
||||
let mut send = clone_box(&*self.0.lock().unwrap().send);
|
||||
let mut buf = vec![0; 8];
|
||||
let msg: T::OutNot = notif.into();
|
||||
let msg: <T::Out as Channel>::Notif = notif.into();
|
||||
msg.encode(&mut buf);
|
||||
send(&buf, self.clone())
|
||||
}
|
||||
@@ -112,7 +112,7 @@ impl<'a, T> DynRequester for MappedRequester<'a, T> {
|
||||
}
|
||||
|
||||
impl<T: MsgSet> DynRequester for ReqNot<T> {
|
||||
type Transfer = T::OutReq;
|
||||
type Transfer = <T::Out as Channel>::Req;
|
||||
fn raw_request(&self, req: Self::Transfer) -> RawReply {
|
||||
let mut g = self.0.lock().unwrap();
|
||||
let id = g.id;
|
||||
@@ -156,23 +156,27 @@ mod test {
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use orchid_api_derive::Coding;
|
||||
use orchid_api_traits::Request;
|
||||
use orchid_api_traits::{Channel, Request};
|
||||
|
||||
use super::{MsgSet, ReqNot};
|
||||
use crate::{clone, reqnot::Requester as _};
|
||||
|
||||
#[derive(Coding, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, Coding, PartialEq)]
|
||||
pub struct TestReq(u8);
|
||||
impl Request for TestReq {
|
||||
type Response = u8;
|
||||
}
|
||||
|
||||
pub struct TestChan;
|
||||
impl Channel for TestChan {
|
||||
type Notif = u8;
|
||||
type Req = TestReq;
|
||||
}
|
||||
|
||||
pub struct TestMsgSet;
|
||||
impl MsgSet for TestMsgSet {
|
||||
type InNot = u8;
|
||||
type InReq = TestReq;
|
||||
type OutNot = u8;
|
||||
type OutReq = TestReq;
|
||||
type In = TestChan;
|
||||
type Out = TestChan;
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user