plotters-unsable 0.1.13-5c709bb

Plot Drawing Library in Pure Rust for both native and WASM applications
Documentation
use crate::coord::Shift;
use crate::drawing::area::IntoDrawingArea;
use crate::drawing::backend::{BackendCoord, BackendStyle, DrawingBackend, DrawingErrorKind};
use crate::drawing::DrawingArea;
use crate::style::{Color, FontDesc};

pub struct RGBA(pub u8, pub u8, pub u8, pub f64);

pub struct MockedBackend {
    height: u32,
    width: u32,
    init_count: u32,
    pub draw_count: u32,
    pub num_draw_pixel_call: u32,
    pub num_draw_line_call: u32,
    pub num_draw_rect_call: u32,
    pub num_draw_circle_call: u32,
    pub num_draw_text_call: u32,
    pub num_draw_path_call: u32,
    check_draw_pixel: Option<Box<dyn FnMut(RGBA, BackendCoord)>>,
    check_draw_line: Option<Box<dyn FnMut(RGBA, BackendCoord, BackendCoord)>>,
    check_draw_rect: Option<Box<dyn FnMut(RGBA, bool, BackendCoord, BackendCoord)>>,
    check_draw_path: Option<Box<dyn FnMut(RGBA, Vec<BackendCoord>)>>,
    check_draw_circle: Option<Box<dyn FnMut(RGBA, bool, BackendCoord, u32)>>,
    check_draw_text: Option<Box<dyn FnMut(RGBA, &str, f64, BackendCoord, &str)>>,
    drop_check: Option<Box<dyn FnMut(&Self)>>,
}

macro_rules! def_set_checker_func {
    ($name:ident, $($param:ty),*) => {
        pub fn $name<T: FnMut($($param,)*) + 'static>(&mut self, check:T) -> &mut Self {
            self.$name = Some(Box::new(check));
            self
        }
    }
}

impl MockedBackend {
    pub fn new(width: u32, height: u32) -> Self {
        MockedBackend {
            height,
            width,
            init_count: 0,
            draw_count: 0,
            num_draw_pixel_call: 0,
            num_draw_line_call: 0,
            num_draw_rect_call: 0,
            num_draw_circle_call: 0,
            num_draw_text_call: 0,
            num_draw_path_call: 0,
            check_draw_pixel: None,
            check_draw_line: None,
            check_draw_rect: None,
            check_draw_path: None,
            check_draw_circle: None,
            check_draw_text: None,
            drop_check: None,
        }
    }

    def_set_checker_func!(check_draw_pixel, RGBA, BackendCoord);
    def_set_checker_func!(check_draw_line, RGBA, BackendCoord, BackendCoord);
    def_set_checker_func!(check_draw_rect, RGBA, bool, BackendCoord, BackendCoord);
    def_set_checker_func!(check_draw_path, RGBA, Vec<BackendCoord>);
    def_set_checker_func!(check_draw_circle, RGBA, bool, BackendCoord, u32);
    def_set_checker_func!(check_draw_text, RGBA, &str, f64, BackendCoord, &str);
    def_set_checker_func!(drop_check, &Self);

    fn check_before_draw(&mut self) {
        self.draw_count += 1;
        assert_eq!(self.init_count, self.draw_count);
    }
}

#[derive(Debug)]
pub struct MockedError;

impl std::fmt::Display for MockedError {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(fmt, "MockedError")
    }
}

impl std::error::Error for MockedError {}

fn to_rgba<T: Color>(color: &T) -> RGBA {
    let (r, g, b) = color.rgb();
    let a = color.alpha();
    RGBA(r, g, b, a)
}

impl DrawingBackend for MockedBackend {
    type ErrorType = MockedError;

    fn get_size(&self) -> (u32, u32) {
        (self.width, self.height)
    }

    fn ensure_prepared(&mut self) -> Result<(), DrawingErrorKind<MockedError>> {
        self.init_count += 1;
        Ok(())
    }

    fn present(&mut self) -> Result<(), DrawingErrorKind<MockedError>> {
        self.init_count = 0;
        self.draw_count = 0;
        Ok(())
    }

    fn draw_pixel<S: Color>(
        &mut self,
        point: BackendCoord,
        color: &S,
    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
        self.check_before_draw();
        self.num_draw_pixel_call += 1;
        let color = to_rgba(color);
        if let Some(ref mut checker) = self.check_draw_pixel {
            checker(color, point);
        }
        Ok(())
    }

    fn draw_line<S: BackendStyle>(
        &mut self,
        from: BackendCoord,
        to: BackendCoord,
        style: &S,
    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
        self.check_before_draw();
        self.num_draw_line_call += 1;
        let color = to_rgba(style.as_color());
        if let Some(ref mut checker) = self.check_draw_line {
            checker(color, from, to);
        }
        Ok(())
    }

    fn draw_rect<S: BackendStyle>(
        &mut self,
        upper_left: BackendCoord,
        bottom_right: BackendCoord,
        style: &S,
        fill: bool,
    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
        self.check_before_draw();
        self.num_draw_rect_call += 1;
        let color = to_rgba(style.as_color());
        if let Some(ref mut checker) = self.check_draw_rect {
            checker(color, fill, upper_left, bottom_right);
        }
        Ok(())
    }

    fn draw_path<S: BackendStyle, I: IntoIterator<Item = BackendCoord>>(
        &mut self,
        path: I,
        style: &S,
    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
        self.check_before_draw();
        self.num_draw_path_call += 1;
        let color = to_rgba(style.as_color());
        if let Some(ref mut checker) = self.check_draw_path {
            checker(color, path.into_iter().collect());
        }
        Ok(())
    }

    fn draw_circle<S: BackendStyle>(
        &mut self,
        center: BackendCoord,
        radius: u32,
        style: &S,
        fill: bool,
    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
        self.check_before_draw();
        self.num_draw_circle_call += 1;
        let color = to_rgba(style.as_color());
        if let Some(ref mut checker) = self.check_draw_circle {
            checker(color, fill, center, radius);
        }
        Ok(())
    }

    fn draw_text<'a, C: Color>(
        &mut self,
        text: &str,
        font: &FontDesc<'a>,
        pos: BackendCoord,
        color: &C,
    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
        self.check_before_draw();
        self.num_draw_text_call += 1;
        let color = to_rgba(color);
        if let Some(ref mut checker) = self.check_draw_text {
            checker(color, font.get_name(), font.get_size(), pos, text);
        }
        Ok(())
    }
}

impl Drop for MockedBackend {
    fn drop(&mut self) {
        let mut temp = None;
        std::mem::swap(&mut temp, &mut self.drop_check);

        if let Some(mut checker) = temp {
            checker(self);
        }
    }
}

pub fn create_mocked_drawing_area<F: FnOnce(&mut MockedBackend)>(
    width: u32,
    height: u32,
    setup: F,
) -> DrawingArea<MockedBackend, Shift> {
    let mut backend = MockedBackend::new(width, height);
    setup(&mut backend);
    backend.into_drawing_area()
}