simplify IO.

This commit is contained in:
Joe Ardent 2024-06-10 12:34:24 -07:00
parent a2be482b6a
commit e5150af666
2 changed files with 27 additions and 32 deletions

View file

@ -1,4 +1,4 @@
use serde_json::Value; use crate::Value;
use crate::{check_err, mk_payload, Body, RpcResult, Runner}; use crate::{check_err, mk_payload, Body, RpcResult, Runner};
@ -37,7 +37,7 @@ impl Kv {
/// let kv = Kv::seq(); /// let kv = Kv::seq();
/// let result = kv.read(&runner, "MY_KEY"); /// let result = kv.read(&runner, "MY_KEY");
/// // if "MY_KEY" had previously been written into the store, then the Result will be `Ok` /// // if "MY_KEY" had previously been written into the store, then the Result will be `Ok`
/// // and the body will be `Some(Value)`. /// // and the body will always be `Some(Value)`.
/// assert!(result.is_ok() && result.unwrap().is_some()); /// assert!(result.is_ok() && result.unwrap().is_some());
/// ``` /// ```
pub fn read(&self, runner: &Runner, key: &str) -> RpcResult { pub fn read(&self, runner: &Runner, key: &str) -> RpcResult {

View file

@ -58,13 +58,13 @@ impl Runner {
/// ```no_run /// ```no_run
/// use nebkor_maelstrom::{Body, Message, Node, Runner}; /// use nebkor_maelstrom::{Body, Message, Node, Runner};
/// struct Foo; /// struct Foo;
/// impl Node for Foo {fn handle(&mut self, _runner: &Runner, _msg: Message) { /* empty impl here*/ }} /// impl Node for Foo {fn handle(&mut self, _runner: &Runner, _msg: Message) { /* empty impl */ }}
/// ///
/// let runner = Runner::new(Foo); /// let runner = Runner::new(Foo);
/// ///
/// let on_init = |rnr: &Runner| { /// let on_init = |rnr: &Runner| {
/// eprintln!("received the `init` message!"); /// eprintln!("received the `init` message!");
/// let msg = Message { body: Body::from_type("ignore_me"), ..Default::default() }; /// let msg = Message { body: Body::from_type("yo_yo_yo"), ..Default::default() };
/// // send `msg` to the node to be processed by its `handle()` method /// // send `msg` to the node to be processed by its `handle()` method
/// rnr.get_backdoor().send(msg).unwrap(); /// rnr.get_backdoor().send(msg).unwrap();
/// }; /// };
@ -73,32 +73,19 @@ impl Runner {
/// runner.run(Some(on_init)); /// runner.run(Some(on_init));
/// ``` /// ```
pub fn run(&self, on_init: Option<OnInit>) { pub fn run(&self, on_init: Option<OnInit>) {
let (stdin_tx, stdin_rx) = channel(); let (outbound_tx, outbound_rx) = channel();
thread::spawn(move || { let _ = self.outbound_tx.get_or_init(|| outbound_tx);
let stdin = std::io::stdin().lock().lines();
for line in stdin {
stdin_tx.send(line.unwrap()).unwrap();
}
});
let (stdout_tx, stdout_rx) = channel(); // decouple processing output from handling messages
thread::spawn(move || { thread::spawn(move || {
let mut stdout = std::io::stdout().lock(); let mut stdout = std::io::stdout().lock();
for msg in stdout_rx { while let Ok(msg) = outbound_rx.recv() {
let msg = serde_json::to_string(&msg).unwrap();
writeln!(&mut stdout, "{msg}").unwrap(); writeln!(&mut stdout, "{msg}").unwrap();
} }
}); });
let (outbound_tx, outbound_rx) = channel(); self.process_input(on_init);
let _ = self.outbound_tx.get_or_init(|| outbound_tx);
thread::spawn(move || {
while let Ok(msg) = outbound_rx.recv() {
let msg = serde_json::to_string(&msg).unwrap();
stdout_tx.send(msg).unwrap();
}
});
self.process_input(stdin_rx, on_init);
} }
/// Get a Sender that will send Messages to the node as input. Useful for triggering periodic /// Get a Sender that will send Messages to the node as input. Useful for triggering periodic
@ -175,23 +162,30 @@ impl Runner {
let _ = self.nodes.get_or_init(|| nodes); let _ = self.nodes.get_or_init(|| nodes);
} }
fn process_input(&self, stdin_rx: Receiver<String>, on_init: Option<OnInit>) { fn process_input(&self, on_init: Option<OnInit>) {
let (json_tx, json_rx) = channel(); // for sending Messages to the node's inputs
let _ = self.backdoor.get_or_init(|| json_tx.clone()); let (encoded_input_tx, encoded_input_rx) = channel();
let _ = self.backdoor.get_or_init(|| encoded_input_tx.clone());
// decouple stdin from processing
let proms = self.promises.clone(); let proms = self.promises.clone();
thread::spawn(move || { thread::spawn(move || {
for line in stdin_rx { let stdin = std::io::stdin().lock();
for line in stdin.lines().map_while(std::result::Result::ok) {
let msg: Message = serde_json::from_str(&line).unwrap(); let msg: Message = serde_json::from_str(&line).unwrap();
let irt = msg.body.in_reply_to; let irt = msg.body.in_reply_to;
if let Some(tx) = proms.lock().unwrap().remove(&irt) { if let Some(promise) = proms.lock().unwrap().remove(&irt) {
tx.send(msg).unwrap(); // this is the result of an RPC call
promise.send(msg).unwrap();
} else { } else {
json_tx.send(msg).unwrap(); // just let the node's `handle()` method handle it
encoded_input_tx.send(msg).unwrap();
} }
} }
}); });
let msg = json_rx.recv().unwrap(); // first Message is always `init`:
let msg = encoded_input_rx.recv().unwrap();
{ {
self.init(&msg); self.init(&msg);
let body = Body::from_type("init_ok"); let body = Body::from_type("init_ok");
@ -201,8 +195,9 @@ impl Runner {
} }
} }
// every other message is for the node's handle() method
let mut node = self.node.lock().unwrap(); let mut node = self.node.lock().unwrap();
for msg in json_rx { for msg in encoded_input_rx {
node.handle(self, msg); node.handle(self, msg);
} }
} }