pubnub-core 0.1.0

PubNub core crate, modular and composable
Documentation
use crate::pubnub::PubNub;
use crate::runtime::Runtime;
use crate::subscription::subscribe_loop::ExitTx as SubscribeLoopExitTx;
use crate::subscription::subscribe_loop_supervisor::{
    SubscribeLoopSupervisor, SubscribeLoopSupervisorParams,
};
use crate::transport::Transport;
use futures_util::lock::Mutex;
use std::sync::Arc;

/// # PubNub Client Builder
///
/// Create a [`crate::PubNub`] client using the builder pattern.
/// Optional items can be overridden using this.
#[derive(Clone, Debug)]
pub struct Builder<TTransport = (), TRuntime = ()> {
    /// Transport to use for communication.
    transport: TTransport,
    /// Runtime to use for managing resources.
    runtime: TRuntime,

    /// Subscription related configuration params.
    /// If set, gets a signal when subscribe loop exits.
    subscribe_loop_exit_tx: Option<SubscribeLoopExitTx>,
}

impl<TTransport, TRuntime> Builder<TTransport, TRuntime>
where
    TTransport: Transport,
    TRuntime: Runtime,
{
    /// Build the [`PubNub`] client to begin streaming messages.
    ///
    /// # Example
    ///
    /// ```
    /// use pubnub_core::mock::{runtime::MockRuntime, transport::MockTransport};
    /// use pubnub_core::Builder;
    ///
    /// let transport = MockTransport::new();
    /// let runtime = MockRuntime::new();
    ///
    /// let pubnub = Builder::with_components(transport, runtime).build();
    /// ```
    #[must_use]
    pub fn build(self) -> PubNub<TTransport, TRuntime> {
        let Self {
            transport,
            runtime,
            subscribe_loop_exit_tx,
        } = self;

        let subscribe_loop_supervisor_params = SubscribeLoopSupervisorParams {
            exit_tx: subscribe_loop_exit_tx,
        };

        PubNub {
            transport,
            runtime,

            subscribe_loop_supervisor: Arc::new(Mutex::new(SubscribeLoopSupervisor::new(
                subscribe_loop_supervisor_params,
            ))),
        }
    }
}

impl<TTransport, TRuntime> Builder<TTransport, TRuntime> {
    /// Create a new [`Builder`] that can configure a [`PubNub`] client
    /// with custom component implementations.
    ///
    /// # Example
    ///
    /// ```
    /// use pubnub_core::mock::{runtime::MockRuntime, transport::MockTransport};
    /// use pubnub_core::Builder;
    ///
    /// let transport = MockTransport::new();
    /// let runtime = MockRuntime::new();
    ///
    /// let pubnub = Builder::with_components(transport, runtime).build();
    /// ```
    #[must_use]
    pub fn with_components(transport: TTransport, runtime: TRuntime) -> Self {
        Self {
            subscribe_loop_exit_tx: None,

            transport,
            runtime,
        }
    }

    /// Set the subscribe loop exit tx.
    ///
    /// If set, subscribe loop sends a message to it when it exits.
    ///
    /// # Example
    ///
    /// ```
    /// # use pubnub_core::mock::{transport::MockTransport, runtime::MockRuntime};
    /// # let transport = MockTransport::new();
    /// # let runtime = MockRuntime::new();
    /// use pubnub_core::Builder;
    ///
    /// let (tx, _rx) = futures_channel::mpsc::channel(1);
    ///
    /// let pubnub = Builder::with_components(transport, runtime)
    ///     .subscribe_loop_exit_tx(tx)
    ///     .build();
    /// ```
    #[must_use]
    pub fn subscribe_loop_exit_tx(mut self, tx: SubscribeLoopExitTx) -> Self {
        self.subscribe_loop_exit_tx = Some(tx);
        self
    }

    /// Set the transport to use.
    ///
    /// This allows changing the [`Transport`] type on the builder and,
    /// therefore, on the resulting [`PubNub`] client.
    #[must_use]
    pub fn transport<U: Transport>(self, transport: U) -> Builder<U, TRuntime> {
        Builder {
            transport,

            // Copy the rest of the fields.
            runtime: self.runtime,
            subscribe_loop_exit_tx: self.subscribe_loop_exit_tx,
        }
    }

    /// Set the runtime to use.
    ///
    /// This allows changing the [`Runtime`] type on the builder and,
    /// therefore, on the resulting [`PubNub`] client.
    #[must_use]
    pub fn runtime<U: Runtime>(self, runtime: U) -> Builder<TTransport, U> {
        Builder {
            runtime,

            // Copy the rest of the fields.
            transport: self.transport,
            subscribe_loop_exit_tx: self.subscribe_loop_exit_tx,
        }
    }
}

impl Builder<(), ()> {
    /// Create a new [`Builder`] that can configure a [`PubNub`] client.
    ///
    /// # Example
    ///
    /// ```
    /// use pubnub_core::mock::{runtime::MockRuntime, transport::MockTransport};
    /// use pubnub_core::Builder;
    ///
    /// let transport = MockTransport::new();
    /// let runtime = MockRuntime::new();
    ///
    /// let pubnub = Builder::new().transport(transport).runtime(runtime).build();
    /// ```
    #[must_use]
    pub fn new() -> Self {
        Self::with_components((), ())
    }
}

impl<TTransport, TRuntime> Default for Builder<TTransport, TRuntime>
where
    TTransport: Default,
    TRuntime: Default,
{
    /// Create a new [`Builder`] that can configure a [`PubNub`] client
    /// with default components.
    #[must_use]
    fn default() -> Self {
        Self::with_components(TTransport::default(), TRuntime::default())
    }
}