Skip to content

Commit

Permalink
Improve documentation
Browse files Browse the repository at this point in the history
Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
  • Loading branch information
zhiburt committed Feb 19, 2022
1 parent 2d5caab commit 26e51ac
Show file tree
Hide file tree
Showing 20 changed files with 336 additions and 135 deletions.
16 changes: 8 additions & 8 deletions examples/bash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ fn main() {
p.expect_prompt().unwrap(); // go sure `wc` is really done
println!(
"/etc/passwd has {} lines, {} words, {} chars",
String::from_utf8_lossy(lines.first()),
String::from_utf8_lossy(words.first()),
String::from_utf8_lossy(bytes.first()),
String::from_utf8_lossy(lines.matches()[0]),
String::from_utf8_lossy(words.matches()[0]),
String::from_utf8_lossy(bytes.matches()[0]),
);

// case 3: read while program is still executing
Expand All @@ -36,7 +36,7 @@ fn main() {
let duration = p.expect(Regex("[0-9. ]+ ms")).unwrap();
println!(
"Roundtrip time: {}",
String::from_utf8_lossy(duration.first())
String::from_utf8_lossy(duration.matches()[0])
);
}

Expand Down Expand Up @@ -67,9 +67,9 @@ fn main() {
p.expect_prompt().await.unwrap(); // go sure `wc` is really done
println!(
"/etc/passwd has {} lines, {} words, {} chars",
String::from_utf8_lossy(lines.first()),
String::from_utf8_lossy(words.first()),
String::from_utf8_lossy(bytes.first()),
String::from_utf8_lossy(lines.matches()[0]),
String::from_utf8_lossy(words.matches()[0]),
String::from_utf8_lossy(bytes.matches()[0]),
);

// case 3: read while program is still executing
Expand All @@ -79,7 +79,7 @@ fn main() {
let duration = p.expect(Regex("[0-9. ]+ ms")).await.unwrap();
println!(
"Roundtrip time: {}",
String::from_utf8_lossy(duration.first())
String::from_utf8_lossy(duration.matches()[0])
);
}

Expand Down
12 changes: 6 additions & 6 deletions examples/expect_line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@ fn main() {

println!("{:?}", String::from_utf8_lossy(m.as_bytes()));

let is_eof = m.first().is_empty();
let is_eof = m.matches()[0].is_empty();
if is_eof {
break;
}

if m.first() == [b'\n'] {
if m.matches()[0] == [b'\n'] {
continue;
}

println!("{:?}", String::from_utf8_lossy(m.first()));
println!("{:?}", String::from_utf8_lossy(m.matches()[0]));
}
}

Expand All @@ -43,16 +43,16 @@ fn main() {
.await
.expect("Expect failed");

let is_eof = m.first().is_empty();
let is_eof = m.matches()[0].is_empty();
if is_eof {
break;
}

if m.first() == [b'\n'] {
if m.matches()[0] == [b'\n'] {
continue;
}

println!("{:?}", String::from_utf8_lossy(m.first()));
println!("{:?}", String::from_utf8_lossy(m.matches()[0]));
}
})
}
12 changes: 6 additions & 6 deletions examples/powershell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ fn main() {
p.expect_prompt().await.unwrap();
println!(
"/etc/passwd has {} lines, {} words, {} chars",
String::from_utf8_lossy(lines.first()),
String::from_utf8_lossy(words.first()),
String::from_utf8_lossy(lines.matches()[0]),
String::from_utf8_lossy(words.matches()[0]),
String::from_utf8_lossy(bytes.matches()[1]),
);

Expand All @@ -38,7 +38,7 @@ fn main() {
let duration = p.expect(Regex("[0-9.]+ms")).await.unwrap();
println!(
"Roundtrip time: {}",
String::from_utf8_lossy(duration.first())
String::from_utf8_lossy(duration.matches()[0])
);
}

Expand Down Expand Up @@ -67,8 +67,8 @@ fn main() {
p.expect_prompt().unwrap();
println!(
"/etc/passwd has {} lines, {} words, {} chars",
String::from_utf8_lossy(lines.first()),
String::from_utf8_lossy(words.first()),
String::from_utf8_lossy(lines.matches()[0]),
String::from_utf8_lossy(words.matches()[0]),
String::from_utf8_lossy(bytes.matches()[1]),
);

Expand All @@ -78,7 +78,7 @@ fn main() {
let duration = p.expect(Regex("[0-9.]+ms")).unwrap();
println!(
"Roundtrip time: {}",
String::from_utf8_lossy(duration.first())
String::from_utf8_lossy(duration.matches()[0])
);
}

Expand Down
4 changes: 2 additions & 2 deletions examples/python.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ fn main() {

let found = p.expect(Regex(r"'.*'")).unwrap();

println!("Platform {}", String::from_utf8_lossy(found.first()));
println!("Platform {}", String::from_utf8_lossy(found.matches()[0]));
}

#[cfg(feature = "async")]
Expand All @@ -22,6 +22,6 @@ fn main() {

let found = p.expect(Regex(r"'.*'")).await.unwrap();

println!("Platform {}", String::from_utf8_lossy(found.first()));
println!("Platform {}", String::from_utf8_lossy(found.matches()[0]));
})
}
2 changes: 2 additions & 0 deletions src/control_code.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! A module which contains [ControlCode] type.

