From 3b550f5d3dad77a56455352579fae3071b42e86d Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Wed, 29 Dec 2021 02:55:24 -0500 Subject: wip another complete refactor --- src/pty.rs | 193 ++++++++++++++++++------------------------------------------- 1 file changed, 56 insertions(+), 137 deletions(-) (limited to 'src/pty.rs') diff --git a/src/pty.rs b/src/pty.rs index 72c59e1..f01e014 100644 --- a/src/pty.rs +++ b/src/pty.rs @@ -1,167 +1,86 @@ -use ::std::os::unix::io::{AsRawFd as _, FromRawFd as _, IntoRawFd as _}; - -#[cfg(any(feature = "backend-async-std", feature = "backend-smol"))] -pub mod async_io; -#[cfg(feature = "backend-std")] -pub mod std; -#[cfg(feature = "backend-tokio")] -pub mod tokio; - -pub struct Pty { - pt: Pt, - ptsname: ::std::path::PathBuf, +pub struct Pty { + pt: async_io::Async, + ptsname: std::path::PathBuf, } -impl Pty { - pub fn new() -> crate::error::Result { - let (pt_fd, ptsname) = create_pt()?; - - // safe because posix_openpt (or the previous functions operating on - // the result) would have returned an Err (causing us to return early) - // if the file descriptor was invalid. additionally, into_raw_fd gives - // up ownership over the file descriptor, allowing the newly created - // File object to take full ownership. - let fh = unsafe { ::std::fs::File::from_raw_fd(pt_fd) }; - let pt = Pt::new_from_fh(fh)?; - +impl Pty { + pub fn new() -> crate::Result { + let (pt, ptsname) = + crate::sys::create_pt().map_err(crate::error::create_pty)?; + let pt = + async_io::Async::new(pt).map_err(crate::error::create_pty)?; Ok(Self { pt, ptsname }) } - pub fn pt(&self) -> &Pt { - &self.pt - } - - pub fn pt_mut(&mut self) -> &mut Pt { - &mut self.pt - } - pub fn resize(&self, size: crate::Size) -> crate::error::Result<()> { - set_term_size(self.pt().as_raw_fd(), size) + crate::sys::set_term_size(self, size) .map_err(crate::error::set_term_size) } - fn pts(&self) -> crate::error::Result<::std::fs::File> { - let fh = ::std::fs::OpenOptions::new() + pub(crate) fn pts(&self) -> std::io::Result { + let fh = std::fs::OpenOptions::new() .read(true) .write(true) - .open(&self.ptsname) - .map_err(crate::error::create_pty)?; + .open(&self.ptsname)?; Ok(fh) } - - pub(crate) fn setup( - &self, - ) -> crate::Result<( - ::std::fs::File, - ::std::os::unix::io::RawFd, - ::std::os::unix::io::RawFd, - ::std::os::unix::io::RawFd, - )> { - let pts = self.pts()?; - let pts_fd = pts.as_raw_fd(); - - let stdin = - nix::unistd::dup(pts_fd).map_err(crate::error::create_pty)?; - let stdout = - nix::unistd::dup(pts_fd).map_err(crate::error::create_pty)?; - let stderr = - nix::unistd::dup(pts_fd).map_err(crate::error::create_pty)?; - - Ok((pts, stdin, stdout, stderr)) - } } -pub trait Impl: ::std::os::unix::io::AsRawFd + Sized { - fn new_from_fh(fh: ::std::fs::File) -> crate::Result; -} +impl std::ops::Deref for Pty { + type Target = async_io::Async; -/// Represents the size of the pty. -#[derive(Debug, Clone, Copy)] -pub struct Size { - row: u16, - col: u16, - xpixel: u16, - ypixel: u16, + fn deref(&self) -> &Self::Target { + &self.pt + } } -impl Size { - /// Returns a [`Size`](Size) instance with the given number of rows and - /// columns. - #[must_use] - pub fn new(row: u16, col: u16) -> Self { - Self { - row, - col, - xpixel: 0, - ypixel: 0, - } +impl std::ops::DerefMut for Pty { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.pt } +} - /// Returns a [`Size`](Size) instance with the given number of rows and - /// columns, as well as the given pixel dimensions. - #[must_use] - pub fn new_with_pixel( - row: u16, - col: u16, - xpixel: u16, - ypixel: u16, - ) -> Self { - Self { - row, - col, - xpixel, - ypixel, - } +impl std::os::unix::io::AsRawFd for Pty { + fn as_raw_fd(&self) -> std::os::unix::io::RawFd { + self.pt.as_raw_fd() } } -impl From for nix::pty::Winsize { - fn from(size: Size) -> Self { - Self { - ws_row: size.row, - ws_col: size.col, - ws_xpixel: size.xpixel, - ws_ypixel: size.ypixel, - } +// there is an AsyncRead impl for &Async, but without this +// explicit impl, rust finds the AsyncRead impl for Async +// first, and then complains that it requires &mut self, because method +// resolution/autoderef doesn't take mutability into account +impl futures_io::AsyncRead for &Pty { + fn poll_read( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &mut [u8], + ) -> std::task::Poll> { + std::pin::Pin::new(&mut &self.pt).poll_read(cx, buf) } } -fn create_pt( -) -> crate::error::Result<(::std::os::unix::io::RawFd, ::std::path::PathBuf)> -{ - let pt = nix::pty::posix_openpt( - nix::fcntl::OFlag::O_RDWR | nix::fcntl::OFlag::O_NOCTTY, - ) - .map_err(crate::error::create_pty)?; - nix::pty::grantpt(&pt).map_err(crate::error::create_pty)?; - nix::pty::unlockpt(&pt).map_err(crate::error::create_pty)?; - - let ptsname = nix::pty::ptsname_r(&pt) - .map_err(crate::error::create_pty)? - .into(); - - let pt_fd = pt.into_raw_fd(); - - Ok((pt_fd, ptsname)) -} +// same as above +impl futures_io::AsyncWrite for &Pty { + fn poll_write( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &[u8], + ) -> std::task::Poll> { + std::pin::Pin::new(&mut &self.pt).poll_write(cx, buf) + } -nix::ioctl_write_ptr_bad!( - set_term_size_unsafe, - libc::TIOCSWINSZ, - nix::pty::Winsize -); + fn poll_flush( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + std::pin::Pin::new(&mut &self.pt).poll_flush(cx) + } -fn set_term_size( - fd: ::std::os::unix::io::RawFd, - size: Size, -) -> nix::Result<()> { - let size = size.into(); - // safe because std::fs::File is required to contain a valid file - // descriptor and size is guaranteed to be initialized because it's a - // normal rust value, and nix::pty::Winsize is a repr(C) struct with the - // same layout as `struct winsize` from sys/ioctl.h. - unsafe { - set_term_size_unsafe(fd, ::std::ptr::NonNull::from(&size).as_ptr()) + fn poll_close( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + std::pin::Pin::new(&mut &self.pt).poll_close(cx) } - .map(|_| ()) } -- cgit v1.2.3-54-g00ecf