From 4f34e97f273a94e138ad2cdc17989ce00921c2f1 Mon Sep 17 00:00:00 2001 From: Alexandre Bury Date: Sun, 3 Mar 2019 18:06:50 -0800 Subject: [PATCH] Add user-data --- CHANGELOG.md | 4 ++++ examples/user_data.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ src/cursive.rs | 31 +++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 examples/user_data.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e74c79..c84ad8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ - Updated to Rust 2018 (now requires rustc > 1.31) - Add a logging implementation (`logger::init()`) and a `DebugConsole` (`cursive::toggle_debug_console()`) +- Add user-data to Cursive. + - `Cursive::set_user_data()` can store some user-defined data structure. + - `Cursive::user_data()` and `Cursive::with_user_data()` can be used to + access the data. - Add `StackView::remove_layer()` - Add `CircularFocus` view (and bring proper circular focus to dialogs) - Add `HideableView::is_visible()` diff --git a/examples/user_data.rs b/examples/user_data.rs new file mode 100644 index 0000000..0c9cbd1 --- /dev/null +++ b/examples/user_data.rs @@ -0,0 +1,42 @@ +//! This example shows the usage of user data. +//! +//! This lets you attach data to the main `Cursive` root, which can simplify +//! communication in simple applications. +//! +//! `Cursive::set_user_data` is used to store or update the user data, while +//! `Cursive::user_data` and `Cursive::with_user_data` can access it, if they +//! know the exact type. +use cursive::views::Dialog; +use cursive::Cursive; + +struct Data { + counter: u32, +} + +fn main() { + let mut siv = Cursive::default(); + + // `Cursive::set_user_data` accepts any `T: Any`, which includes most + // owned types + siv.set_user_data(Data { counter: 0 }); + + siv.add_layer( + Dialog::text("This uses some user data!") + .title("User data example") + .button("Increment", |s| { + // `Cursive::with_user_data()` is an easy way to run a closure + // on the data. + s.with_user_data(|data: &mut Data| { + data.counter += 1; + }); + }) + .button("Show", |s| { + // `Cursive::user_data()` returns a reference to the data. + let value = s.user_data::().unwrap().counter; + s.add_layer(Dialog::info(format!("Current value: {}", value))); + }) + .button("Quit", Cursive::quit), + ); + + siv.run(); +} diff --git a/src/cursive.rs b/src/cursive.rs index ef655ea..40e2780 100644 --- a/src/cursive.rs +++ b/src/cursive.rs @@ -43,6 +43,9 @@ pub struct Cursive { cb_source: Receiver>, cb_sink: Sender>, + + // User-provided data. + user_data: Box, } /// Identifies a screen in the cursive root. @@ -147,6 +150,7 @@ impl Cursive { cb_source, cb_sink, backend, + user_data: Box::new(()), } } @@ -181,6 +185,33 @@ impl Cursive { Self::new(backend::dummy::Backend::init) } + /// Sets some data to be stored in Cursive. + /// + /// It can later on be accessed with `Cursive::user_data()` + pub fn set_user_data(&mut self, user_data: T) { + self.user_data = Box::new(user_data); + } + + /// Attempts to access the user-provided data. + /// + /// If some data was set previously with the same type, returns a reference to it. + /// If nothing was set or if the type is different, returns `None`. + pub fn user_data(&mut self) -> Option<&mut T> { + self.user_data.downcast_mut() + } + + /// Runs the given closure on the stored user data, if any. + /// + /// If no user data was supplied, or if the type is different, nothing will be run. + /// Otherwise, the result will be returned. + pub fn with_user_data(&mut self, f: F) -> Option + where + F: FnOnce(&mut T) -> R, + T: Any, + { + self.user_data().map(f) + } + /// Show the debug console. /// /// Currently, this will show logs if [`::logger::init()`] was called.