use std::convert::TryFrom;

/// ControlCode represents the standard ASCII control codes [wiki]
Expand Down
4 changes: 2 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub enum Error {
}

impl Error {
pub fn unknown(message: impl Into<String>, err: impl Display) -> Error {
pub(crate) fn unknown(message: impl Into<String>, err: impl Display) -> Error {
Self::Other {
message: message.into(),
origin: err.to_string(),
Expand Down Expand Up @@ -44,6 +44,6 @@ impl From<io::Error> for Error {
}
}

pub fn to_io_error<E: Display>(message: &'static str) -> impl FnOnce(E) -> io::Error {
pub(crate) fn to_io_error<E: Display>(message: &'static str) -> impl FnOnce(E) -> io::Error {
move |e: E| io::Error::new(io::ErrorKind::Other, format!("{}; {}", message, e))
}
6 changes: 0 additions & 6 deletions src/found.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,6 @@ impl Found {
self.matches.is_empty()
}

/// First returns a first match.
pub fn first(&self) -> &[u8] {
let m = &self.matches[0];
&self.buf[m.start()..m.end()]
}

/// Matches returns a list of matches.
pub fn matches(&self) -> Vec<&[u8]> {
self.matches
Expand Down
2 changes: 1 addition & 1 deletion src/interact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use std::{
io::{self, Read, Stdout, Write},
};

/// InteractOptions represents options of an interact session.
/// InteractOptions represents options of an interactive session.
pub struct InteractOptions<P, S, R, W, C> {
escape_character: u8,
input_filter: Option<FilterFn>,
Expand Down
2 changes: 2 additions & 0 deletions src/needle.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! A module which contains a [Needle] trait and a list of implementations.

use crate::error::Error;

/// Needle an interface for search of a match in a buffer.
Expand Down
19 changes: 19 additions & 0 deletions src/process/mod.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,50 @@
//! This module contains a platform independent abstraction over an os process.

use std::io::Result;

#[cfg(unix)]
pub mod unix;
#[cfg(windows)]
pub mod windows;

/// This trait represents a platform independent process which runs a program.
pub trait Process: Sized {
/// A command which process can run.
type Command;
/// A representation of IO stream of communication with a programm a process is running.
type Stream;

/// Spawn parses a given string as a commandline string and spawns it on a process.
fn spawn<S: AsRef<str>>(cmd: S) -> Result<Self>;
/// Spawn_command runs a process with a given command.
fn spawn_command(command: Self::Command) -> Result<Self>;
/// It opens a IO stream with a spawned process.
fn open_stream(&mut self) -> Result<Self::Stream>;
}

/// Healthcheck represents a check by which we can determine if a spawned process is still alive.
pub trait Healthcheck {
/// The function returns a status of a process if it still alive and it can operate.
fn is_alive(&mut self) -> Result<bool>;
}

/// NonBlocking interface represens a [std::io::Read]er which can be turned in a non blocking mode
/// so its read operations will return imideately.
pub trait NonBlocking {
/// Sets a [std::io::Read]er into a non blocking mode.
fn set_non_blocking(&mut self) -> Result<()>;
/// Sets a [std::io::Read]er back into a blocking mode.
fn set_blocking(&mut self) -> Result<()>;
}

#[cfg(feature = "async")]
/// IntoAsyncStream interface turns a [Process::Stream] into an async version.
/// To be used with `async`/`await`syntax
pub trait IntoAsyncStream {
/// AsyncStream type.
/// Like [Process::Stream] but it represents an async IO stream.
type AsyncsStream;

/// Turns an object into a async stream.
fn into_async_stream(self) -> Result<Self::AsyncsStream>;
}
3 changes: 3 additions & 0 deletions src/process/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use std::{
process::Command,
};

/// A Unix representation of a [Process] via [PtyProcess]
pub struct UnixProcess {
proc: PtyProcess,
}
Expand Down Expand Up @@ -80,6 +81,7 @@ impl DerefMut for UnixProcess {
}
}

/// A IO stream (write/read) of [UnixProcess].
#[derive(Debug)]
pub struct PtyStream {
handle: Stream,
Expand Down Expand Up @@ -172,6 +174,7 @@ impl AsRawFd for PtyStream {
}
}

/// An async version of IO stream of [UnixProcess].
#[cfg(feature = "async")]
pub struct AsyncPtyStream {
stream: async_io::Async<PtyStream>,
Expand Down
4 changes: 3 additions & 1 deletion src/process/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ use std::{
task::{Context, Poll},
};

/// A windows representation of a [Process] via [conpty::Process].
pub struct WinProcess {
proc: Process,
}

impl ProcessTrait for WinProcess {
type Command = ProcAttr;

type Stream = ProcessStream;

fn spawn<S: AsRef<str>>(cmd: S) -> Result<Self> {
Expand Down Expand Up @@ -68,6 +68,7 @@ impl DerefMut for WinProcess {
}
}

/// An IO stream of [WinProcess].
#[derive(Debug)]
pub struct ProcessStream {
pub input: PipeWriter,
Expand Down Expand Up @@ -119,6 +120,7 @@ impl IntoAsyncStream for ProcessStream {
}
}

/// An async version of IO stream of [WinProcess].
#[cfg(feature = "async")]
pub struct AsyncProcessStream {
stream: blocking::Unblock<ProcessStream>,
Expand Down
39 changes: 31 additions & 8 deletions src/session/async_session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,33 @@ impl<P, S> Session<P, S> {
}

impl<P, S: AsyncRead + Unpin> Session<P, S> {
/// Expect waits until a pattern is matched.
///
/// If the method returns [Ok] it is guaranteed that at least 1 match was found.
///
/// This make assertions in a lazy manner. Starts from 1st byte then checks 2nd byte and goes further.
/// It is done intentinally to be presize.
/// Here's an example,
/// when you call this method with [crate::Regex] and output contains 123, expect will return ‘1’ as a match not ‘123’.
///
/// # Example
///
/// ```
/// # futures_lite::future::block_on(async {
/// let mut p = expectrl::spawn("echo 123").unwrap();
/// let m = p.expect(expectrl::Regex("\\d+")).await.unwrap();
/// assert_eq!(m.matches()[0], b"1");
/// #});
/// ```
///
/// This behaviour is different from [Session::check].
///
/// It returns an error if timeout is reached.
/// You can specify a timeout value by [Session::set_expect_timeout] method.
pub async fn expect<N: Needle>(&mut self, needle: N) -> Result<Found, Error> {
self.stream.expect(needle).await
}

/// Is matched checks if a pattern is matched.
/// It doesn't consumes bytes from stream.
pub async fn is_matched<E: Needle>(&mut self, needle: E) -> Result<bool, Error> {
self.stream.is_matched(needle).await
}

/// Check checks if a pattern is matched.
/// Returns empty found structure if nothing found.
///
Expand All @@ -74,13 +91,19 @@ impl<P, S: AsyncRead + Unpin> Session<P, S> {
/// // wait to guarantee that check will successed (most likely)
/// std::thread::sleep(std::time::Duration::from_secs(1));
/// let m = p.check(expectrl::Regex("\\d+")).await.unwrap();
/// assert_eq!(m.first(), b"123");
/// assert_eq!(m.matches()[0], b"123");
/// # });
/// ```
pub async fn check<E: Needle>(&mut self, needle: E) -> Result<Found, Error> {
self.stream.check(needle).await
}

/// Is matched checks if a pattern is matched.
/// It doesn't consumes bytes from stream.
pub async fn is_matched<E: Needle>(&mut self, needle: E) -> Result<bool, Error> {
self.stream.is_matched(needle).await
}

/// Verifyes if stream is empty or not.
pub async fn is_empty(&mut self) -> io::Result<bool> {
self.stream.is_empty().await
Expand Down Expand Up @@ -333,7 +356,7 @@ impl<S: AsyncRead + Unpin> Stream<S> {
/// // wait to guarantee that check will successed (most likely)
/// std::thread::sleep(std::time::Duration::from_secs(1));
/// let m = p.check(expectrl::Regex("\\d+")).await.unwrap();
/// assert_eq!(m.first(), b"123");
/// assert_eq!(m.matches()[0], b"123");
/// # });
/// ```
#[cfg(feature = "async")]
Expand Down

0 comments on commit 26e51ac

Please sign in to comment.