use crate::cli::{IsTerminal, StdoutStream};
use crate::p2;
use bytes::Bytes;
use std::io::{self, Write};
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::AsyncWrite;
use wasmtime_wasi_io::streams::OutputStream;
impl IsTerminal for tokio::io::Stdout {
fn is_terminal(&self) -> bool {
std::io::stdout().is_terminal()
}
}
impl StdoutStream for tokio::io::Stdout {
fn p2_stream(&self) -> Box<dyn OutputStream> {
Box::new(StdioOutputStream::Stdout)
}
fn async_stream(&self) -> Box<dyn AsyncWrite + Send + Sync> {
Box::new(StdioOutputStream::Stdout)
}
}
impl IsTerminal for std::io::Stdout {
fn is_terminal(&self) -> bool {
std::io::IsTerminal::is_terminal(self)
}
}
impl StdoutStream for std::io::Stdout {
fn p2_stream(&self) -> Box<dyn OutputStream> {
Box::new(StdioOutputStream::Stdout)
}
fn async_stream(&self) -> Box<dyn AsyncWrite + Send + Sync> {
Box::new(StdioOutputStream::Stdout)
}
}
impl IsTerminal for tokio::io::Stderr {
fn is_terminal(&self) -> bool {
std::io::stderr().is_terminal()
}
}
impl StdoutStream for tokio::io::Stderr {
fn p2_stream(&self) -> Box<dyn OutputStream> {
Box::new(StdioOutputStream::Stderr)
}
fn async_stream(&self) -> Box<dyn AsyncWrite + Send + Sync> {
Box::new(StdioOutputStream::Stderr)
}
}
impl IsTerminal for std::io::Stderr {
fn is_terminal(&self) -> bool {
std::io::IsTerminal::is_terminal(self)
}
}
impl StdoutStream for std::io::Stderr {
fn p2_stream(&self) -> Box<dyn OutputStream> {
Box::new(StdioOutputStream::Stderr)
}
fn async_stream(&self) -> Box<dyn AsyncWrite + Send + Sync> {
Box::new(StdioOutputStream::Stderr)
}
}
enum StdioOutputStream {
Stdout,
Stderr,
}
impl OutputStream for StdioOutputStream {
fn write(&mut self, bytes: Bytes) -> p2::StreamResult<()> {
match self {
StdioOutputStream::Stdout => std::io::stdout().write_all(&bytes),
StdioOutputStream::Stderr => std::io::stderr().write_all(&bytes),
}
.map_err(|e| p2::StreamError::LastOperationFailed(wasmtime::format_err!(e)))
}
fn flush(&mut self) -> p2::StreamResult<()> {
match self {
StdioOutputStream::Stdout => std::io::stdout().flush(),
StdioOutputStream::Stderr => std::io::stderr().flush(),
}
.map_err(|e| p2::StreamError::LastOperationFailed(wasmtime::format_err!(e)))
}
fn check_write(&mut self) -> p2::StreamResult<usize> {
Ok(1024 * 1024)
}
}
impl AsyncWrite for StdioOutputStream {
fn poll_write(
self: Pin<&mut Self>,
_cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
Poll::Ready(match *self {
StdioOutputStream::Stdout => std::io::stdout().write(buf),
StdioOutputStream::Stderr => std::io::stderr().write(buf),
})
}
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(match *self {
StdioOutputStream::Stdout => std::io::stdout().flush(),
StdioOutputStream::Stderr => std::io::stderr().flush(),
})
}
fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(Ok(()))
}
}
#[async_trait::async_trait]
impl p2::Pollable for StdioOutputStream {
async fn ready(&mut self) {}
}