moar fancy comments
cargo devel CI / cargo CI (push) Has been cancelled
Details
cargo devel CI / cargo CI (push) Has been cancelled
Details
This commit is contained in:
parent
5b594122ba
commit
0ffa4cd497
|
@ -6,17 +6,20 @@ use std::str::FromStr;
|
||||||
use std::sync::{Arc, Barrier};
|
use std::sync::{Arc, Barrier};
|
||||||
use std::{sync::mpsc, thread};
|
use std::{sync::mpsc, thread};
|
||||||
|
|
||||||
|
// simulate a complex datatype with special meaning being sent somewhere
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct Message {
|
struct Message {
|
||||||
payload: String,
|
payload: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// be able to print the Message
|
||||||
impl std::fmt::Display for Message {
|
impl std::fmt::Display for Message {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "Message {{{}}}", self.payload)
|
write!(f, "Message {{{}}}", self.payload)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make a new Message from a string
|
||||||
impl std::str::FromStr for Message {
|
impl std::str::FromStr for Message {
|
||||||
type Err = std::convert::Infallible;
|
type Err = std::convert::Infallible;
|
||||||
fn from_str(s: &str) -> std::prelude::v1::Result<Self, Self::Err> {
|
fn from_str(s: &str) -> std::prelude::v1::Result<Self, Self::Err> {
|
||||||
|
@ -26,37 +29,76 @@ impl std::str::FromStr for Message {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// printer thread function, will print any message received via the mpsc channel
|
||||||
fn printer(receiver: mpsc::Receiver<Message>, barrier: Arc<Barrier>) -> Result<()> {
|
fn printer(receiver: mpsc::Receiver<Message>, barrier: Arc<Barrier>) -> Result<()> {
|
||||||
let mut stdout = std::io::stdout();
|
let mut stdout = std::io::stdout();
|
||||||
loop {
|
|
||||||
let msg = receiver.recv()?;
|
// run as long as we can receive something (err always means all senders have been dropped)
|
||||||
|
while let Ok(msg) = receiver.recv() {
|
||||||
println!("{msg}");
|
println!("{msg}");
|
||||||
stdout.flush()?;
|
stdout.flush()?;
|
||||||
barrier.wait(); // wait until the main thread wants us to print
|
barrier.wait(); // done with printing, the main thread can continue
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
|
// channel that can be split across threads to send values between them
|
||||||
|
// mpsc means Multi-producer, single-consumer
|
||||||
let (sender, receiver) = mpsc::channel();
|
let (sender, receiver) = mpsc::channel();
|
||||||
let barrier = Arc::new(Barrier::new(2));
|
|
||||||
let barrier_printer = barrier.clone();
|
// we need to wait for the printer thread to be done before we print the prompt "> " to stdout,
|
||||||
thread::spawn(|| printer(receiver, barrier_printer).expect("printer error"));
|
// otherwise we mix up the prints.
|
||||||
let mut msg;
|
//
|
||||||
let mut buf = String::new();
|
// We put it into an Arc, so that we can share it across threads.
|
||||||
let stdin = std::io::stdin();
|
let barrier = Arc::new(Barrier::new(
|
||||||
let mut stdout = std::io::stdout();
|
2, /* number of threads, continue when this many are waiting */
|
||||||
|
));
|
||||||
|
let barrier_printer = barrier.clone(); // second one for the printer, this contains a reference
|
||||||
|
// to our original barrier. (An Arc is a special kind of reference)
|
||||||
|
|
||||||
|
// we spawn a thread and give it something to run
|
||||||
|
let _handle = thread::spawn(|| printer(receiver, barrier_printer).expect("printer error"));
|
||||||
|
|
||||||
|
let mut msg; // we store our messages here
|
||||||
|
let mut buf = String::new(); // we put the contents of the stdin here
|
||||||
|
let stdin = std::io::stdin(); // we read user input from here
|
||||||
|
let mut stdout = std::io::stdout(); // we need this to flush explicitly
|
||||||
|
|
||||||
|
// do this forever
|
||||||
loop {
|
loop {
|
||||||
buf.clear();
|
buf.clear(); // we want an empty buf at the start
|
||||||
|
|
||||||
|
// print a prompt while staying in the same line
|
||||||
print!("> ");
|
print!("> ");
|
||||||
stdout.flush()?;
|
stdout.flush()?; // make sure that the stdout gets printed now instead of waiting for a
|
||||||
let _ = stdin.read_line(&mut buf)?;
|
// newline (stdout flushes automatically at newlines)
|
||||||
buf = buf.replace('\n', "");
|
|
||||||
if buf.is_empty() {
|
let _ = stdin.read_line(&mut buf)?; // read the user input
|
||||||
|
|
||||||
|
// check for special inputs
|
||||||
|
if buf == "\n" {
|
||||||
|
// enter
|
||||||
continue;
|
continue;
|
||||||
|
} else if buf.to_lowercase() == "exit\n" || buf.is_empty() {
|
||||||
|
// exit or ctrl-d
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buf = buf.replace('\n', ""); // we don't need the newline, just accept the user input when
|
||||||
|
// the user presses return
|
||||||
|
// if the user input was empty start anew
|
||||||
|
|
||||||
|
// convert the user input into a message (we could also just send a String, but this
|
||||||
|
// simulates a more complex behavior)
|
||||||
msg = Message::from_str(&buf).unwrap();
|
msg = Message::from_str(&buf).unwrap();
|
||||||
|
|
||||||
|
// send the `Message` to the printer thread
|
||||||
sender.send(msg)?;
|
sender.send(msg)?;
|
||||||
barrier.wait(); // wait until the printer is done printing the message, so we dont mix
|
|
||||||
// stdout prints (we use print instead of println)
|
// wait until the printer is done printing the message, so we dont mix
|
||||||
|
// stdout prints (we use print instead of println)
|
||||||
|
barrier.wait();
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue