From 592cc685067c36cbba87e4db14f4ebc71d65b951 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Sun, 19 Apr 2020 21:55:23 +0200
Subject: Remove `Layer` trait and simplify `Canvas`

---
 wgpu/src/widget/canvas.rs             |  46 ++++++-------
 wgpu/src/widget/canvas/cache.rs       | 110 +++++++++++++++++++++++++++++++
 wgpu/src/widget/canvas/drawable.rs    |   9 +++
 wgpu/src/widget/canvas/geometry.rs    |  15 +++++
 wgpu/src/widget/canvas/layer.rs       |  25 -------
 wgpu/src/widget/canvas/layer/cache.rs | 120 ----------------------------------
 wgpu/src/widget/canvas/program.rs     |  16 -----
 wgpu/src/widget/canvas/state.rs       |  20 ++++++
 8 files changed, 177 insertions(+), 184 deletions(-)
 create mode 100644 wgpu/src/widget/canvas/cache.rs
 create mode 100644 wgpu/src/widget/canvas/geometry.rs
 delete mode 100644 wgpu/src/widget/canvas/layer.rs
 delete mode 100644 wgpu/src/widget/canvas/layer/cache.rs
 delete mode 100644 wgpu/src/widget/canvas/program.rs
 create mode 100644 wgpu/src/widget/canvas/state.rs

(limited to 'wgpu/src')

diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs
index 326bc7d5..2b485e18 100644
--- a/wgpu/src/widget/canvas.rs
+++ b/wgpu/src/widget/canvas.rs
@@ -14,24 +14,26 @@ use iced_native::{
 };
 use std::hash::Hash;
 
-pub mod layer;
 pub mod path;
 
+mod cache;
 mod drawable;
 mod event;
 mod fill;
 mod frame;
-mod program;
+mod geometry;
+mod state;
 mod stroke;
 mod text;
 
+pub use cache::Cache;
 pub use drawable::Drawable;
 pub use event::Event;
 pub use fill::Fill;
 pub use frame::Frame;
-pub use layer::Layer;
+pub use geometry::Geometry;
 pub use path::Path;
-pub use program::Program;
+pub use state::State;
 pub use stroke::{LineCap, LineJoin, Stroke};
 pub use text::Text;
 
@@ -65,7 +67,7 @@ pub use text::Text;
 /// #     pub use iced_wgpu::canvas;
 /// #     pub use iced_native::Color;
 /// # }
-/// use iced::canvas::{self, layer, Canvas, Drawable, Fill, Frame, Path};
+/// use iced::canvas::{self, Cache, Canvas, Drawable, Fill, Frame, Path};
 /// use iced::Color;
 ///
 /// // First, we define the data we need for drawing
@@ -86,31 +88,29 @@ pub use text::Text;
 /// }
 ///
 /// // We can use a `Cache` to avoid unnecessary re-tessellation
-/// let mut cache: layer::Cache<Circle> = layer::Cache::new();
+/// let cache = Cache::new();
 ///
 /// // Finally, we simply use our `Cache` to create the `Canvas`!
-/// let canvas = Canvas::new(&mut cache, &Circle { radius: 50.0 });
+/// let canvas = Canvas::new(cache.with(Circle { radius: 50.0 }));
 /// ```
 #[derive(Debug)]
-pub struct Canvas<'a, P: Program> {
+pub struct Canvas<S: State> {
     width: Length,
     height: Length,
-    program: &'a mut P,
-    input: &'a P::Input,
+    state: S,
 }
 
