use std::io::{self, BufRead, BufWriter};
use wasm_bindgen::prelude::*;
use crate::stdio::{Stdio, out::RawOut};
#[wasm_bindgen]
extern "C" {
pub fn wasm_stdin_read_line() -> String;
pub fn wasm_stdout_write(data: &[u8]);
pub fn wasm_stderr_write(data: &[u8]);
}
pub struct WasmStdin {
buf: Vec<u8>,
pos: usize,
}
impl io::Read for WasmStdin {
fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
let filled = self.fill_buf()?;
let n = filled.len().min(out.len());
out[..n].copy_from_slice(&filled[..n]);
self.consume(n);
Ok(n)
}
}
impl io::BufRead for WasmStdin {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
if self.pos >= self.buf.len() {
wasm_stdout_write(b"\x1b[2K\r>> ");
let line = wasm_stdin_read_line();
self.buf = line.into_bytes();
self.pos = 0;
}
Ok(&self.buf[self.pos..])
}
fn consume(&mut self, amount: usize) {
self.pos = (self.pos + amount).min(self.buf.len());
}
}
pub struct WasmStdout;
impl io::Write for WasmStdout {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
wasm_stdout_write(buf);
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
pub struct WasmStderr;
impl io::Write for WasmStderr {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
wasm_stderr_write(buf);
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
pub struct WasmStdio {
stdin: WasmStdin,
stdout: RawOut<BufWriter<WasmStdout>>,
stderr: RawOut<BufWriter<WasmStderr>>,
}
impl WasmStdio {
pub fn new() -> Self {
Self {
stdin: WasmStdin {
buf: Vec::new(),
pos: 0,
},
stdout: RawOut(BufWriter::new(WasmStdout)),
stderr: RawOut(BufWriter::new(WasmStderr)),
}
}
}
impl Stdio for WasmStdio {
fn stdin(&mut self) -> &mut impl BufRead {
&mut self.stdin
}
fn stdout(&mut self) -> &mut impl io::Write {
&mut self.stdout
}
fn stderr(&mut self) -> &mut impl io::Write {
&mut self.stderr
}
fn push_history(&mut self, _entry: &str) {}
}