trapeze 0.2.0

A rust implementation of ttrpc
Documentation
use std::future::Future;
use std::ops::Deref;
use std::time::Duration;

use crate::{Result, Status};

#[derive(Clone, Copy, Debug)]
pub enum Timeout {
    None,
    Duration(Duration),
}

impl Default for Timeout {
    fn default() -> Self {
        Self::None
    }
}

impl Deref for Timeout {
    type Target = Duration;
    fn deref(&self) -> &Self::Target {
        match self {
            Timeout::None => &Duration::ZERO,
            Timeout::Duration(t) => t,
        }
    }
}

pub trait WithTimeout {
    type Ouput;
    fn with_timeout(self, t: impl Into<Timeout>) -> impl Future<Output = Result<Self::Ouput>>;
}

impl<Output, F: Future<Output = Result<Output>>> WithTimeout for F {
    type Ouput = Output;
    async fn with_timeout(self, t: impl Into<Timeout>) -> Result<Self::Ouput> {
        let Timeout::Duration(t) = t.into() else {
            return self.await;
        };

        let Ok(output) = tokio::time::timeout(t, self).await else {
            return Err(Status::timeout());
        };

        output
    }
}

const MAX_TIMEOUT: Duration = Duration::from_nanos(i64::MAX as u64);

impl From<Option<Duration>> for Timeout {
    fn from(value: Option<Duration>) -> Self {
        match value {
            Some(t) => t.into(),
            _ => Timeout::None,
        }
    }
}

impl From<Duration> for Timeout {
    fn from(t: Duration) -> Self {
        if t.is_zero() {
            return Timeout::None;
        }
        Timeout::Duration(t.min(MAX_TIMEOUT))
    }
}

impl Timeout {
    pub fn from_nanos(nanos: i64) -> Self {
        Some(Duration::from_nanos(nanos.max(0) as u64)).into()
    }

    pub fn as_nanos(&self) -> i64 {
        self.deref().as_nanos().min(i64::MAX as u128) as i64
    }
}