async-ssh2-lite 0.5.0

Asynchronous ssh2.
Documentation
use core::{
    task::{Context, Poll},
    time::Duration,
};
use std::io::Error as IoError;

use async_trait::async_trait;
use ssh2::{BlockDirections, Error as Ssh2Error, Session};

use crate::error::Error;

//
#[cfg(feature = "async-io")]
mod impl_async_io;
#[cfg(feature = "tokio")]
mod impl_tokio;

//
#[async_trait]
pub trait AsyncSessionStream {
    //
    async fn x_with<R>(
        &self,
        op: impl FnMut() -> Result<R, Ssh2Error> + Send,
        sess: &Session,
        expected_block_directions: BlockDirections,
        sleep_dur: Option<Duration>,
    ) -> Result<R, Error>;

    async fn rw_with<R>(
        &self,
        op: impl FnMut() -> Result<R, Ssh2Error> + Send,
        sess: &Session,
    ) -> Result<R, Error> {
        self.x_with(
            op,
            sess,
            BlockDirections::Both,
            Some(Duration::from_millis(1)),
        )
        .await
    }

    async fn none_with<R>(
        &self,
        op: impl FnMut() -> Result<R, Ssh2Error> + Send,
        sess: &Session,
    ) -> Result<R, Error> {
        self.x_with(
            op,
            sess,
            BlockDirections::None,
            Some(Duration::from_millis(1)),
        )
        .await
    }

    async fn read_with<R>(
        &self,
        op: impl FnMut() -> Result<R, Ssh2Error> + Send,
        sess: &Session,
    ) -> Result<R, Error> {
        self.x_with(
            op,
            sess,
            BlockDirections::Inbound,
            Some(Duration::from_millis(1)),
        )
        .await
    }

    async fn write_with<R>(
        &self,
        op: impl FnMut() -> Result<R, Ssh2Error> + Send,
        sess: &Session,
    ) -> Result<R, Error> {
        self.x_with(
            op,
            sess,
            BlockDirections::Outbound,
            Some(Duration::from_millis(1)),
        )
        .await
    }

    //
    fn poll_x_with<R>(
        &self,
        cx: &mut Context,
        op: impl FnMut() -> Result<R, IoError> + Send,
        sess: &Session,
        expected_block_directions: BlockDirections,
        sleep_dur: Option<Duration>,
    ) -> Poll<Result<R, IoError>>;

    fn poll_read_with<R>(
        &self,
        cx: &mut Context,
        op: impl FnMut() -> Result<R, IoError> + Send,
        sess: &Session,
    ) -> Poll<Result<R, IoError>> {
        self.poll_x_with(
            cx,
            op,
            sess,
            BlockDirections::Inbound,
            Some(Duration::from_millis(1)),
        )
    }

    fn poll_write_with<R>(
        &self,
        cx: &mut Context,
        op: impl FnMut() -> Result<R, IoError> + Send,
        sess: &Session,
    ) -> Poll<Result<R, IoError>> {
        self.poll_x_with(
            cx,
            op,
            sess,
            BlockDirections::Both,
            Some(Duration::from_millis(1)),
        )
    }
}

//
pub trait BlockDirectionsExt {
    fn is_readable(&self) -> bool;
    fn is_writable(&self) -> bool;
}
impl BlockDirectionsExt for BlockDirections {
    fn is_readable(&self) -> bool {
        matches!(self, BlockDirections::Inbound | BlockDirections::Both)
    }

    fn is_writable(&self) -> bool {
        matches!(self, BlockDirections::Outbound | BlockDirections::Both)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_block_directions_ext() {
        assert!(!BlockDirections::None.is_readable());
        assert!(!BlockDirections::None.is_writable());
        assert!(BlockDirections::Inbound.is_readable());
        assert!(!BlockDirections::Inbound.is_writable());
        assert!(!BlockDirections::Outbound.is_readable());
        assert!(BlockDirections::Outbound.is_writable());
        assert!(BlockDirections::Both.is_readable());
        assert!(BlockDirections::Both.is_writable());
    }
}