sketchbook 0.0.2

Interactive visual applications in Rust
Documentation
use super::Ream;
use crate::env::*;
use crate::{Setup, Sketch};

/// Single sketch ream.
///
/// Only one sketch can be run using this ream, but it is fully usable in a `no_std` environment.
///
/// ```
/// use sketchbook::*;
/// use sketchbook::ream::*;
///
/// #[apply(derive_sketch)]
/// #[sketch(env=minimal)]
/// struct App {
///     #[page]
///     page: minimal::Page,
/// }
///
/// impl Setup for App {
///     fn setup(page: minimal::Page, _: ()) -> Self {
///         Self { page }
///     }
/// }
///
/// // create book and bind it
/// Book::<Single<App>>::bind();
/// ```
#[cfg_attr(docsrs, doc(cfg(feature = "ream-single")))]
pub struct Single<S, I = ()> {
    inner: SingleInner<S, I>,
}

impl<E> core::fmt::Debug for Single<E> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        f.debug_struct("Single").finish()
    }
}

enum SingleInner<S, I> {
    Sketch(S),
    Input(I),
    Temp,
}

impl<S, I> SingleInner<S, I> {
    fn take_input(&mut self) -> I {
        use SingleInner::*;
        match core::mem::replace(self, Temp) {
            Input(input) => input,
            _ => panic!("Attempted to take input from non-input variant."),
        }
    }
}

impl<S, I> Single<S, I> {
    /// Create new ream that will pass the default value for the input type.
    pub fn new() -> Self
    where
        I: Default,
    {
        Self {
            inner: SingleInner::Input(I::default()),
        }
    }

    /// Create new ream that will pass an input to the sketch.
    pub fn with_input(input: I) -> Self {
        Self {
            inner: SingleInner::Input(input),
        }
    }
}

impl<S, I> Default for Single<S, I>
where
    I: Default,
{
    fn default() -> Self {
        Self::new()
    }
}

impl<S, I> From<I> for Single<S, I> {
    fn from(input: I) -> Self {
        Self::with_input(input)
    }
}

impl<S, I> Ream for Single<S, I>
where
    S: Sketch + Setup<I>,
{
    type Env = S::Env;

    type Error = core::convert::Infallible;

    fn update(&mut self, mill: &mut MillOf<Self::Env>) -> Result<Status, Self::Error> {
        use SingleInner::*;
        match &mut self.inner {
            inner @ Input(_) => {
                // create sketch
                let page = mill.new_page();
                self.inner = Sketch(S::setup(page, inner.take_input()));
                Ok(Status::Continue)
            }
            Sketch(sketch) => {
                // process group of events
                sketch.get_page_mut().start_group();
                while let Some(event) = sketch.get_page_mut().next_event_in_group() {
                    sketch.get_page_mut().before_event(&event);
                    sketch.handle_environment_event(&event);
                    sketch.get_page_mut().finish_event(event);
                }
                sketch.get_page_mut().end_group();

                Ok(sketch.get_page_mut().status())
            }
            Temp => unreachable!(),
        }
    }
}