Refactor UserInput to use channels

This commit is contained in:
bakaq
2025-01-30 06:14:38 -03:00
parent 4e032c8a28
commit baae1dca15
3 changed files with 73 additions and 27 deletions

View File

@@ -1,7 +1,6 @@
use std::cell::RefCell; use std::borrow::Cow;
use std::io::{Seek, SeekFrom, Write}; use std::io::Write;
use std::rc::Rc; use std::sync::mpsc::{channel, Receiver, Sender};
use std::{borrow::Cow, io::Cursor};
use rand::{rngs::StdRng, SeedableRng}; use rand::{rngs::StdRng, SeedableRng};
@@ -40,14 +39,12 @@ impl StreamConfig {
/// ///
/// This also returns a handler to the stdin do the [`Machine`](crate::Machine). /// This also returns a handler to the stdin do the [`Machine`](crate::Machine).
pub fn with_callbacks(stdout: Option<Callback>, stderr: Option<Callback>) -> (UserInput, Self) { pub fn with_callbacks(stdout: Option<Callback>, stderr: Option<Callback>) -> (UserInput, Self) {
let stdin = Rc::new(RefCell::new(Cursor::new(Vec::new()))); let (sender, receiver) = channel();
( (
UserInput { UserInput { inner: sender },
inner: stdin.clone(),
},
StreamConfig { StreamConfig {
inner: StreamConfigInner::Callbacks { inner: StreamConfigInner::Callbacks {
stdin, stdin: receiver,
stdout, stdout,
stderr, stderr,
}, },
@@ -59,23 +56,19 @@ impl StreamConfig {
/// A handler for the stdin of the [`Machine`](crate::Machine). /// A handler for the stdin of the [`Machine`](crate::Machine).
#[derive(Debug)] #[derive(Debug)]
pub struct UserInput { pub struct UserInput {
inner: Rc<RefCell<Cursor<Vec<u8>>>>, inner: Sender<Vec<u8>>,
} }
impl Write for UserInput { impl Write for UserInput {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let mut inner = self.inner.borrow_mut(); self.inner
let pos = inner.position(); .send(buf.into())
.map(|_| buf.len())
inner.seek(SeekFrom::End(0))?; .map_err(|_| std::io::ErrorKind::BrokenPipe.into())
let result = inner.write(buf);
inner.seek(SeekFrom::Start(pos))?;
result
} }
fn flush(&mut self) -> std::io::Result<()> { fn flush(&mut self) -> std::io::Result<()> {
self.inner.borrow_mut().flush() Ok(())
} }
} }
@@ -85,7 +78,7 @@ enum StreamConfigInner {
#[default] #[default]
Memory, Memory,
Callbacks { Callbacks {
stdin: Rc<RefCell<Cursor<Vec<u8>>>>, stdin: Receiver<Vec<u8>>,
stdout: Option<Callback>, stdout: Option<Callback>,
stderr: Option<Callback>, stderr: Option<Callback>,
}, },

View File

@@ -620,7 +620,7 @@ fn callback_streams() {
let (mut user_input, streams) = StreamConfig::with_callbacks( let (mut user_input, streams) = StreamConfig::with_callbacks(
Some(Box::new(move |x| { Some(Box::new(move |x| {
x.read_to_string(&mut *test_string2.borrow_mut()).unwrap(); x.read_to_string(&mut test_string2.borrow_mut()).unwrap();
})), })),
None, None,
); );

View File

@@ -16,7 +16,6 @@ pub use scryer_modular_bitfield::prelude::*;
#[cfg(feature = "http")] #[cfg(feature = "http")]
use bytes::{buf::Reader as BufReader, Buf, Bytes}; use bytes::{buf::Reader as BufReader, Buf, Bytes};
use std::cell::RefCell;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;
@@ -30,7 +29,8 @@ use std::net::{Shutdown, TcpStream};
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::path::PathBuf; use std::path::PathBuf;
use std::ptr; use std::ptr;
use std::rc::Rc; use std::sync::mpsc::Receiver;
use std::sync::mpsc::TryRecvError;
#[cfg(feature = "tls")] #[cfg(feature = "tls")]
use native_tls::TlsStream; use native_tls::TlsStream;
@@ -414,13 +414,50 @@ impl Write for CallbackStream {
#[derive(Debug)] #[derive(Debug)]
pub struct InputChannelStream { pub struct InputChannelStream {
pub(crate) inner: Rc<RefCell<Cursor<Vec<u8>>>>, pub(crate) inner: Cursor<Vec<u8>>,
pub eof: bool,
channel: Receiver<Vec<u8>>,
} }
impl Read for InputChannelStream { impl Read for InputChannelStream {
#[inline] #[inline]
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.inner.borrow_mut().read(buf) if self.eof {
return Ok(0);
}
let to_read = buf.len();
let mut total_read = 0;
loop {
total_read += self.inner.read(&mut buf[total_read..])?;
if total_read < to_read {
// We need to get more data to read
match self.channel.try_recv() {
Ok(data) => {
// Append into self.inner
let pos = self.inner.position();
assert_eq!(pos as usize, self.inner.get_ref().len());
self.inner.write_all(&data)?;
self.inner.seek(SeekFrom::Start(pos))?;
}
Err(TryRecvError::Empty) => {
// Data is pending
break;
}
Err(TryRecvError::Disconnected) => {
// The other end of the channel was closed so we are EOF
self.eof = true;
break;
}
}
} else {
assert_eq!(total_read, to_read);
break;
}
}
Ok(total_read)
} }
} }
@@ -602,9 +639,14 @@ impl Stream {
} }
#[inline] #[inline]
pub fn input_channel(cursor: Rc<RefCell<Cursor<Vec<u8>>>>, arena: &mut Arena) -> Stream { pub fn input_channel(channel: Receiver<Vec<u8>>, arena: &mut Arena) -> Stream {
let inner = Cursor::new(Vec::new());
Stream::InputChannel(arena_alloc!( Stream::InputChannel(arena_alloc!(
StreamLayout::new(CharReader::new(InputChannelStream { inner: cursor })), StreamLayout::new(CharReader::new(InputChannelStream {
inner,
eof: false,
channel
})),
arena arena
)) ))
} }
@@ -1239,6 +1281,13 @@ impl Stream {
AtEndOfStream::Past AtEndOfStream::Past
} }
} }
Stream::InputChannel(stream_layout) => {
if stream_layout.stream.get_ref().eof {
AtEndOfStream::At
} else {
AtEndOfStream::Not
}
}
_ => AtEndOfStream::Not, _ => AtEndOfStream::Not,
} }
} }
@@ -1519,6 +1568,10 @@ impl Stream {
readline_stream.reset(); readline_stream.reset();
true true
} }
Stream::InputChannel(ref mut input_channel_stream) => {
input_channel_stream.stream.get_mut().inner.set_position(0);
true
}
_ => false, _ => false,
} }
} }