dittolive-ditto 4.9.2

Ditto is a peer to peer cross-platform database that allows mobile, web, IoT and server apps to sync with or without an internet connection.
Documentation
use super::*;

/// A factory that can open a single [`StreamCandidate`].
///
/// While you can use the `OverloadId` pattern to define your own factories regardless of whether or
/// not you own their type, the common use cases should be covered by its two main implementations:
/// - [`WriteOnly`] is the advised [`CandidateHandler`] when you don't care about received data
///   (which will be dropped immediately if any arrives), but want to use the [`Stream`] to send
///   data.
/// - Any function that returns a handler that implments [`IntoChannel<_, Payload>`] will see its
///   return value used to [`StreamCandidate::open`], yielding a [`Stream<_>`] that wraps the
///   [`IntoChannel::Receiver`].
///
/// These factories can be passed to [`ConnectionBuilder::on_receive_factory`] and
/// [`AcceptorBuilder::on_receive_factory`] to simplify the handling of the [`StreamCandidate`] step
/// of setting up a [`Stream`].
pub trait SingleCandidateHandler<OverloadId>: Send + Sync + 'static {
    /// Typically [`Stream`], but may be [`StreamCandidate`] or any other type if necessary.
    type Output;
    /// Typically a call to [`StreamCandidate::open`] or [`StreamCandidate::open_write_only`].
    fn open_once(self, candidate: StreamCandidate) -> Self::Output;
}

/// A factory that can open multiple [`StreamCandidate`]s.
///
/// While you can use the `OverloadId` pattern to define your own factories regardless of whether or
/// not you own their type, the common use cases should be covered by its two main implementations:
/// - [`WriteOnly`] is the advised [`CandidateHandler`] when you don't care about received data
///   (which will be dropped immediately if any arrives), but want to use the [`Stream`] to send
///   data.
/// - Any function that returns a handler that implments [`IntoChannel<_, Payload>`] will see its
///   return value used to [`StreamCandidate::open`], yielding a [`Stream<_>`] that wraps the
///   [`IntoChannel::Receiver`].
///
/// These factories can be passed to [`ConnectionBuilder::on_receive_factory`] and
/// [`AcceptorBuilder::on_receive_factory`] to simplify the handling of the [`StreamCandidate`] step
/// of setting up a [`Stream`].
pub trait CandidateHandler<OverloadId>: SingleCandidateHandler<OverloadId> {
    /// Typically a call to [`StreamCandidate::open`] or [`StreamCandidate::open_write_only`].
    fn open(&self, candidate: StreamCandidate) -> Self::Output;
}

/// A factory that opens [`StreamCandidate`] as [write-only](StreamCandidate::open_write_only).
pub struct WriteOnly;

impl<OverloadId, Handler, F: FnOnce() -> Handler + Send + Sync + 'static>
    SingleCandidateHandler<OverloadId> for F
where
    Handler: IntoChannel<OverloadId, Inbound>,
    Handler::Sender: Channel<OverloadId, Inbound>,
{
    type Output = Stream<Handler::Receiver>;
    fn open_once(self, candidate: StreamCandidate) -> Self::Output {
        candidate.open(self())
    }
}
impl<OverloadId, Handler, F: Fn() -> Handler + Send + Sync + 'static> CandidateHandler<OverloadId>
    for F
where
    Handler: IntoChannel<OverloadId, Inbound>,
    Handler::Sender: Channel<OverloadId, Inbound>,
{
    fn open(&self, candidate: StreamCandidate) -> Self::Output {
        candidate.open(self())
    }
}

impl SingleCandidateHandler<()> for WriteOnly {
    type Output = Stream<()>;
    fn open_once(self, candidate: StreamCandidate) -> Self::Output {
        candidate.open_write_only()
    }
}
impl CandidateHandler<()> for WriteOnly {
    fn open(&self, candidate: StreamCandidate) -> Self::Output {
        candidate.open_write_only()
    }
}
impl SingleCandidateHandler<()> for () {
    type Output = StreamCandidate;
    fn open_once(self, candidate: StreamCandidate) -> Self::Output {
        candidate
    }
}
impl CandidateHandler<()> for () {
    fn open(&self, candidate: StreamCandidate) -> Self::Output {
        candidate
    }
}

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

    fn candidate_handlers() {
        fn assert_single_handler<H: SingleCandidateHandler<Oid>, Oid>(value: H) {}
        fn assert_handler<H: CandidateHandler<Oid>, Oid>(value: H) {
            assert_single_handler(value);
        }
        assert_handler(crate::experimental::bus::WriteOnly);
        assert_handler(());
        assert_handler(|| std::sync::mpsc::channel());
        assert_handler(|| tokio::sync::mpsc::unbounded_channel());
        assert_handler(|| |candidate: Inbound| ());
    }
}