plotters_unsable/element/
composable.rs

1use super::*;
2use crate::drawing::backend::DrawingBackend;
3use std::borrow::Borrow;
4use std::iter::{once, Once};
5use std::marker::PhantomData;
6use std::ops::Add;
7
8/// An empty composibable element, which is the start point of an ad-hoc composible element
9pub struct EmptyElement<Coord, DB: DrawingBackend> {
10    coord: Coord,
11    phantom: PhantomData<DB>,
12}
13
14impl<Coord, DB: DrawingBackend> EmptyElement<Coord, DB> {
15    pub fn at(coord: Coord) -> Self {
16        Self {
17            coord,
18            phantom: PhantomData,
19        }
20    }
21}
22
23impl<Coord, Other, DB: DrawingBackend> Add<Other> for EmptyElement<Coord, DB>
24where
25    Other: Drawable<DB>,
26    for<'a> &'a Other: PointCollection<'a, BackendCoord>,
27{
28    type Output = BoxedElement<Coord, DB, Other>;
29    fn add(self, other: Other) -> Self::Output {
30        BoxedElement {
31            offset: self.coord,
32            inner: other,
33            phantom: PhantomData,
34        }
35    }
36}
37
38impl<'a, Coord, DB: DrawingBackend> PointCollection<'a, Coord> for &'a EmptyElement<Coord, DB> {
39    type Borrow = &'a Coord;
40    type IntoIter = Once<&'a Coord>;
41    fn point_iter(self) -> Self::IntoIter {
42        once(&self.coord)
43    }
44}
45
46impl<Coord, DB: DrawingBackend> Drawable<DB> for EmptyElement<Coord, DB> {
47    fn draw<I: Iterator<Item = BackendCoord>>(
48        &self,
49        _pos: I,
50        _backend: &mut DB,
51    ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
52        Ok(())
53    }
54}
55
56/// An composed element has only one component
57pub struct BoxedElement<Coord, DB: DrawingBackend, A: Drawable<DB>> {
58    inner: A,
59    offset: Coord,
60    phantom: PhantomData<DB>,
61}
62
63impl<'b, Coord, DB: DrawingBackend, A: Drawable<DB>> PointCollection<'b, Coord>
64    for &'b BoxedElement<Coord, DB, A>
65{
66    type Borrow = &'b Coord;
67    type IntoIter = Once<&'b Coord>;
68    fn point_iter(self) -> Self::IntoIter {
69        once(&self.offset)
70    }
71}
72
73impl<Coord, DB: DrawingBackend, A> Drawable<DB> for BoxedElement<Coord, DB, A>
74where
75    for<'a> &'a A: PointCollection<'a, BackendCoord>,
76    A: Drawable<DB>,
77{
78    fn draw<I: Iterator<Item = BackendCoord>>(
79        &self,
80        mut pos: I,
81        backend: &mut DB,
82    ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
83        if let Some((x0, y0)) = pos.next() {
84            self.inner.draw(
85                self.inner.point_iter().into_iter().map(|p| {
86                    let p = p.borrow();
87                    (p.0 + x0, p.1 + y0)
88                }),
89                backend,
90            )?;
91        }
92        Ok(())
93    }
94}
95
96impl<Coord, DB: DrawingBackend, My, Yours> Add<Yours> for BoxedElement<Coord, DB, My>
97where
98    My: Drawable<DB>,
99    for<'a> &'a My: PointCollection<'a, BackendCoord>,
100    Yours: Drawable<DB>,
101    for<'a> &'a Yours: PointCollection<'a, BackendCoord>,
102{
103    type Output = ComposedElement<Coord, DB, My, Yours>;
104    fn add(self, yours: Yours) -> Self::Output {
105        ComposedElement {
106            offset: self.offset,
107            first: self.inner,
108            second: yours,
109            phantom: PhantomData,
110        }
111    }
112}
113
114/// The composed element which has at least two components
115pub struct ComposedElement<Coord, DB: DrawingBackend, A, B>
116where
117    A: Drawable<DB>,
118    B: Drawable<DB>,
119{
120    first: A,
121    second: B,
122    offset: Coord,
123    phantom: PhantomData<DB>,
124}
125
126impl<'b, Coord, DB: DrawingBackend, A, B> PointCollection<'b, Coord>
127    for &'b ComposedElement<Coord, DB, A, B>
128where
129    A: Drawable<DB>,
130    B: Drawable<DB>,
131{
132    type Borrow = &'b Coord;
133    type IntoIter = Once<&'b Coord>;
134    fn point_iter(self) -> Self::IntoIter {
135        once(&self.offset)
136    }
137}
138
139impl<Coord, DB: DrawingBackend, A, B> Drawable<DB> for ComposedElement<Coord, DB, A, B>
140where
141    for<'a> &'a A: PointCollection<'a, BackendCoord>,
142    for<'b> &'b B: PointCollection<'b, BackendCoord>,
143    A: Drawable<DB>,
144    B: Drawable<DB>,
145{
146    fn draw<I: Iterator<Item = BackendCoord>>(
147        &self,
148        mut pos: I,
149        backend: &mut DB,
150    ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
151        if let Some((x0, y0)) = pos.next() {
152            self.first.draw(
153                self.first.point_iter().into_iter().map(|p| {
154                    let p = p.borrow();
155                    (p.0 + x0, p.1 + y0)
156                }),
157                backend,
158            )?;
159            self.second.draw(
160                self.second.point_iter().into_iter().map(|p| {
161                    let p = p.borrow();
162                    (p.0 + x0, p.1 + y0)
163                }),
164                backend,
165            )?;
166        }
167        Ok(())
168    }
169}
170
171impl<Coord, DB: DrawingBackend, A, B, C> Add<C> for ComposedElement<Coord, DB, A, B>
172where
173    A: Drawable<DB>,
174    for<'a> &'a A: PointCollection<'a, BackendCoord>,
175    B: Drawable<DB>,
176    for<'a> &'a B: PointCollection<'a, BackendCoord>,
177    C: Drawable<DB>,
178    for<'a> &'a C: PointCollection<'a, BackendCoord>,
179{
180    type Output = ComposedElement<Coord, DB, A, ComposedElement<BackendCoord, DB, B, C>>;
181    fn add(self, rhs: C) -> Self::Output {
182        ComposedElement {
183            offset: self.offset,
184            first: self.first,
185            second: ComposedElement {
186                offset: (0, 0),
187                first: self.second,
188                second: rhs,
189                phantom: PhantomData,
190            },
191            phantom: PhantomData,
192        }
193    }
194}