tros 0.6.0

Your tros from tarantool TX thread to tokio(..and others!)
Documentation
use crate::error::Result;

#[cfg(feature = "tp-cbus")]
pub mod cbus;
#[cfg(feature = "tp-poll")]
pub mod poll;

#[cfg(feature = "picodata")]
pub type PicodataTransport<'a> = cbus::CBusTransport<'a>;

#[cfg(feature = "vanilla")]
pub type VanillaTransport = poll::PollTransport;

/// `Transport` describes a method of transferring data
/// from tarantool side to the external runtime side and vice verse.
pub trait Transport {
    type Sender<T>: TransportSender<T> + Send
    where
        T: Send;
    type Receiver<T>: TransportReceiver<T>
    where
        T: Send;

    fn create_channel<T: Send>(&self) -> (Self::Sender<T>, Self::Receiver<T>);
}

// Attribute `enum_dispatch` is added only for test purposes - to construct general type.
// Those traits can't be dispatched normally(through `dyn` keyword),
// because methods take `self` as an argument.

#[cfg_attr(feature = "test", enum_dispatch::enum_dispatch)]
pub trait TransportSender<T> {
    fn send(self, data: T) -> Result<()>;
}

#[cfg_attr(feature = "test", enum_dispatch::enum_dispatch)]
pub trait TransportReceiver<T> {
    fn receive(self) -> Result<T>;
}

#[cfg(feature = "test")]
pub mod test {
    //! Provides test utilities.
    //!
    //! When you add new transport, consider altering this module as well.
    //! You should alter several underlying places:
    //! 1) Add new [GeneralTransport] enum variant;
    //! 2) Add new [GeneralTransportSender] enum variant;
    //! 3) Add new [GeneralTransportReceiver] enum variant;
    //! 4) Add channel creation method to newly created variant at [GeneralTransport::create_channel];
    //! 5) Add possible transport configurations to [GeneralTransport::all_iter()].
    //!     You may freely add multiple instances configs for a single transport type.
    use std::iter::{empty, once_with};

    use super::{cbus::CBusTransport, poll::PollTransport, *};
    use enum_dispatch::enum_dispatch;

    /// `GeneralTransport` unites all possible transports in a single place for tests.
    /// Using it, one can run single test for various transports.
    /// When you add new transport, consider adding it there as well to test it.
    #[derive(Debug)]
    pub enum GeneralTransport<'a> {
        CBus(CBusTransport<'a>),
        Poll(PollTransport),
    }

    impl<'a> GeneralTransport<'a> {
        /// An iterator over all possible transports for testing.
        /// It constructs needed iterators lazily.
        ///
        /// When you add new transport, add its possible instances there as well.
        /// You may freely add several variations of single transport to test various configs.
        pub fn all_iter() -> impl Iterator<Item = GeneralTransport<'static>> {
            empty()
                .chain(once_with(|| GeneralTransport::CBus(Default::default())))
                .chain(once_with(|| {
                    GeneralTransport::Poll(PollTransport::default())
                }))
        }
    }

    // We can't use `enum_dispatch` here as trait has associated types,
    // so we manually implement transport trait.
    impl<'a> Transport for GeneralTransport<'a> {
        type Sender<T> = GeneralTransportSender<'a, T>
        where
            T: Send;

        type Receiver<T> = GeneralTransportReceiver<'a, T>
        where
            T: Send;

        fn create_channel<T: Send>(&self) -> (Self::Sender<T>, Self::Receiver<T>) {
            match self {
                GeneralTransport::CBus(tp) => cast_channel(tp.create_channel()),
                GeneralTransport::Poll(tp) => cast_channel(tp.create_channel()),
            }
        }
    }

    #[enum_dispatch(TransportSender<T>)]
    pub enum GeneralTransportSender<'a, T: Send> {
        CBus(<CBusTransport<'a> as Transport>::Sender<T>),
        Poll(<PollTransport as Transport>::Sender<T>),
    }

    #[enum_dispatch(TransportReceiver<T>)]
    pub enum GeneralTransportReceiver<'a, T: Send> {
        CBus(<CBusTransport<'a> as Transport>::Receiver<T>),
        Poll(<PollTransport as Transport>::Receiver<T>),
    }

    /// Transforms (sender, receiver) pair to the needed more general types.
    fn cast_channel<TX, RX, ToTX: From<TX>, ToRX: From<RX>>((tx, rx): (TX, RX)) -> (ToTX, ToRX) {
        (tx.into(), rx.into())
    }
}