Add RefCellView

Wraps a view and provide interior mutability
This commit is contained in:
Alexandre Bury 2017-02-08 11:57:28 -08:00
parent b63762d441
commit b0193b0ebc
4 changed files with 64 additions and 7 deletions

View File

@ -1,11 +1,11 @@
[package]
authors = ["Alexandre Bury <alexandre.bury@gmail.com>"]
build = "build.rs"
categories = ["command-line-interface", "gui"]
description = "A TUI (Text User Interface) library focused on ease-of-use."
documentation = "https://gyscos.github.io/Cursive/cursive/index.html"
exclude = ["doc", "assets"]
keywords = ["ncurses", "TUI", "UI"]
categories = ["command-line-interface", "gui"]
license = "MIT"
name = "cursive"
readme = "Readme.md"
@ -13,7 +13,11 @@ repository = "https://github.com/gyscos/Cursive"
version = "0.4.0"
[badges]
travis-ci = { repository = "gyscos/Cursive" }
[badges.travis-ci]
repository = "gyscos/Cursive"
[build-dependencies]
[build-dependencies.skeptic]
optional = true
@ -23,18 +27,19 @@ version = "0.6"
chan = "0.1.18"
num = "0.1"
odds = "0.2"
owning_ref = "0.2.4"
toml = "0.2"
unicode-segmentation = "1.0"
unicode-width = "0.1"
[dependencies.chan-signal]
optional = true
version = "0.1"
[dependencies.bear-lib-terminal]
optional = true
version = "1.3.1"
[dependencies.chan-signal]
optional = true
version = "0.1"
[dependencies.ncurses]
features = ["wide"]
optional = true
@ -55,8 +60,8 @@ skeptic = "0.6"
[features]
default = ["ncurses"]
termion-backend = ["termion", "chan-signal"]
pancurses-backend = ["pancurses"]
termion-backend = ["termion", "chan-signal"]
[lib]
name = "cursive"

View File

@ -64,6 +64,7 @@ extern crate unicode_segmentation;
extern crate unicode_width;
extern crate odds;
extern crate num;
extern crate owning_ref;
#[macro_use]
extern crate chan;

View File

@ -52,6 +52,7 @@ mod menu_popup;
mod panel;
mod progress_bar;
mod radio;
mod refcell_view;
mod select_view;
mod slider_view;
mod shadow_view;
@ -78,6 +79,7 @@ pub use self::menubar::Menubar;
pub use self::panel::Panel;
pub use self::progress_bar::{Counter, ProgressBar};
pub use self::radio::{RadioGroup, RadioButton};
pub use self::refcell_view::{RefCellView, ViewRef};
pub use self::select_view::SelectView;
pub use self::shadow_view::ShadowView;
pub use self::sized_view::SizedView;

49
src/views/refcell_view.rs Normal file
View File

@ -0,0 +1,49 @@
use owning_ref::{RcRef, OwningHandle};
use std::cell::{RefCell, RefMut};
use std::rc::Rc;
use view::{View, ViewWrapper};
/// Wrapper around a view to provide interior mutability.
pub struct RefCellView<V: View> {
view: Rc<RefCell<V>>,
}
/// Mutable reference to a view.
pub type ViewRef<V> = OwningHandle<RcRef<RefCell<V>>, RefMut<'static, V>>;
impl<V: View> RefCellView<V> {
/// Wraps `view` in a new `RefCellView`.
pub fn new(view: V) -> Self {
RefCellView { view: Rc::new(RefCell::new(view)) }
}
/// Gets mutable access to the inner view.
pub fn get_mut(&mut self) -> ViewRef<V> {
// TODO: return a standalone item (not tied to our lifetime)
// that bundles `self.view.clone()` and allow mutable reference to
// the inner view.
let cell_ref = RcRef::new(self.view.clone());
OwningHandle::new(cell_ref,
|x| unsafe { x.as_ref() }.unwrap().borrow_mut())
}
}
impl<T: View> ViewWrapper for RefCellView<T> {
type V = T;
fn with_view<F, R>(&self, f: F) -> R
where F: FnOnce(&Self::V) -> R
{
f(&*self.view.borrow())
}
fn with_view_mut<F, R>(&mut self, f: F) -> R
where F: FnOnce(&mut Self::V) -> R
{
f(&mut *self.view.borrow_mut())
}
}