Skip to content

Commit

Permalink
Fix serial console breaking on Windows when a non-UTF8 sequence is ou…
Browse files Browse the repository at this point in the history
…tput
  • Loading branch information
lif committed Feb 14, 2024
1 parent b55912f commit 61b5594
Showing 1 changed file with 32 additions and 12 deletions.
44 changes: 32 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ pub struct Console<O: AsyncWriteExt + Unpin + Send> {
raw_guard: Option<RawModeGuard>,
}

impl Console<tokio::io::Stdout> {
/// Construct with the normal stdin and stdout file descriptors, for
/// typical use.
pub async fn new_stdio(escape: Option<EscapeSequence>) -> Result<Self, Error> {
Console::new(tokio::io::stdin(), tokio::io::stdout(), escape).await
}
}

impl<O: AsyncWriteExt + Unpin + Send + AsRawFdHandle> Console<O> {
/// Construct with arbitrary [AsyncReadExt] and [AsyncWriteExt] streams,
/// supporting use cases where we might be talking to something other than
Expand All @@ -84,17 +92,7 @@ impl<O: AsyncWriteExt + Unpin + Send + AsRawFdHandle> Console<O> {
)?);
Ok(Self::new_inner(stdin, stdout, escape, raw_guard))
}
}

impl Console<tokio::io::Stdout> {
/// Construct with the normal stdin and stdout file descriptors, for
/// typical use.
pub async fn new_stdio(escape: Option<EscapeSequence>) -> Result<Self, Error> {
Console::new(tokio::io::stdin(), tokio::io::stdout(), escape).await
}
}

impl<O: AsyncWriteExt + Unpin + Send> Console<O> {
fn new_inner<I: AsyncReadExt + Unpin + Send + 'static>(
stdin: I,
stdout: O,
Expand Down Expand Up @@ -125,8 +123,30 @@ impl<O: AsyncWriteExt + Unpin + Send> Console<O> {

/// Write the given bytes to stdout.
pub async fn write_stdout(&mut self, bytes: &[u8]) -> Result<(), Error> {
self.stdout.write_all(bytes).await?;
self.stdout.flush().await?;
// windows io in rust fails if any byte sequences aren't valid utf8
#[cfg(target_family = "windows")]
{
use winapi::shared::minwindef::LPDWORD;
use winapi::um::winnt::{HANDLE, VOID};
let mut _lp_num_of_chars_written = 0u32;
let res = unsafe {
winapi::um::consoleapi::WriteConsoleA(
self.stdout.as_raw_handle() as HANDLE,
bytes.as_ptr() as *const VOID,
bytes.len() as u32,
(&mut _lp_num_of_chars_written) as LPDWORD,
std::ptr::null_mut::<VOID>(),
)
};
if res == 0 {
return Err(std::io::Error::last_os_error().into());
}
}
#[cfg(not(target_family = "windows"))]
{
self.stdout.write_all(bytes).await?;
self.stdout.flush().await?;
}
Ok(())
}

Expand Down

0 comments on commit 61b5594

Please sign in to comment.