Skip to content

Commit 985caf3

Browse files
committed
x-bow: guaranteed get and set methods, plus more documentations
1 parent 816fb38 commit 985caf3

File tree

4 files changed

+170
-11
lines changed

4 files changed

+170
-11
lines changed

x-bow/src/guarantee.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,24 @@ pub trait PathExtGuaranteed: PathExt {
3535
fn borrow_mut_without_notifying(&self) -> RefMut<'_, <Self as Path>::Out> {
3636
self.borrow_opt_mut_without_notifying().unwrap()
3737
}
38+
39+
/// Clone the data identified by this path.
40+
///
41+
/// Equivalent to `path.borrow().clone()`.
42+
fn get(&self) -> Self::Out
43+
where
44+
Self::Out: Clone,
45+
{
46+
self.borrow().clone()
47+
}
48+
49+
/// Set the data identified by this path, notifying listeners.
50+
///
51+
/// Equivalent to `*path.borrow_mut() = data;`
52+
fn set(&self, data: Self::Out)
53+
where
54+
Self::Out: Sized,
55+
{
56+
*self.borrow_mut() = data;
57+
}
3858
}

x-bow/src/lib.rs

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
//! let stream = path.until_change();
3535
//!
3636
//! // Mutably borrow the `i32` of the path, and increment it.
37-
//! // This will cause the `stream` we create to fire.
37+
//! // This will cause the `stream` we created to fire.
3838
//! *path.borrow_mut() += 1;
3939
//! ```
4040
//!
@@ -68,6 +68,103 @@
6868
//! Types that implements [Trackable] have their corresponding `PathBuilder` type.
6969
//! To be `Trackable`, types should have `#[derive(Trackable)]` on them.
7070
//!
71+
//! ## Usage
72+
//! ### Steps
73+
//! 1. Make your structs and enums trackable by putting
74+
//! `#[derive(Trackable)]` and `[track(deep)]` on them.
75+
//! See documentation for the [Trackable macro][derive@Trackable].
76+
//! ```
77+
//! # use x_bow::{Trackable, Store, PathExt, PathExtGuaranteed};
78+
//! // 👇 Derive `Trackable` to allow parts of the struct to be tracked.
79+
//! #[derive(Trackable)]
80+
//! #[track(deep)]
81+
//! struct MyStruct {
82+
//! field_1: i32,
83+
//! field_2: u64,
84+
//! child_enum: MyEnum
85+
//! }
86+
//! // 👇 Derive `Trackable` to allow parts of the enum to be tracked.
87+
//! #[derive(Trackable)]
88+
//! #[track(deep)]
89+
//! enum MyEnum {
90+
//! Variant1(i32),
91+
//! Variant2 {
92+
//! data: String
93+
//! }
94+
//! }
95+
//! ```
96+
//! 2. Put your data in a [Store].
97+
//! ```
98+
//! # use x_bow::{Trackable, Store, PathExt, PathExtGuaranteed};
99+
//! # #[derive(Trackable)]
100+
//! # #[track(deep)]
101+
//! # struct MyStruct {
102+
//! # field_1: i32,
103+
//! # field_2: u64,
104+
//! # child_enum: MyEnum
105+
//! # }
106+
//! #
107+
//! # #[derive(Trackable)]
108+
//! # #[track(deep)]
109+
//! # enum MyEnum {
110+
//! # Variant1(i32),
111+
//! # Variant2 {
112+
//! # data: String
113+
//! # }
114+
//! # }
115+
//! let my_data = MyStruct {
116+
//! field_1: 42,
117+
//! field_2: 123,
118+
//! child_enum: MyEnum::Variant2 { data: "Hello".to_string() }
119+
//! };
120+
//! let store = Store::new(my_data);
121+
//! ```
122+
//! 3. Make [Path]s.
123+
//! ```
124+
//! # use x_bow::{Trackable, Store, PathExt, PathExtGuaranteed};
125+
//! # #[derive(Trackable)]
126+
//! # #[track(deep)]
127+
//! # struct MyStruct {
128+
//! # field_1: i32,
129+
//! # field_2: u64,
130+
//! # child_enum: MyEnum
131+
//! # }
132+
//! #
133+
//! # #[derive(Trackable)]
134+
//! # #[track(deep)]
135+
//! # enum MyEnum {
136+
//! # Variant1(i32),
137+
//! # Variant2 {
138+
//! # data: String
139+
//! # }
140+
//! # }
141+
//! let my_data = MyStruct {
142+
//! field_1: 42,
143+
//! field_2: 123,
144+
//! child_enum: MyEnum::Variant2 { data: "Hello".to_string() }
145+
//! };
146+
//! # let store = Store::new(my_data);
147+
//! let path_to_field_1 = store.build_path().field_1();
148+
//! let path_to_data = store.build_path().child_enum().Variant2_data();
149+
//! ```
150+
//! 4. Use the Paths you made.
151+
//! See [PathExt] and [PathExtGuaranteed] for available APIs.
152+
//!
153+
//! ### Tracking through Vec and HashMap
154+
//! You can track through [Vec] using the `index(_)` method.
155+
//! ```
156+
//! # use x_bow::{Trackable, Store, PathExt, PathExtGuaranteed};
157+
//! let store = Store::new(vec![1, 2, 3]);
158+
//! let path = store.build_path().index(1); // 👈 path to the second element in the vec
159+
//! ```
160+
//! You can track through [HashMap][std::collections::HashMap] using the `key(_)` method.
161+
//! ```
162+
//! # use x_bow::{Trackable, Store, PathExt, PathExtGuaranteed};
163+
//! # use std::collections::HashMap;
164+
//! let store = Store::new(HashMap::<u32, String>::new());
165+
//! let path = store.build_path().key(555); // 👈 path to the String at key 555 in the hashmap.
166+
//! ```
167+
//!
71168
//! ## Design
72169
//!
73170
//! ### Borrowing and Paths

