cotis 0.1.0-alpha

Modular Rust UI framework core
Documentation
//! Conversion between layout output and renderer command streams.
//!
//! Every [`crate::cotis_app::CotisApp`] includes a pipe. When layout output already
//! matches what the renderer expects, pass [`()`] as the identity pipe (see
//! [`LayoutRenderPipe`](crate::pipes::LayoutRenderPipe) for [`()`]).

/// Transforms layout output items into renderer command items.
///
/// This is the boundary between the layout domain and render domain.
pub trait LayoutRenderPipe<ElementType, RenderCommandType> {
    /// Converts a stream of layout output items into renderer commands.
    fn transform(
        &mut self,
        render_commands: impl Iterator<Item = ElementType>,
    ) -> impl Iterator<Item = RenderCommandType>;
}

/// Identity [`LayoutRenderPipe`] used when layout output is already in renderer command form.
///
/// Pass [`()`] to [`CotisApp::new`](crate::cotis_app::CotisApp::new) when no conversion is needed.
impl<T> LayoutRenderPipe<T, T> for () {
    /// Returns incoming items unchanged.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use cotis::pipes::LayoutRenderPipe;
    ///
    /// let mut pipe = ();
    /// let output: Vec<_> = pipe.transform([1, 2, 3].into_iter()).collect();
    /// assert_eq!(output, vec![1, 2, 3]);
    /// ```
    fn transform(&mut self, render_commands: impl Iterator<Item = T>) -> impl Iterator<Item = T> {
        render_commands
    }
}

/// Closure-based pipe adapter.
///
/// Any closure with the expected signature can be used as a pipe implementation.
impl<E, R, IR: Iterator<Item = R>, F> LayoutRenderPipe<E, R> for F
where
    F: for<'a> FnMut(Box<dyn Iterator<Item = E> + 'a>) -> IR,
{
    /// Delegates transformation to the closure.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use cotis::pipes::LayoutRenderPipe;
    ///
    /// fn double_iter<'a>(iter: Box<dyn Iterator<Item = i32> + 'a>) -> std::vec::IntoIter<i32> {
    ///     iter.map(|v| v * 2).collect::<Vec<_>>().into_iter()
    /// }
    ///
    /// let mut pipe = double_iter;
    /// let output: Vec<_> = pipe.transform([1, 2, 3].into_iter()).collect();
    /// assert_eq!(output, vec![2, 4, 6]);
    /// ```
    fn transform(&mut self, render_commands: impl Iterator<Item = E>) -> impl Iterator<Item = R> {
        self(Box::new(render_commands))
    }
}