-impl<'a, P: Program> Canvas<'a, P> {
+impl<S: State> Canvas<S> {
     const DEFAULT_SIZE: u16 = 100;
 
     /// Creates a new [`Canvas`] with no layers.
     ///
     /// [`Canvas`]: struct.Canvas.html
-    pub fn new(program: &'a mut P, input: &'a P::Input) -> Self {
+    pub fn new(state: S) -> Self {
         Canvas {
             width: Length::Units(Self::DEFAULT_SIZE),
             height: Length::Units(Self::DEFAULT_SIZE),
-            program,
-            input,
+            state,
         }
     }
 
@@ -131,7 +131,7 @@ impl<'a, P: Program> Canvas<'a, P> {
     }
 }
 
-impl<'a, Message, P: Program> Widget<Message, Renderer> for Canvas<'a, P> {
+impl<Message, S: State> Widget<Message, Renderer> for Canvas<S> {
     fn width(&self) -> Length {
         self.width
     }
@@ -178,7 +178,7 @@ impl<'a, Message, P: Program> Widget<Message, Renderer> for Canvas<'a, P> {
         };
 
         if let Some(canvas_event) = canvas_event {
-            self.program.update(canvas_event, bounds.size(), self.input)
+            self.state.update(canvas_event, bounds.size())
         }
     }
 
@@ -196,12 +196,12 @@ impl<'a, Message, P: Program> Widget<Message, Renderer> for Canvas<'a, P> {
         (
             Primitive::Group {
                 primitives: self
-                    .program
-                    .layers(self.input)
-                    .iter()
-                    .map(|layer| Primitive::Cached {
+                    .state
+                    .draw(size)
+                    .into_iter()
+                    .map(|geometry| Primitive::Cached {
                         origin,
-                        cache: layer.draw(size),
+                        cache: geometry.into_primitive(),
                     })
                     .collect(),
             },
@@ -218,12 +218,12 @@ impl<'a, Message, P: Program> Widget<Message, Renderer> for Canvas<'a, P> {
     }
 }
 
-impl<'a, Message, P: Program> From<Canvas<'a, P>>
+impl<'a, Message, S: State + 'a> From<Canvas<S>>
     for Element<'a, Message, Renderer>
 where
     Message: 'static,
 {
-    fn from(canvas: Canvas<'a, P>) -> Element<'a, Message, Renderer> {
+    fn from(canvas: Canvas<S>) -> Element<'a, Message, Renderer> {
         Element::new(canvas)
     }
 }
diff --git a/wgpu/src/widget/canvas/cache.rs b/wgpu/src/widget/canvas/cache.rs
new file mode 100644
index 00000000..c88239af
--- /dev/null
+++ b/wgpu/src/widget/canvas/cache.rs
@@ -0,0 +1,110 @@
+use crate::{
+    canvas::{Drawable, Frame, Geometry},
+    Primitive,
+};
+
+use iced_native::Size;
+use std::{cell::RefCell, sync::Arc};
+
+enum State {
+    Empty,
+    Filled {
+        bounds: Size,
+        primitive: Arc<Primitive>,
+    },
+}
+
+impl Default for State {
+    fn default() -> Self {
+        State::Empty
+    }
+}
+/// A simple cache that stores generated geometry to avoid recomputation.
+///
+/// A [`Cache`] will not redraw its geometry unless the dimensions of its layer
+/// change or it is explicitly cleared.
+///
+/// [`Layer`]: ../trait.Layer.html
+/// [`Cache`]: struct.Cache.html
+#[derive(Debug, Default)]
+pub struct Cache {
+    state: RefCell<State>,
+}
+
+impl Cache {
+    /// Creates a new empty [`Cache`].
+    ///
+    /// [`Cache`]: struct.Cache.html
+    pub fn new() -> Self {
+        Cache {
+            state: Default::default(),
+        }
+    }
+
+    /// Clears the cache, forcing a redraw the next time it is used.
+    ///
+    /// [`Cached`]: struct.Cached.html
+    pub fn clear(&mut self) {
+        *self.state.borrow_mut() = State::Empty;
+    }
+
+    pub fn draw<T>(&self, new_bounds: Size, input: T) -> Geometry
+    where
+        T: Drawable + std::fmt::Debug,
+    {
+        use std::ops::Deref;
+
+        if let State::Filled { bounds, primitive } = self.state.borrow().deref()
+        {
+            if *bounds == new_bounds {
+                return Geometry::from_primitive(primitive.clone());
+            }
+        }
+
+        let mut frame = Frame::new(new_bounds.width, new_bounds.height);
+        input.draw(&mut frame);
+
+        let primitive = Arc::new(frame.into_primitive());
+
+        *self.state.borrow_mut() = State::Filled {
+            bounds: new_bounds,
+            primitive: primitive.clone(),
+        };
+
+        Geometry::from_primitive(primitive)
+    }
+
+    pub fn with<'a, T>(&'a self, input: T) -> impl crate::canvas::State + 'a
+    where
+        T: Drawable + std::fmt::Debug + 'a,
+    {
+        Bind { cache: self, input }
+    }
+}
+
+struct Bind<'a, T> {
+    cache: &'a Cache,
+    input: T,
+}
+
+impl<'a, T> crate::canvas::State for Bind<'a, T>
+where
+    T: Drawable + std::fmt::Debug + 'a,
+{
+    fn draw(&self, bounds: Size) -> Vec<Geometry> {
+        vec![self.cache.draw(bounds, &self.input)]
+    }
+}
+
+impl std::fmt::Debug for State {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            State::Empty => write!(f, "Empty"),
+            State::Filled { primitive, bounds } => f
+                .debug_struct("Filled")
+                .field("primitive", primitive)
+                .field("bounds", bounds)
+                .finish(),
+        }
+    }
+}
diff --git a/wgpu/src/widget/canvas/drawable.rs b/wgpu/src/widget/canvas/drawable.rs
index 48ba6b4c..32258b71 100644
--- a/wgpu/src/widget/canvas/drawable.rs
+++ b/wgpu/src/widget/canvas/drawable.rs
@@ -16,3 +16,12 @@ impl<'a> Drawable for dyn Fn(&mut Frame) + 'a {
         self(frame)
     }
 }
+
+impl<T> Drawable for &T
+where
+    T: Drawable,
+{
+    fn draw(&self, frame: &mut Frame) {
+        T::draw(self, frame)
+    }
+}
diff --git a/wgpu/src/widget/canvas/geometry.rs b/wgpu/src/widget/canvas/geometry.rs
new file mode 100644
index 00000000..db7b4054
--- /dev/null
+++ b/wgpu/src/widget/canvas/geometry.rs
@@ -0,0 +1,15 @@
+use crate::Primitive;
+use std::sync::Arc;
+
+#[derive(Debug)]
+pub struct Geometry(Arc<Primitive>);
+
+impl Geometry {
+    pub(crate) fn from_primitive(primitive: Arc<Primitive>) -> Self {
+        Self(primitive)
+    }
+
+    pub(crate) fn into_primitive(self) -> Arc<Primitive> {
+        self.0
+    }
+}
diff --git a/wgpu/src/widget/canvas/layer.rs b/wgpu/src/widget/canvas/layer.rs
deleted file mode 100644
index a46b7fb1..00000000
--- a/wgpu/src/widget/canvas/layer.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-//! Produce, store, and reuse geometry.
-mod cache;
-
-pub use cache::Cache;
-
-use crate::Primitive;
-use iced_native::Size;
-
-use std::sync::Arc;
-
-/// A layer that can be presented at a [`Canvas`].
-///
-/// [`Canvas`]: ../struct.Canvas.html
-pub trait Layer: std::fmt::Debug {
-    /// Draws the [`Layer`] in the given bounds and produces a [`Primitive`] as
-    /// a result.
-    ///
-    /// The [`Layer`] may choose to store the produced [`Primitive`] locally and
-    /// only recompute it when the bounds change, its contents change, or is
-    /// otherwise explicitly cleared by other means.
-    ///
-    /// [`Layer`]: trait.Layer.html
-    /// [`Primitive`]: ../../../enum.Primitive.html
-    fn draw(&self, bounds: Size) -> Arc<Primitive>;
-}
diff --git a/wgpu/src/widget/canvas/layer/cache.rs b/wgpu/src/widget/canvas/layer/cache.rs
deleted file mode 100644
index 4ecebb48..00000000
--- a/wgpu/src/widget/canvas/layer/cache.rs
+++ /dev/null
@@ -1,120 +0,0 @@
-use crate::{
-    canvas::{Drawable, Frame, Layer},
-    Primitive,
-};
-
-use iced_native::Size;
-use std::{borrow::Borrow, cell::RefCell, marker::PhantomData, sync::Arc};
-
-enum State {
-    Empty,
-    Filled {
-        bounds: Size,
-        primitive: Arc<Primitive>,
-    },
-}
-
-impl Default for State {
-    fn default() -> Self {
-        State::Empty
-    }
-}
-/// A simple cache that stores generated geometry to avoid recomputation.
-///
-/// A [`Cache`] will not redraw its geometry unless the dimensions of its layer
-/// change or it is explicitly cleared.
-///
-/// [`Layer`]: ../trait.Layer.html
-/// [`Cache`]: struct.Cache.html
-#[derive(Debug, Default)]
-pub struct Cache {
-    state: RefCell<State>,
-}
-
-impl Cache {
-    /// Creates a new empty [`Cache`].
-    ///
-    /// [`Cache`]: struct.Cache.html
-    pub fn new() -> Self {
-        Cache {
-            state: Default::default(),
-        }
-    }
-
-    /// Clears the cache, forcing a redraw the next time it is used.
-    ///
-    /// [`Cached`]: struct.Cached.html
-    pub fn clear(&mut self) {
-        *self.state.borrow_mut() = State::Empty;
-    }
-
-    /// Binds the [`Cache`] with some data, producing a [`Layer`] that can be
-    /// added to a [`Canvas`].
-    ///
-    /// [`Cache`]: struct.Cache.html
-    /// [`Layer`]: ../trait.Layer.html
-    /// [`Canvas`]: ../../struct.Canvas.html
-    pub fn with<'a, T>(
-        &'a self,
-        input: impl Borrow<T> + std::fmt::Debug + 'a,
-    ) -> impl Layer + 'a
-    where
-        T: Drawable + std::fmt::Debug + 'a,
-    {
-        Bind {
-            cache: self,
-            input: input,
-            drawable: PhantomData,
-        }
-    }
-}
-
-#[derive(Debug)]
-struct Bind<'a, T: Drawable, I: Borrow<T> + 'a> {
-    cache: &'a Cache,
-    input: I,
-    drawable: PhantomData<T>,
-}
-
-impl<'a, T, I> Layer for Bind<'a, T, I>
-where
-    T: Drawable + std::fmt::Debug,
-    I: Borrow<T> + std::fmt::Debug + 'a,
-{
-    fn draw(&self, current_bounds: Size) -> Arc<Primitive> {
-        use std::ops::Deref;
-
-        if let State::Filled { bounds, primitive } =
-            self.cache.state.borrow().deref()
-        {
-            if *bounds == current_bounds {
-                return primitive.clone();
-            }
-        }
-
-        let mut frame = Frame::new(current_bounds.width, current_bounds.height);
-        self.input.borrow().draw(&mut frame);
-
-        let primitive = Arc::new(frame.into_primitive());
-
-        *self.cache.state.borrow_mut() = State::Filled {
-            bounds: current_bounds,
-            primitive: primitive.clone(),
-        };
-
-        primitive
-    }
-}
-
-impl std::fmt::Debug for State {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            State::Empty => write!(f, "Empty"),
-            State::Filled { primitive, bounds } => f
-                .debug_struct("Filled")
-                .field("primitive", primitive)
-                .field("bounds", bounds)
-                .finish(),
-        }
-    }
-}
diff --git a/wgpu/src/widget/canvas/program.rs b/wgpu/src/widget/canvas/program.rs
deleted file mode 100644
index c65a078b..00000000
--- a/wgpu/src/widget/canvas/program.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-use crate::canvas::{Event, Layer, Size};
-
-pub trait Program {
-    type Input;
-
-    fn layers<'a>(&'a self, input: &'a Self::Input)
-        -> Vec<Box<dyn Layer + 'a>>;
-
-    fn update<'a>(
-        &'a mut self,
-        _event: Event,
-        _bounds: Size,
-        _input: &'a Self::Input,
-    ) {
-    }
-}
diff --git a/wgpu/src/widget/canvas/state.rs b/wgpu/src/widget/canvas/state.rs
new file mode 100644
index 00000000..8388f94d
--- /dev/null
+++ b/wgpu/src/widget/canvas/state.rs
@@ -0,0 +1,20 @@
+use crate::canvas::{Event, Geometry, Size};
+
+pub trait State {
+    fn update(&mut self, _event: Event, _bounds: Size) {}
+
+    fn draw(&self, bounds: Size) -> Vec<Geometry>;
+}
+
+impl<T> State for &mut T
+where
+    T: State,
+{
+    fn update(&mut self, event: Event, bounds: Size) {
+        T::update(self, event, bounds);
+    }
+
+    fn draw(&self, bounds: Size) -> Vec<Geometry> {
+        T::draw(self, bounds)
+    }
+}
-- 
cgit