Skip to content

Commit

Permalink
refactor IntoResult trait into its own internal module and separately…
Browse files Browse the repository at this point in the history
… implement IsError (hopefully Windows compiles now...)
  • Loading branch information
apparebit committed Nov 12, 2024
1 parent 9c26d70 commit f48487a
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 56 deletions.
66 changes: 66 additions & 0 deletions src/term/sys/into_result.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use std::io::Result;

/// Trait to determine whether a status code is an error.
pub(crate) trait IsError {
/// Determine if this value is an error.
fn is_error(&self) -> bool;
}

#[cfg(target_family = "unix")]
macro_rules! is_error {
($source:ty) => {
impl IsError for $source {
#[inline]
fn is_error(&self) -> bool {
*self == -1
}
}
};
}

#[cfg(target_family = "windows")]
macro_rules! is_error {
($source:ty) => {
impl IsError for $source {
#[inline]
fn is_error(&self) -> bool {
*self == 0
}
}
};
}

is_error!(i32);
is_error!(isize);
#[cfg(target_family = "windows")]
is_error!(u32);

/// Trait to convert a status code into a Rust result.
pub(crate) trait IntoResult {
/// The target type.
type Target;

/// Convert this status code into a Rust result.
fn into_result(self) -> Result<Self::Target>;
}

macro_rules! into_result {
($source:ty, $target:ty) => {
impl IntoResult for $source {
type Target = $target;

fn into_result(self) -> Result<Self::Target> {
if self.is_error() {
Err(std::io::Error::last_os_error())
} else {
Ok(self as Self::Target)
}
}
}
};
}

into_result!(i32, u32);
into_result!(isize, usize);
#[cfg(target_family = "windows")]
into_result!(u32, u32);
1 change: 1 addition & 0 deletions src/term/sys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pub(crate) type RawHandle = std::os::fd::RawFd;
#[cfg(target_family = "windows")]
pub(crate) type RawHandle = std::os::windows::io::RawHandle;

mod into_result;
#[cfg(target_family = "unix")]
mod unix;
#[cfg(target_family = "windows")]
Expand Down
37 changes: 1 addition & 36 deletions src/term/sys/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,44 +12,9 @@ use std::io::{Read, Result, Write};
use std::os::fd::{AsRawFd, OwnedFd};
use std::ptr::{from_mut, from_ref};

use super::RawHandle;
use super::{into_result::IntoResult, RawHandle};
use crate::term::{Mode, Options};

/// A trait for converting libc status codes to Rust std::io results.
///
/// The implementations for pairs of signed and unsigned primitive integers of
/// the same size differ solely in the declared types for `Self` and `Unsigned`.
/// Hence, we delegate to a declarative macro.
trait IntoResult {
/// The unsigned version of `Self`.
type Unsigned;

/// Actually convert a signed status code to a Rust result.
///
/// If the status code is negative, this method returns the last OS error.
/// Otherwise, it returns the now unsigned status code wrapped as a result.
fn into_result(self) -> Result<Self::Unsigned>;
}

macro_rules! into_result {
($signed:ty, $unsigned:ty) => {
impl IntoResult for $signed {
type Unsigned = $unsigned;

fn into_result(self) -> Result<Self::Unsigned> {
if self < 0 {
Err(std::io::Error::last_os_error())
} else {
Ok(self as Self::Unsigned)
}
}
}
};
}

into_result!(i32, u32);
into_result!(isize, usize);

// ------------------------------------------------------------------------------------------------

/// A connection to the terminal device.
Expand Down
25 changes: 5 additions & 20 deletions src/term/sys/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,9 @@ use windows_sys::Win32::Globalization;
use windows_sys::Win32::System::Console::{self, CONSOLE_MODE as ConsoleMode};
use windows_sys::Win32::System::Threading;

use super::RawHandle;
use super::{into_result::IntoResult, RawHandle};
use crate::term::{Mode, Options};

/// A trait for converting Windows status BOOL to Rust std::io results.
trait IntoResult {
/// Convert the return type into an error.
fn into_result(self) -> Result<u32>;
}

impl IntoResult for u32 {
#[inline]
fn into_result(self) -> Result<u32> {
if self != 0 {
Ok(self)
} else {
Err(Error::last_os_error())
}
}
}

// ----------------------------------------------------------------------------------------------------------

/// The connections to the terminal device.
Expand Down Expand Up @@ -155,8 +138,10 @@ impl Config {
& Console::ENABLE_VIRTUAL_TERMINAL_PROCESSING;

// If the update fails, try to restore old configuration.
this.update(new_input_mode, new_output_mode)
.or_else(|e| this.restore())?;
this.update(new_input_mode, new_output_mode).or_else(|e| {
this.restore();
e
})?;

Ok(this)
}
Expand Down

0 comments on commit f48487a

Please sign in to comment.