buoyant 0.7.0-alpha.1

SwiftUI-like UIs in Rust for embedded devices
Documentation
//! This module implements a non-transitioning Option<T>
//! For a transition-capable version, use [`crate::render::TransitionOption`].

use crate::{
    render::{AnimatedJoin, AnimationDomain, Render},
    render_target::RenderTarget,
};

impl<T: AnimatedJoin> AnimatedJoin for Option<T> {
    fn join_from(&mut self, source: &Self, domain: &AnimationDomain) {
        if let (Some(source), Some(target)) = (source, self) {
            target.join_from(source, domain);
        }
    }
}

impl<T: Render<Color>, Color: Copy> Render<Color> for Option<T> {
    fn render(&self, render_target: &mut impl RenderTarget<ColorFormat = Color>, style: &Color) {
        if let Some(view) = self {
            view.render(render_target, style);
        }
    }

    fn render_animated(
        render_target: &mut impl RenderTarget<ColorFormat = Color>,
        source: &Self,
        target: &Self,
        style: &Color,
        domain: &AnimationDomain,
    ) {
        match (source, target) {
            (Some(source), Some(target)) => {
                T::render_animated(render_target, source, target, style, domain);
            }
            (_, None) => {}
            (None, Some(target)) => {
                target.render(render_target, style);
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{
        primitives::{Point, Size},
        render::shape::Rect,
        render_target::FixedTextBuffer,
    };
    use std::{string::String, string::ToString, time::Duration};

    #[test]
    fn some_option_renders() {
        let mut buffer = FixedTextBuffer::<1, 1>::default();
        Some(Rect::new(Point::zero(), Size::new(1, 1))).render(&mut buffer, &'X');
        assert_eq!(buffer.text[0][0], 'X');
    }

    #[test]
    fn none_option_does_not_render() {
        let mut buffer = FixedTextBuffer::<1, 1>::default();
        Option::<Rect>::None.render(&mut buffer, &'X');
        assert_eq!(buffer.text[0][0], ' ');
    }

    #[test]
    fn animated_render_some_to_some() {
        let mut buffer = FixedTextBuffer::<3, 1>::default();
        let source = Some(Rect::new(Point::zero(), Size::new(1, 1)));
        let target = Some(Rect::new(Point::new(2, 0), Size::new(1, 1)));
        let domain = AnimationDomain::new(128, Duration::from_millis(100));
        Option::render_animated(&mut buffer, &source, &target, &'O', &domain);
        assert_eq!(buffer.text[0].iter().collect::<String>(), " O ".to_string());
    }

    #[test]
    fn animated_render_some_to_none() {
        let mut buffer = FixedTextBuffer::<1, 1>::default();
        let source = Some(Rect::new(Point::zero(), Size::new(1, 1)));
        let domain = AnimationDomain::new(128, Duration::from_millis(100));
        Option::render_animated(&mut buffer, &source, &None, &'X', &domain);
        assert_eq!(buffer.text[0][0], ' ');
    }

    #[test]
    fn animated_render_none_to_some() {
        let mut buffer = FixedTextBuffer::<1, 1>::default();
        let target = Some(Rect::new(Point::zero(), Size::new(1, 1)));
        let domain = AnimationDomain::new(128, Duration::from_millis(100));
        Option::render_animated(&mut buffer, &None, &target, &'Y', &domain);
        assert_eq!(buffer.text[0][0], 'Y');
    }

    #[test]
    fn animated_render_none_to_none() {
        let mut buffer = FixedTextBuffer::<1, 1>::default();
        let domain = AnimationDomain::new(128, Duration::from_millis(100));
        Option::<Rect>::render_animated(&mut buffer, &None, &None, &'Z', &domain);
        assert_eq!(buffer.text[0][0], ' ');
    }

    #[test]
    fn animated_join_some_to_some() {
        let source = Some(Rect::new(Point::zero(), Size::new(10, 10)));
        let mut target = Some(Rect::new(Point::new(20, 20), Size::new(30, 30)));
        let domain = AnimationDomain::new(128, Duration::from_millis(100));
        target.join_from(&source, &domain);
        assert_eq!(
            target,
            Some(Rect::new(Point::new(10, 10), Size::new(20, 20)))
        );
    }

    #[test]
    fn animated_join_some_to_none() {
        let source = Some(Rect::new(Point::zero(), Size::new(1, 1)));
        let mut target = None;
        let domain = AnimationDomain::new(128, Duration::from_millis(100));
        target.join_from(&source, &domain);
        assert_eq!(target, None);
    }

    #[test]
    fn animated_join_none_to_some() {
        let source = None;
        let mut target = Some(Rect::new(Point::zero(), Size::new(1, 1)));
        let domain = AnimationDomain::new(128, Duration::from_millis(100));
        target.join_from(&source, &domain);
        assert_eq!(target, Some(Rect::new(Point::zero(), Size::new(1, 1))));
    }

    #[test]
    fn animated_join_none_to_none() {
        let source = None;
        let mut target = None;
        let domain = AnimationDomain::new(128, Duration::from_millis(100));
        Option::<Rect>::join_from(&mut target, &source, &domain);
        assert_eq!(target, None);
    }
}