Make RefCellView re-entrant safe

Don't crash if the view is already borrowed.
This commit is contained in:
Alexandre Bury 2017-02-08 15:33:43 -08:00
parent 1b8d109e94
commit b50d2f077f
2 changed files with 16 additions and 14 deletions

View File

@ -20,10 +20,10 @@ pub trait ViewWrapper {
type V: View; type V: View;
/// Get an immutable reference to the wrapped view. /// Get an immutable reference to the wrapped view.
fn with_view<F, R>(&self, f: F) -> R where F: FnOnce(&Self::V) -> R; fn with_view<F, R>(&self, f: F) -> Option<R> where F: FnOnce(&Self::V) -> R;
/// Get a mutable reference to the wrapped view. /// Get a mutable reference to the wrapped view.
fn with_view_mut<F, R>(&mut self, f: F) -> R fn with_view_mut<F, R>(&mut self, f: F) -> Option<R>
where F: FnOnce(&mut Self::V) -> R; where F: FnOnce(&mut Self::V) -> R;
/// Wraps the `draw` method. /// Wraps the `draw` method.
@ -33,12 +33,12 @@ pub trait ViewWrapper {
/// Wraps the `required_size` method. /// Wraps the `required_size` method.
fn wrap_required_size(&mut self, req: Vec2) -> Vec2 { fn wrap_required_size(&mut self, req: Vec2) -> Vec2 {
self.with_view_mut(|v| v.required_size(req)) self.with_view_mut(|v| v.required_size(req)).unwrap_or_else(Vec2::zero)
} }
/// Wraps the `on_event` method. /// Wraps the `on_event` method.
fn wrap_on_event(&mut self, ch: Event) -> EventResult { fn wrap_on_event(&mut self, ch: Event) -> EventResult {
self.with_view_mut(|v| v.on_event(ch)) self.with_view_mut(|v| v.on_event(ch)).unwrap_or(EventResult::Ignored)
} }
/// Wraps the `layout` method. /// Wraps the `layout` method.
@ -48,7 +48,7 @@ pub trait ViewWrapper {
/// Wraps the `take_focus` method. /// Wraps the `take_focus` method.
fn wrap_take_focus(&mut self, source: Direction) -> bool { fn wrap_take_focus(&mut self, source: Direction) -> bool {
self.with_view_mut(|v| v.take_focus(source)) self.with_view_mut(|v| v.take_focus(source)).unwrap_or(false)
} }
/// Wraps the `find` method. /// Wraps the `find` method.
@ -59,7 +59,7 @@ pub trait ViewWrapper {
/// Wraps the `needs_relayout` method. /// Wraps the `needs_relayout` method.
fn wrap_needs_relayout(&self) -> bool { fn wrap_needs_relayout(&self) -> bool {
self.with_view(|v| v.needs_relayout()) self.with_view(|v| v.needs_relayout()).unwrap_or(true)
} }
} }
@ -120,14 +120,16 @@ macro_rules! wrap_impl {
(self.$v:ident: $t:ty) => { (self.$v:ident: $t:ty) => {
type V = $t; type V = $t;
fn with_view<F, R>(&self, f: F) -> R where F: FnOnce(&Self::V) -> R { fn with_view<F, R>(&self, f: F) -> Option<R>
f(&self.$v) where F: FnOnce(&Self::V) -> R
{
Some(f(&self.$v))
} }
fn with_view_mut<F, R>(&mut self, f: F) -> R fn with_view_mut<F, R>(&mut self, f: F) -> Option<R>
where F: FnOnce(&mut Self::V) -> R where F: FnOnce(&mut Self::V) -> R
{ {
f(&mut self.$v) Some(f(&mut self.$v))
} }
}; };
} }

View File

@ -35,15 +35,15 @@ impl<V: View> RefCellView<V> {
impl<T: View> ViewWrapper for RefCellView<T> { impl<T: View> ViewWrapper for RefCellView<T> {
type V = T; type V = T;
fn with_view<F, R>(&self, f: F) -> R fn with_view<F, R>(&self, f: F) -> Option<R>
where F: FnOnce(&Self::V) -> R where F: FnOnce(&Self::V) -> R
{ {
f(&*self.view.borrow()) self.view.try_borrow().ok().map(|v| f(&*v))
} }
fn with_view_mut<F, R>(&mut self, f: F) -> R fn with_view_mut<F, R>(&mut self, f: F) -> Option<R>
where F: FnOnce(&mut Self::V) -> R where F: FnOnce(&mut Self::V) -> R
{ {
f(&mut *self.view.borrow_mut()) self.view.try_borrow_mut().ok().map(|mut v| f(&mut *v))
} }
} }