Use an associated type in ViewWrapper

This removes the need for dynamic dispatching
This commit is contained in:
Alexandre Bury 2016-09-19 17:11:00 -07:00
parent 3813f7c446
commit 08d1c1e5b0
8 changed files with 26 additions and 46 deletions

View File

@ -16,11 +16,14 @@ use event::{Event, EventResult};
/// ///
/// [`wrap_impl!`]: ../macro.wrap_impl.html /// [`wrap_impl!`]: ../macro.wrap_impl.html
pub trait ViewWrapper { pub trait ViewWrapper {
/// Type that this view wraps.
type V: View;
/// Get an immutable reference to the wrapped view. /// Get an immutable reference to the wrapped view.
fn get_view(&self) -> &View; fn get_view(&self) -> &Self::V;
/// Get a mutable reference to the wrapped view. /// Get a mutable reference to the wrapped view.
fn get_view_mut(&mut self) -> &mut View; fn get_view_mut(&mut self) -> &mut Self::V;
/// Wraps the `draw` method. /// Wraps the `draw` method.
fn wrap_draw(&self, printer: &Printer) { fn wrap_draw(&self, printer: &Printer) {
@ -90,27 +93,13 @@ impl<T: ViewWrapper> View for T {
/// Convenient macro to implement the [`ViewWrapper`] trait. /// Convenient macro to implement the [`ViewWrapper`] trait.
/// ///
/// It defines the `get_view` and `get_view_mut` implementations,
/// as well as the `type V` declaration.
///
/// [`ViewWrapper`]: view/trait.ViewWrapper.html /// [`ViewWrapper`]: view/trait.ViewWrapper.html
/// ///
/// # Examples /// # Examples
/// ///
/// If the wrapped view is in a box, just name it in the macro:
///
/// ```no_run
/// # #[macro_use] extern crate cursive;
/// # use cursive::view::{View,ViewWrapper};
/// struct BoxFooView {
/// content: Box<View>,
/// }
///
/// impl ViewWrapper for BoxFooView {
/// wrap_impl!(self.content);
/// }
/// # fn main() { }
/// ```
///
/// If the content is directly a view, reference it:
///
/// ```no_run /// ```no_run
/// # #[macro_use] extern crate cursive; /// # #[macro_use] extern crate cursive;
/// # use cursive::view::{View,ViewWrapper}; /// # use cursive::view::{View,ViewWrapper};
@ -119,30 +108,21 @@ impl<T: ViewWrapper> View for T {
/// } /// }
/// ///
/// impl <T: View> ViewWrapper for FooView<T> { /// impl <T: View> ViewWrapper for FooView<T> {
/// wrap_impl!(&self.view); /// wrap_impl!(self.view: T);
/// } /// }
/// # fn main() { } /// # fn main() { }
/// ``` /// ```
#[macro_export] #[macro_export]
macro_rules! wrap_impl { macro_rules! wrap_impl {
(&self.$v:ident) => { (self.$v:ident: $t:path) => {
type V = $t;
fn get_view(&self) -> &View { fn get_view(&self) -> &Self::V {
&self.$v &self.$v
} }
fn get_view_mut(&mut self) -> &mut View { fn get_view_mut(&mut self) -> &mut Self::V {
&mut self.$v &mut self.$v
} }
}; };
(self.$v:ident) => {
fn get_view(&self) -> &View {
&*self.$v
}
fn get_view_mut(&mut self) -> &mut View {
&mut *self.$v
}
};
} }

View File

@ -149,7 +149,7 @@ impl<T: View> BoxView<T> {
} }
impl<T: View> ViewWrapper for BoxView<T> { impl<T: View> ViewWrapper for BoxView<T> {
wrap_impl!(&self.view); wrap_impl!(self.view: T);
fn wrap_get_min_size(&mut self, req: Vec2) -> Vec2 { fn wrap_get_min_size(&mut self, req: Vec2) -> Vec2 {

View File

@ -19,7 +19,7 @@ impl<T: View> IdView<T> {
} }
impl<T: View + Any> ViewWrapper for IdView<T> { impl<T: View + Any> ViewWrapper for IdView<T> {
wrap_impl!(&self.view); wrap_impl!(self.view: T);
fn wrap_find(&mut self, selector: &Selector) -> Option<&mut Any> { fn wrap_find(&mut self, selector: &Selector) -> Option<&mut Any> {
match selector { match selector {

View File

@ -16,16 +16,16 @@ use view::{View, ViewWrapper};
/// .register('q', |s| s.quit()) /// .register('q', |s| s.quit())
/// .register(Key::Esc, |s| s.quit()); /// .register(Key::Esc, |s| s.quit());
/// ``` /// ```
pub struct KeyEventView { pub struct KeyEventView<T: View> {
content: Box<View>, content: T,
callbacks: HashMap<Event, Callback>, callbacks: HashMap<Event, Callback>,
} }
impl KeyEventView { impl <T: View> KeyEventView<T> {
/// Wraps the given view in a new KeyEventView. /// Wraps the given view in a new KeyEventView.
pub fn new<V: View + 'static>(view: V) -> Self { pub fn new(view: T) -> Self {
KeyEventView { KeyEventView {
content: Box::new(view), content: view,
callbacks: HashMap::new(), callbacks: HashMap::new(),
} }
} }
@ -40,8 +40,8 @@ impl KeyEventView {
} }
} }
impl ViewWrapper for KeyEventView { impl <T: View> ViewWrapper for KeyEventView<T> {
wrap_impl!(self.content); wrap_impl!(self.content: T);
fn wrap_on_event(&mut self, event: Event) -> EventResult { fn wrap_on_event(&mut self, event: Event) -> EventResult {
match self.content.on_event(event) { match self.content.on_event(event) {

View File

@ -16,7 +16,7 @@ impl<V: View> Panel<V> {
impl<V: View> ViewWrapper for Panel<V> { impl<V: View> ViewWrapper for Panel<V> {
wrap_impl!(&self.view); wrap_impl!(self.view: V);
fn wrap_get_min_size(&mut self, req: Vec2) -> Vec2 { fn wrap_get_min_size(&mut self, req: Vec2) -> Vec2 {
// TODO: make borders conditional? // TODO: make borders conditional?

View File

@ -45,7 +45,7 @@ impl<T: View> ShadowView<T> {
} }
impl<T: View> ViewWrapper for ShadowView<T> { impl<T: View> ViewWrapper for ShadowView<T> {
wrap_impl!(&self.view); wrap_impl!(self.view: T);
fn wrap_get_min_size(&mut self, req: Vec2) -> Vec2 { fn wrap_get_min_size(&mut self, req: Vec2) -> Vec2 {
// Make sure req >= offset // Make sure req >= offset

View File

@ -21,7 +21,7 @@ impl<T: View> SizedView<T> {
} }
impl<T: View> ViewWrapper for SizedView<T> { impl<T: View> ViewWrapper for SizedView<T> {
wrap_impl!(&self.view); wrap_impl!(self.view: T);
fn wrap_layout(&mut self, size: Vec2) { fn wrap_layout(&mut self, size: Vec2) {
self.size = size; self.size = size;

View File

@ -36,7 +36,7 @@ impl<T: View> TrackedView<T> {
} }
impl<T: View> ViewWrapper for TrackedView<T> { impl<T: View> ViewWrapper for TrackedView<T> {
wrap_impl!(&self.view); wrap_impl!(self.view: T);
fn wrap_draw(&self, printer: &Printer) { fn wrap_draw(&self, printer: &Printer) {
self.offset.set(printer.offset); self.offset.set(printer.offset);