aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2021-02-23 00:17:01 -0500
committerJesse Luehrs <doy@tozt.net>2021-02-23 00:17:01 -0500
commitf3e8046eff473aa9bf940b7fbd156cf3dfbfa352 (patch)
treea6b3ed53e89556cd801a49a0619ba37e4c397be6
parentacb3681ee251599af194c8555344edc65750ef14 (diff)
downloadpty-process-f3e8046eff473aa9bf940b7fbd156cf3dfbfa352.tar.gz
pty-process-f3e8046eff473aa9bf940b7fbd156cf3dfbfa352.zip
also create separate pty structs per backend
for now, they are identical, but i will change them to be specialized next
-rw-r--r--Cargo.toml2
-rw-r--r--examples/basic.rs2
-rw-r--r--src/async_std.rs2
-rw-r--r--src/command.rs41
-rw-r--r--src/command/async_process.rs1
-rw-r--r--src/command/std.rs1
-rw-r--r--src/command/tokio.rs1
-rw-r--r--src/lib.rs9
-rw-r--r--src/pty.rs74
-rw-r--r--src/pty/async_io.rs36
-rw-r--r--src/pty/std.rs36
-rw-r--r--src/pty/tokio.rs36
-rw-r--r--src/std.rs2
-rw-r--r--src/tokio.rs2
14 files changed, 184 insertions, 61 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 27e5bf1..6357d07 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,6 +9,7 @@ libc = "*"
nix = "0.17"
thiserror = "1.0"
+async-io = { version = "1.3", optional = true }
async-process = { version = "1.0", optional = true }
tokio = { version = "1.2", optional = true, features = ["process"] }
@@ -16,3 +17,4 @@ tokio = { version = "1.2", optional = true, features = ["process"] }
default = ["std"]
std = []
+async-std = ["async-io", "async-process"]
diff --git a/examples/basic.rs b/examples/basic.rs
index d7f99d0..bc9389c 100644
--- a/examples/basic.rs
+++ b/examples/basic.rs
@@ -35,7 +35,7 @@ impl Drop for RawGuard {
}
}
-fn run(child: &pty_process::Child<std::process::Child>) {
+fn run(child: &pty_process::std::Child) {
let _raw = RawGuard::new();
let mut buf = [0_u8; 4096];
let pty = child.pty().as_raw_fd();
diff --git a/src/async_std.rs b/src/async_std.rs
new file mode 100644
index 0000000..e91a18d
--- /dev/null
+++ b/src/async_std.rs
@@ -0,0 +1,2 @@
+pub type Child =
+ crate::command::Child<async_process::Child, crate::pty::async_io::Pty>;
diff --git a/src/command.rs b/src/command.rs
index 0b53626..4679579 100644
--- a/src/command.rs
+++ b/src/command.rs
@@ -1,34 +1,38 @@
use crate::error::*;
+use crate::pty::Pty as _;
use ::std::os::unix::io::AsRawFd as _;
mod std;
-#[cfg(feature = "async-process")]
+#[cfg(feature = "async-std")]
mod async_process;
#[cfg(feature = "tokio")]
mod tokio;
pub trait Command {
type Child;
+ type Pty;
fn spawn_pty(
&mut self,
size: Option<&crate::pty::Size>,
- ) -> Result<Child<Self::Child>>;
+ ) -> Result<Child<Self::Child, Self::Pty>>;
}
impl<T> Command for T
where
T: CommandImpl,
+ T::Pty: crate::pty::Pty,
{
type Child = T::Child;
+ type Pty = T::Pty;
fn spawn_pty(
&mut self,
size: Option<&crate::pty::Size>,
- ) -> Result<Child<Self::Child>> {
- let (pty, pts, stdin, stdout, stderr) = setup_pty(size)?;
+ ) -> Result<Child<Self::Child, Self::Pty>> {
+ let (pty, pts, stdin, stdout, stderr) = setup_pty::<Self::Pty>(size)?;
let pt_fd = pty.pt().as_raw_fd();
let pts_fd = pts.as_raw_fd();
@@ -69,12 +73,15 @@ where
}
}
-pub struct Child<T> {
- child: T,
- pty: crate::pty::Pty,
+pub struct Child<C, P> {
+ child: C,
+ pty: P,
}
-impl<T> Child<T> {
+impl<C, P> Child<C, P>
+where
+ P: crate::pty::Pty,
+{
pub fn pty(&self) -> &::std::fs::File {
self.pty.pt()
}
@@ -84,15 +91,15 @@ impl<T> Child<T> {
}
}
-impl<T> ::std::ops::Deref for Child<T> {
- type Target = T;
+impl<C, P> ::std::ops::Deref for Child<C, P> {
+ type Target = C;
fn deref(&self) -> &Self::Target {
&self.child
}
}
-impl<T> ::std::ops::DerefMut for Child<T> {
+impl<C, P> ::std::ops::DerefMut for Child<C, P> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.child
}
@@ -101,6 +108,7 @@ impl<T> ::std::ops::DerefMut for Child<T> {
// XXX shouldn't be pub?
pub trait CommandImpl {
type Child;
+ type Pty;
fn std_fds(
&mut self,
@@ -114,16 +122,19 @@ pub trait CommandImpl {
fn spawn_impl(&mut self) -> ::std::io::Result<Self::Child>;
}
-fn setup_pty(
+fn setup_pty<P>(
size: Option<&crate::pty::Size>,
) -> Result<(
- crate::pty::Pty,
+ P,
::std::fs::File,
::std::os::unix::io::RawFd,
::std::os::unix::io::RawFd,
::std::os::unix::io::RawFd,
-)> {
- let pty = crate::pty::Pty::new()?;
+)>
+where
+ P: crate::pty::Pty,
+{
+ let pty = P::new()?;
if let Some(size) = size {
pty.resize(size)?;
}
diff --git a/src/command/async_process.rs b/src/command/async_process.rs
index 4c453e6..4248402 100644
--- a/src/command/async_process.rs
+++ b/src/command/async_process.rs
@@ -3,6 +3,7 @@ use std::os::unix::io::FromRawFd as _;
impl super::CommandImpl for async_process::Command {
type Child = async_process::Child;
+ type Pty = crate::pty::async_io::Pty;
fn std_fds(
&mut self,
diff --git a/src/command/std.rs b/src/command/std.rs
index 3287834..f1c5418 100644
--- a/src/command/std.rs
+++ b/src/command/std.rs
@@ -3,6 +3,7 @@ use std::os::unix::process::CommandExt as _;
impl super::CommandImpl for std::process::Command {
type Child = std::process::Child;
+ type Pty = crate::pty::std::Pty;
fn std_fds(
&mut self,
diff --git a/src/command/tokio.rs b/src/command/tokio.rs
index 60dfb56..67baf74 100644
--- a/src/command/tokio.rs
+++ b/src/command/tokio.rs
@@ -2,6 +2,7 @@ use std::os::unix::io::FromRawFd as _;
impl super::CommandImpl for tokio::process::Command {
type Child = tokio::process::Child;
+ type Pty = crate::pty::tokio::Pty;
fn std_fds(
&mut self,
diff --git a/src/lib.rs b/src/lib.rs
index 112bec1..76bbf9c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,6 +1,13 @@
mod command;
-pub use command::{Child, Command};
+pub use command::Command;
mod error;
pub use error::{Error, Result};
mod pty;
pub use pty::{Pty, Size};
+
+pub mod std;
+
+#[cfg(feature = "async-std")]
+pub mod async_std;
+#[cfg(feature = "tokio")]
+pub mod tokio;
diff --git a/src/pty.rs b/src/pty.rs
index ad4dfcf..f192298 100644
--- a/src/pty.rs
+++ b/src/pty.rs
@@ -1,6 +1,24 @@
use crate::error::*;
-use std::os::unix::io::{AsRawFd as _, FromRawFd as _, IntoRawFd as _};
+use ::std::os::unix::io::{AsRawFd as _, IntoRawFd as _};
+
+pub mod std;
+
+#[cfg(feature = "async-std")]
+pub mod async_io;
+#[cfg(feature = "tokio")]
+pub mod tokio;
+
+pub trait Pty {
+ fn new() -> Result<Self>
+ where
+ Self: Sized;
+ fn pt(&self) -> &::std::fs::File;
+ fn pts(&self) -> Result<::std::fs::File>;
+ fn resize(&self, size: &super::Size) -> Result<()> {
+ set_term_size(self.pt(), size).map_err(Error::SetTermSize)
+ }
+}
pub struct Size {
row: u16,
@@ -45,51 +63,19 @@ impl From<&Size> for nix::pty::Winsize {
}
}
-pub struct Pty {
- pt: std::fs::File,
- ptsname: std::path::PathBuf,
-}
-
-impl Pty {
- pub fn new() -> Result<Self> {
- let pt = nix::pty::posix_openpt(
- nix::fcntl::OFlag::O_RDWR | nix::fcntl::OFlag::O_NOCTTY,
- )
- .map_err(Error::CreatePty)?;
- nix::pty::grantpt(&pt).map_err(Error::CreatePty)?;
- nix::pty::unlockpt(&pt).map_err(Error::CreatePty)?;
-
- let ptsname =
- nix::pty::ptsname_r(&pt).map_err(Error::CreatePty)?.into();
-
- let pt_fd = pt.into_raw_fd();
+fn create_pt() -> 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(Error::CreatePty)?;
+ nix::pty::grantpt(&pt).map_err(Error::CreatePty)?;
+ nix::pty::unlockpt(&pt).map_err(Error::CreatePty)?;
- // 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 pt = unsafe { std::fs::File::from_raw_fd(pt_fd) };
+ let ptsname = nix::pty::ptsname_r(&pt).map_err(Error::CreatePty)?.into();
- Ok(Self { pt, ptsname })
- }
-
- pub fn pt(&self) -> &std::fs::File {
- &self.pt
- }
+ let pt_fd = pt.into_raw_fd();
- pub fn pts(&self) -> Result<std::fs::File> {
- let fh = std::fs::OpenOptions::new()
- .read(true)
- .write(true)
- .open(&self.ptsname)
- .map_err(|e| Error::OpenPts(self.ptsname.clone(), e))?;
- Ok(fh)
- }
-
- pub fn resize(&self, size: &Size) -> Result<()> {
- set_term_size(self.pt(), size).map_err(Error::SetTermSize)
- }
+ Ok((pt_fd, ptsname))
}
nix::ioctl_write_ptr_bad!(
@@ -98,7 +84,7 @@ nix::ioctl_write_ptr_bad!(
nix::pty::Winsize
);
-fn set_term_size(file: &std::fs::File, size: &Size) -> nix::Result<()> {
+fn set_term_size(file: &::std::fs::File, size: &Size) -> nix::Result<()> {
let size = size.into();
let fd = file.as_raw_fd();
// safe because std::fs::File is required to contain a valid file
diff --git a/src/pty/async_io.rs b/src/pty/async_io.rs
new file mode 100644
index 0000000..84097f9
--- /dev/null
+++ b/src/pty/async_io.rs
@@ -0,0 +1,36 @@
+use crate::error::*;
+
+use std::os::unix::io::FromRawFd as _;
+
+pub struct Pty {
+ pt: std::fs::File,
+ ptsname: std::path::PathBuf,
+}
+
+impl super::Pty for Pty {
+ fn new() -> Result<Self> {
+ let (pt_fd, ptsname) = super::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 pt = unsafe { std::fs::File::from_raw_fd(pt_fd) };
+
+ Ok(Self { pt, ptsname })
+ }
+
+ fn pt(&self) -> &std::fs::File {
+ &self.pt
+ }
+
+ fn pts(&self) -> Result<std::fs::File> {
+ let fh = std::fs::OpenOptions::new()
+ .read(true)
+ .write(true)
+ .open(&self.ptsname)
+ .map_err(|e| Error::OpenPts(self.ptsname.clone(), e))?;
+ Ok(fh)
+ }
+}
diff --git a/src/pty/std.rs b/src/pty/std.rs
new file mode 100644
index 0000000..84097f9
--- /dev/null
+++ b/src/pty/std.rs
@@ -0,0 +1,36 @@
+use crate::error::*;
+
+use std::os::unix::io::FromRawFd as _;
+
+pub struct Pty {
+ pt: std::fs::File,
+ ptsname: std::path::PathBuf,
+}
+
+impl super::Pty for Pty {
+ fn new() -> Result<Self> {
+ let (pt_fd, ptsname) = super::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 pt = unsafe { std::fs::File::from_raw_fd(pt_fd) };
+
+ Ok(Self { pt, ptsname })
+ }
+
+ fn pt(&self) -> &std::fs::File {
+ &self.pt
+ }
+
+ fn pts(&self) -> Result<std::fs::File> {
+ let fh = std::fs::OpenOptions::new()
+ .read(true)
+ .write(true)
+ .open(&self.ptsname)
+ .map_err(|e| Error::OpenPts(self.ptsname.clone(), e))?;
+ Ok(fh)
+ }
+}
diff --git a/src/pty/tokio.rs b/src/pty/tokio.rs
new file mode 100644
index 0000000..84097f9
--- /dev/null
+++ b/src/pty/tokio.rs
@@ -0,0 +1,36 @@
+use crate::error::*;
+
+use std::os::unix::io::FromRawFd as _;
+
+pub struct Pty {
+ pt: std::fs::File,
+ ptsname: std::path::PathBuf,
+}
+
+impl super::Pty for Pty {
+ fn new() -> Result<Self> {
+ let (pt_fd, ptsname) = super::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 pt = unsafe { std::fs::File::from_raw_fd(pt_fd) };
+
+ Ok(Self { pt, ptsname })
+ }
+
+ fn pt(&self) -> &std::fs::File {
+ &self.pt
+ }
+
+ fn pts(&self) -> Result<std::fs::File> {
+ let fh = std::fs::OpenOptions::new()
+ .read(true)
+ .write(true)
+ .open(&self.ptsname)
+ .map_err(|e| Error::OpenPts(self.ptsname.clone(), e))?;
+ Ok(fh)
+ }
+}
diff --git a/src/std.rs b/src/std.rs
new file mode 100644
index 0000000..fa07499
--- /dev/null
+++ b/src/std.rs
@@ -0,0 +1,2 @@
+pub type Child =
+ crate::command::Child<std::process::Child, crate::pty::std::Pty>;
diff --git a/src/tokio.rs b/src/tokio.rs
new file mode 100644
index 0000000..289d659
--- /dev/null
+++ b/src/tokio.rs
@@ -0,0 +1,2 @@
+pub type Child =
+ crate::command::Child<tokio::process::Child, crate::pty::tokio::Pty>;