use core::cell::RefCell;
use alloc::rc::Rc;
use alloc::{boxed::Box, string::String, vec::Vec};
use crate::{Device, Value};
pub const CONSOLE_ID: u8 = 0x10;
pub const PORT_STDIN: u8 = 0x00;
pub const PORT_STDOUT: u8 = 0x01;
pub const PORT_STDERR: u8 = 0x02;
pub const PORT_FLUSH: u8 = 0x03;
pub trait Console {
fn read_byte(&mut self) -> Result<Option<u8>, String>;
fn write_stdout(&mut self, byte: u8) -> Result<(), String>;
fn write_stderr(&mut self, byte: u8) -> Result<(), String>;
fn flush(&mut self) -> Result<(), String>;
fn write_stdout_bulk(&mut self, bytes: &[u8]) -> Result<(), String> {
for &b in bytes { self.write_stdout(b)?; }
Ok(())
}
fn write_stderr_bulk(&mut self, bytes: &[u8]) -> Result<(), String> {
for &b in bytes { self.write_stderr(b)?; }
Ok(())
}
}
impl Device for Box<dyn Console> {
fn read(&mut self, port: u8) -> Result<(Value, bool), String> {
let v = match port {
PORT_STDIN => match self.read_byte()? {
Some(b) => Value::from_int(b as i64),
None => Value::from_int(-1),
},
_ => Value::from_int(0),
};
Ok((v, false))
}
fn write(&mut self, port: u8, val: Value, is_handle: bool, heap: &mut crate::memory::Heap)
-> Result<(), String>
{
if is_handle { heap.rc_dec_handle(val.raw())?; return Ok(()); }
let n = val.as_int();
match port {
PORT_STDOUT => self.write_stdout((n & 0xFF) as u8),
PORT_STDERR => self.write_stderr((n & 0xFF) as u8),
PORT_FLUSH => self.flush(),
_ => Ok(()),
}
}
fn write_bytes(&mut self, port: u8, bytes: &[u8], _heap: &mut crate::memory::Heap)
-> Result<(), String>
{
match port {
PORT_STDOUT => self.write_stdout_bulk(bytes),
PORT_STDERR => self.write_stderr_bulk(bytes),
_ => Ok(()),
}
}
}
pub type SharedBuf = Rc<RefCell<Vec<u8>>>;
pub struct BufferConsole {
pub out_buf: SharedBuf,
pub err_buf: SharedBuf,
pub stdin_buf: SharedBuf,
}
impl BufferConsole {
pub fn new() -> Self {
Self {
out_buf: Rc::new(RefCell::new(Vec::new())),
err_buf: Rc::new(RefCell::new(Vec::new())),
stdin_buf: Rc::new(RefCell::new(Vec::new())),
}
}
pub fn handles(&self) -> (SharedBuf, SharedBuf) {
(self.out_buf.clone(), self.err_buf.clone())
}
pub fn stdin_handle(&self) -> SharedBuf {
self.stdin_buf.clone()
}
}
impl Console for BufferConsole {
fn read_byte(&mut self) -> Result<Option<u8>, String> {
let mut buf = self.stdin_buf.borrow_mut();
if buf.is_empty() { Ok(None) } else { Ok(Some(buf.remove(0))) }
}
fn write_stdout(&mut self, byte: u8) -> Result<(), String> {
self.out_buf.borrow_mut().push(byte); Ok(())
}
fn write_stderr(&mut self, byte: u8) -> Result<(), String> {
self.err_buf.borrow_mut().push(byte); Ok(())
}
fn flush(&mut self) -> Result<(), String> { Ok(()) }
fn write_stdout_bulk(&mut self, bytes: &[u8]) -> Result<(), String> {
self.out_buf.borrow_mut().extend_from_slice(bytes); Ok(())
}
fn write_stderr_bulk(&mut self, bytes: &[u8]) -> Result<(), String> {
self.err_buf.borrow_mut().extend_from_slice(bytes); Ok(())
}
}