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