x-bow/src/path_ext.rs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ pub trait PathExt: Path {
129129
/// Clone the data identified by this path.
130130
///
131131
/// Equivalent to `path.borrow_opt().as_deref().map(Clone::clone)`.
132-
fn get_cloned(&self) -> Option<Self::Out>
132+
fn get_opt(&self) -> Option<Self::Out>
133133
where
134134
Self::Out: Clone,
135135
{
@@ -138,17 +138,18 @@ pub trait PathExt: Path {
138138

139139
/// Set the data identified by this path, notifying listeners.
140140
///
141-
/// Returns whether or not the data was set.
142-
///
143-
/// Equivalent to `self.borrow_opt_mut().as_deref_mut().map(|s| *s = data).is_some()`.
144-
fn set(&self, data: Self::Out) -> bool
141+
/// If the data cannot be accessed, Err is returned with the input.
142+
fn set_opt(&self, data: Self::Out) -> Result<(), Self::Out>
145143
where
146144
Self::Out: Sized,
147145
{
148-
self.borrow_opt_mut()
149-
.as_deref_mut()
150-
.map(|s| *s = data)
151-
.is_some()
146+
match self.borrow_opt_mut().as_deref_mut() {
147+
Some(state) => {
148+
*state = data;
149+
Ok(())
150+
}
151+
None => Err(data),
152+
}
152153
}
153154

154155
/// Get a [Stream][futures_core::Stream] that fires everytime a mutable
@@ -425,6 +426,22 @@ pub trait PathExt: Path {
425426
/// This is useful when you are handling the type that implements `Path`
426427
/// directly. Most of the time, though, you will already be working with
427428
/// `PathBuilder`s.
429+
///
430+
/// ```
431+
/// # use x_bow::{Path, PathExt, PathExtGuaranteed, Store, Trackable, IntoPath};
432+
/// fn modify_string(path: impl Path<Out = String>) {
433+
/// path.set_opt("haha".to_string()).ok();
434+
/// }
435+
/// #[derive(Trackable)]
436+
/// struct MyStruct {
437+
/// s: String
438+
/// }
439+
/// let store = Store::new(MyStruct {
440+
/// s: String::from("hello world")
441+
/// });
442+
/// modify_string(store.build_path().s().into_path());
443+
/// assert_eq!(&**store.build_path().s().borrow(), "haha");
444+
/// ```
428445
fn build_path(self) -> <Self::Out as Trackable>::PathBuilder<Self>
429446
where
430447
Self: Sized,
@@ -435,7 +452,6 @@ pub trait PathExt: Path {
435452

436453
/// Create a new Path from borrowing this path.
437454
///
438-
/// Usually, paths are owned and live for as long as the store itself.
439455
/// ```
440456
/// # use x_bow::{Trackable, Store, PathExt};
441457
/// # #[derive(Default, Trackable)]

x-bow/tests/get_and_set.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use x_bow::{PathExtGuaranteed, Store};
2+
use x_bow_macros::Trackable;
3+
4+
#[test]
5+
fn get_and_set() {
6+
#[derive(Trackable, Debug, Default, PartialEq, Clone)]
7+
#[track(deep)]
8+
struct State {
9+
a: String,
10+
b: (Struct1, i32),
11+
}
12+
#[derive(Trackable, Debug, Default, PartialEq, Clone)]
13+
#[track(deep)]
14+
struct Struct1 {
15+
c: i32,
16+
}
17+
let state = Store::new(State {
18+
a: String::from("Hello World"),
19+
b: (Struct1 { c: 5678 }, 1234),
20+
});
21+
assert_eq!(state.build_path().b().t1().get(), 1234);
22+
assert_eq!(state.build_path().b().t0().get(), Struct1 { c: 5678 });
23+
assert_eq!(state.build_path().b().t0().c().get(), 5678);
24+
state.build_path().b().t0().set(Struct1 { c: 42 });
25+
assert_eq!(state.build_path().b().t0().c().get(), 42);
26+
}

0 commit comments

Comments
 (0)