From 98aff399047dac4e9d1cc7897920472312001738 Mon Sep 17 00:00:00 2001 From: Alexandre Bury Date: Mon, 22 Jan 2018 11:50:25 -0800 Subject: [PATCH] Move `View::as_any` to separate trait `AnyView` --- examples/key_codes.rs | 2 -- examples/logs.rs | 2 -- src/cursive.rs | 4 ++-- src/view/mod.rs | 31 +++++++++++++++++-------------- src/view/view_wrapper.rs | 18 ++++++++++++------ src/views/button.rs | 2 -- src/views/canvas.rs | 2 -- src/views/checkbox.rs | 2 -- src/views/dialog.rs | 6 ++---- src/views/dummy.rs | 2 -- src/views/edit_view.rs | 2 -- src/views/linear_layout.rs | 13 +++++-------- src/views/list_view.rs | 25 +++++++++++++------------ src/views/menu_popup.rs | 2 -- src/views/menubar.rs | 2 -- src/views/progress_bar.rs | 2 -- src/views/radio.rs | 3 --- src/views/select_view.rs | 2 -- src/views/slider_view.rs | 2 -- src/views/stack_view.rs | 14 +++++--------- src/views/text_area.rs | 2 -- src/views/text_view.rs | 2 -- 22 files changed, 56 insertions(+), 86 deletions(-) diff --git a/examples/key_codes.rs b/examples/key_codes.rs index 2b345b4..f628583 100644 --- a/examples/key_codes.rs +++ b/examples/key_codes.rs @@ -31,8 +31,6 @@ impl KeyCodeView { } impl View for KeyCodeView { - view_any!(); - fn draw(&self, printer: &Printer) { // We simply draw every event from the history. for (y, line) in self.history.iter().enumerate() { diff --git a/examples/logs.rs b/examples/logs.rs index c1f33a0..83463dd 100644 --- a/examples/logs.rs +++ b/examples/logs.rs @@ -81,8 +81,6 @@ impl BufferView { } impl View for BufferView { - view_any!(); - fn layout(&mut self, _: Vec2) { // Before drawing, we'll want to update the buffer self.update(); diff --git a/src/cursive.rs b/src/cursive.rs index e317498..7cb3286 100644 --- a/src/cursive.rs +++ b/src/cursive.rs @@ -9,7 +9,7 @@ use std::path::Path; use std::sync::mpsc; use theme; use vec::Vec2; -use view::{self, Finder, View}; +use view::{self, AnyView, Finder, View}; use views; /// Identifies a screen in the cursive root. @@ -418,7 +418,7 @@ impl Cursive { } /// Convenient method to remove a layer from the current screen. - pub fn pop_layer(&mut self) -> Option> { + pub fn pop_layer(&mut self) -> Option> { let result = self.screen_mut().pop_layer(); self.clear(); result diff --git a/src/view/mod.rs b/src/view/mod.rs index ca21b01..91fd629 100644 --- a/src/view/mod.rs +++ b/src/view/mod.rs @@ -35,15 +35,6 @@ //! no matter what the request is. This means calling `View::layout()` with //! a size returned by `required_size` is **never** an error. -/// Helper macro to implement `View::as_any` and `View::as_any_mut` -#[macro_export] -macro_rules! view_any { - () => { - fn as_any(&self) -> &::std::any::Any { self } - fn as_any_mut(&mut self) -> &mut ::std::any::Any { self } - } -} - #[macro_use] mod view_wrapper; @@ -73,6 +64,23 @@ use std::any::Any; use vec::Vec2; use views::IdView; +/// A view that can be downcasted to its concrete type. +pub trait AnyView: View { + /// Downcast self to a `Any`. + fn as_any(&self) -> &Any; + + /// Downcast self to a mutable `Any`. + fn as_any_mut(&mut self) -> &mut Any; +} + +impl AnyView for T { + /// Downcast self to a `Any`. + fn as_any(&self) -> &Any { self } + + /// Downcast self to a mutable `Any`. + fn as_any_mut(&mut self) -> &mut Any { self } +} + /// Main trait defining a view behaviour. pub trait View: Any { /// Called when a key was pressed. @@ -82,11 +90,6 @@ pub trait View: Any { EventResult::Ignored } - /// Downcast self to a `Any`. - fn as_any(&self) -> &Any; - - /// Downcast self to a mutable `Any`. - fn as_any_mut(&mut self) -> &mut Any; /// Returns the minimum size the view requires with the given restrictions. /// diff --git a/src/view/view_wrapper.rs b/src/view/view_wrapper.rs index 208649e..d0552b2 100644 --- a/src/view/view_wrapper.rs +++ b/src/view/view_wrapper.rs @@ -78,7 +78,9 @@ pub trait ViewWrapper: 'static { /// Wraps the `find` method. fn wrap_call_on_any<'a>( - &mut self, selector: &Selector, callback: Box + &mut self, + selector: &Selector, + callback: Box, ) { self.with_view_mut(|v| v.call_on_any(selector, callback)); } @@ -98,8 +100,12 @@ pub trait ViewWrapper: 'static { // Some types easily implement ViewWrapper. // This includes Box use std::ops::{Deref, DerefMut}; -impl + DerefMut + 'static> ViewWrapper - for T { + +impl ViewWrapper for T +where + U: View + ?Sized, + T: Deref + DerefMut + 'static, +{ type V = U; fn with_view(&self, f: F) -> Option @@ -119,8 +125,6 @@ impl + DerefMut + 'static> ViewWrapper // The main point of implementing ViewWrapper is to have View for free. impl View for T { - view_any!(); - fn draw(&self, printer: &Printer) { self.wrap_draw(printer); } @@ -142,7 +146,9 @@ impl View for T { } fn call_on_any<'a>( - &mut self, selector: &Selector, callback: Box + &mut self, + selector: &Selector, + callback: Box, ) { self.wrap_call_on_any(selector, callback) } diff --git a/src/views/button.rs b/src/views/button.rs index 9f5ab11..a0ec0fc 100644 --- a/src/views/button.rs +++ b/src/views/button.rs @@ -126,8 +126,6 @@ impl Button { } impl View for Button { - view_any!(); - fn draw(&self, printer: &Printer) { if printer.size.x == 0 { return; diff --git a/src/views/canvas.rs b/src/views/canvas.rs index 5766079..8d5d7af 100644 --- a/src/views/canvas.rs +++ b/src/views/canvas.rs @@ -173,8 +173,6 @@ impl Canvas { } impl View for Canvas { - view_any!(); - fn draw(&self, printer: &Printer) { (self.draw)(&self.state, printer); } diff --git a/src/views/checkbox.rs b/src/views/checkbox.rs index 3fd5ea8..6f8aef4 100644 --- a/src/views/checkbox.rs +++ b/src/views/checkbox.rs @@ -105,8 +105,6 @@ impl Checkbox { } impl View for Checkbox { - view_any!(); - fn required_size(&mut self, _: Vec2) -> Vec2 { Vec2::new(3, 1) } diff --git a/src/views/dialog.rs b/src/views/dialog.rs index 17cabc8..c76f277 100644 --- a/src/views/dialog.rs +++ b/src/views/dialog.rs @@ -10,7 +10,7 @@ use std::cmp::max; use theme::ColorStyle; use unicode_width::UnicodeWidthStr; use vec::{Vec2, Vec4}; -use view::{Selector, View}; +use view::{AnyView, Selector, View}; use views::{Button, DummyView, SizedView, TextView}; #[derive(PartialEq)] @@ -53,7 +53,7 @@ pub struct Dialog { title_position: HAlign, // The actual inner view. - content: SizedView>, + content: SizedView>, // Optional list of buttons under the main view. // Include the top-left corner. @@ -423,8 +423,6 @@ impl Dialog { } impl View for Dialog { - view_any!(); - fn draw(&self, printer: &Printer) { // This will be the buttons_height used by the buttons. let buttons_height = match self.draw_buttons(printer) { diff --git a/src/views/dummy.rs b/src/views/dummy.rs index 2123a50..5b88176 100644 --- a/src/views/dummy.rs +++ b/src/views/dummy.rs @@ -7,7 +7,5 @@ use view::View; pub struct DummyView; impl View for DummyView { - view_any!(); - fn draw(&self, _: &Printer) {} } diff --git a/src/views/edit_view.rs b/src/views/edit_view.rs index 4faee7c..4a2b775 100644 --- a/src/views/edit_view.rs +++ b/src/views/edit_view.rs @@ -434,8 +434,6 @@ fn make_small_stars(length: usize) -> &'static str { } impl View for EditView { - view_any!(); - fn draw(&self, printer: &Printer) { assert_eq!( printer.size.x, diff --git a/src/views/linear_layout.rs b/src/views/linear_layout.rs index f88606c..e191a8a 100644 --- a/src/views/linear_layout.rs +++ b/src/views/linear_layout.rs @@ -7,8 +7,7 @@ use std::any::Any; use std::cmp::min; use std::ops::Deref; use vec::Vec2; -use view::{Selector, SizeCache}; -use view::View; +use view::{AnyView, View, Selector, SizeCache}; /// Arranges its children linearly according to its orientation. pub struct LinearLayout { @@ -20,7 +19,7 @@ pub struct LinearLayout { } struct Child { - view: Box, + view: Box, // The last result from the child's required_size // Doesn't have to be what the child actually gets. size: Vec2, @@ -34,7 +33,7 @@ impl Child { self.size } - fn as_view(&self) -> &View { + fn as_view(&self) -> &AnyView { &*self.view } } @@ -161,12 +160,12 @@ impl LinearLayout { } /// Returns a reference to a child. - pub fn get_child(&self, i: usize) -> Option<&View> { + pub fn get_child(&self, i: usize) -> Option<&AnyView> { self.children.get(i).map(|child| &*child.view) } /// Returns a mutable reference to a child. - pub fn get_child_mut(&mut self, i: usize) -> Option<&mut View> { + pub fn get_child_mut(&mut self, i: usize) -> Option<&mut AnyView> { self.children.get_mut(i).map(|child| &mut *child.view) } @@ -297,8 +296,6 @@ fn try_focus( } impl View for LinearLayout { - view_any!(); - fn draw(&self, printer: &Printer) { // Use pre-computed sizes // eprintln!("Pre loop!"); diff --git a/src/views/list_view.rs b/src/views/list_view.rs index e419cd2..4925d99 100644 --- a/src/views/list_view.rs +++ b/src/views/list_view.rs @@ -7,16 +7,14 @@ use std::any::Any; use std::rc::Rc; use unicode_width::UnicodeWidthStr; use vec::Vec2; -use view::ScrollBase; -use view::Selector; -use view::View; +use view::{AnyView, ScrollBase, Selector, View}; /// Represents a child from a [`ListView`]. /// /// [`ListView`]: struct.ListView.html pub enum ListChild { /// A single row, with a label and a view. - Row(String, Box), + Row(String, Box), /// A delimiter between groups. Delimiter, } @@ -29,7 +27,7 @@ impl ListChild { } } - fn view(&mut self) -> Option<&mut View> { + fn view(&mut self) -> Option<&mut AnyView> { match *self { ListChild::Row(_, ref mut view) => Some(view.as_mut()), _ => None, @@ -150,7 +148,9 @@ impl ListView { } fn iter_mut<'a>( - &'a mut self, from_focus: bool, source: direction::Relative + &'a mut self, + from_focus: bool, + source: direction::Relative, ) -> Box + 'a> { match source { direction::Relative::Front => { @@ -174,7 +174,9 @@ impl ListView { } fn move_focus( - &mut self, n: usize, source: direction::Direction + &mut self, + n: usize, + source: direction::Direction, ) -> EventResult { let i = if let Some(i) = source .relative(direction::Orientation::Vertical) @@ -248,7 +250,8 @@ impl ListView { } fn try_focus( - (i, child): (usize, &mut ListChild), source: direction::Direction + (i, child): (usize, &mut ListChild), + source: direction::Direction, ) -> Option { match *child { ListChild::Delimiter => None, @@ -261,9 +264,6 @@ fn try_focus( } impl View for ListView { - view_any!(); - - fn draw(&self, printer: &Printer) { if self.children.is_empty() { return; @@ -454,7 +454,8 @@ impl View for ListView { } fn call_on_any<'a>( - &mut self, selector: &Selector, + &mut self, + selector: &Selector, mut callback: Box, ) { for view in self.children.iter_mut().filter_map(ListChild::view) { diff --git a/src/views/menu_popup.rs b/src/views/menu_popup.rs index 7da673e..365ec13 100644 --- a/src/views/menu_popup.rs +++ b/src/views/menu_popup.rs @@ -199,8 +199,6 @@ impl MenuPopup { } impl View for MenuPopup { - view_any!(); - fn draw(&self, printer: &Printer) { if !printer.size.fits((2, 2)) { return; diff --git a/src/views/menubar.rs b/src/views/menubar.rs index b39dee3..abb83fc 100644 --- a/src/views/menubar.rs +++ b/src/views/menubar.rs @@ -259,8 +259,6 @@ fn show_child(s: &mut Cursive, offset: Vec2, menu: Rc) { } impl View for Menubar { - view_any!(); - fn draw(&self, printer: &Printer) { // Draw the bar at the top printer.with_color(ColorStyle::primary(), |printer| { diff --git a/src/views/progress_bar.rs b/src/views/progress_bar.rs index b0f2bdb..44538e4 100644 --- a/src/views/progress_bar.rs +++ b/src/views/progress_bar.rs @@ -193,8 +193,6 @@ impl ProgressBar { } impl View for ProgressBar { - view_any!(); - fn draw(&self, printer: &Printer) { // Now, the bar itself... let available = printer.size.x; diff --git a/src/views/radio.rs b/src/views/radio.rs index 0f5a247..15cd4e3 100644 --- a/src/views/radio.rs +++ b/src/views/radio.rs @@ -154,9 +154,6 @@ impl RadioButton { } impl View for RadioButton { - view_any!(); - - fn required_size(&mut self, _: Vec2) -> Vec2 { self.req_size() } diff --git a/src/views/select_view.rs b/src/views/select_view.rs index be529f6..dfd2897 100644 --- a/src/views/select_view.rs +++ b/src/views/select_view.rs @@ -570,8 +570,6 @@ impl SelectView { } impl View for SelectView { - view_any!(); - fn draw(&self, printer: &Printer) { self.last_offset.set(printer.offset); diff --git a/src/views/slider_view.rs b/src/views/slider_view.rs index 13f7fce..01476ef 100644 --- a/src/views/slider_view.rs +++ b/src/views/slider_view.rs @@ -112,8 +112,6 @@ impl SliderView { } impl View for SliderView { - view_any!(); - fn draw(&self, printer: &Printer) { match self.orientation { Orientation::Vertical => { diff --git a/src/views/stack_view.rs b/src/views/stack_view.rs index 63177dc..794c7bb 100644 --- a/src/views/stack_view.rs +++ b/src/views/stack_view.rs @@ -6,7 +6,7 @@ use std::any::Any; use std::ops::Deref; use theme::ColorStyle; use vec::Vec2; -use view::{Offset, Position, Selector, View, ViewWrapper}; +use view::{AnyView, Offset, Position, Selector, View, ViewWrapper}; use views::{Layer, ShadowView}; /// Simple stack of views. @@ -71,8 +71,6 @@ impl ChildWrapper { // TODO: use macros to make this less ugly? impl View for ChildWrapper { - view_any!(); - fn draw(&self, printer: &Printer) { match *self { ChildWrapper::Shadow(ref v) => v.draw(printer), @@ -130,7 +128,7 @@ impl View for ChildWrapper { } struct Child { - view: ChildWrapper>, + view: ChildWrapper>, size: Vec2, placement: Placement, @@ -159,7 +157,7 @@ impl StackView { where T: 'static + View, { - let boxed: Box = Box::new(view); + let boxed: Box = Box::new(view); self.layers.push(Child { view: ChildWrapper::Plain(Layer::new(boxed)), size: Vec2::zero(), @@ -201,7 +199,7 @@ impl StackView { where T: 'static + View, { - let boxed: Box = Box::new(view); + let boxed: Box = Box::new(view); self.layers.push(Child { // Skip padding for absolute/parent-placed views view: ChildWrapper::Shadow( @@ -226,7 +224,7 @@ impl StackView { } /// Remove the top-most layer. - pub fn pop_layer(&mut self) -> Option> { + pub fn pop_layer(&mut self) -> Option> { self.layers.pop().map(|child| child.view.unwrap()) } @@ -324,8 +322,6 @@ impl, I: Iterator> Iterator } impl View for StackView { - view_any!(); - fn draw(&self, printer: &Printer) { let last = self.layers.len(); printer.with_color(ColorStyle::primary(), |printer| { diff --git a/src/views/text_area.rs b/src/views/text_area.rs index ea0a12c..3e72e43 100644 --- a/src/views/text_area.rs +++ b/src/views/text_area.rs @@ -396,8 +396,6 @@ impl TextArea { } impl View for TextArea { - view_any!(); - fn required_size(&mut self, constraint: Vec2) -> Vec2 { // Make sure our structure is up to date self.soft_compute_rows(constraint); diff --git a/src/views/text_view.rs b/src/views/text_view.rs index d175f3f..72c9c75 100644 --- a/src/views/text_view.rs +++ b/src/views/text_view.rs @@ -448,8 +448,6 @@ impl TextView { } impl View for TextView { - view_any!(); - fn draw(&self, printer: &Printer) { let h = self.rows.len(); // If the content is smaller than the view, align it somewhere.