yew_hooks/hooks/
use_set.rs

1use std::cell::{Ref, RefCell};
2use std::collections::HashSet;
3use std::hash::Hash;
4use std::rc::Rc;
5
6use yew::prelude::*;
7
8use super::use_update;
9
10/// State handle for the [`use_set`] hook.
11pub struct UseSetHandle<T> {
12    inner: Rc<RefCell<HashSet<T>>>,
13    update: Rc<dyn Fn()>,
14}
15
16impl<T> UseSetHandle<T> {
17    /// Get immutable ref to the set.
18    ///
19    /// # Panics
20    ///
21    /// Panics if the value is currently mutably borrowed
22    pub fn current(&self) -> Ref<HashSet<T>> {
23        self.inner.borrow()
24    }
25
26    /// Set the hash set.
27    pub fn set(&self, set: HashSet<T>) {
28        *self.inner.borrow_mut() = set;
29        (self.update)();
30    }
31
32    /// Adds a value to the set.
33    pub fn insert(&self, value: T) -> bool
34    where
35        T: Eq + Hash,
36    {
37        let present = self.inner.borrow_mut().insert(value);
38        (self.update)();
39        present
40    }
41
42    /// Adds a value to the set, replacing the existing value,
43    /// if any, that is equal to the given one. Returns the replaced value.
44    pub fn replace(&self, value: T) -> Option<T>
45    where
46        T: Eq + Hash,
47    {
48        let v = self.inner.borrow_mut().replace(value);
49        (self.update)();
50        v
51    }
52
53    /// Removes a value from the set. Returns whether the value was present in the set.
54    pub fn remove(&self, value: &T) -> bool
55    where
56        T: Eq + Hash,
57    {
58        let present = self.inner.borrow_mut().remove(value);
59        (self.update)();
60        present
61    }
62
63    /// Retains only the elements specified by the predicate.
64    pub fn retain<F>(&self, f: F)
65    where
66        T: Eq + Hash,
67        F: FnMut(&T) -> bool,
68    {
69        self.inner.borrow_mut().retain(f);
70        (self.update)();
71    }
72
73    /// Clears the set, removing all values.
74    pub fn clear(&self) {
75        self.inner.borrow_mut().clear();
76        (self.update)();
77    }
78}
79
80impl<T> Clone for UseSetHandle<T> {
81    fn clone(&self) -> Self {
82        Self {
83            inner: self.inner.clone(),
84            update: self.update.clone(),
85        }
86    }
87}
88
89impl<T> PartialEq for UseSetHandle<T>
90where
91    T: Eq + Hash,
92{
93    fn eq(&self, other: &Self) -> bool {
94        *self.inner == *other.inner
95    }
96}
97
98/// A hook that tracks a hash set and provides methods to modify it.
99///
100/// # Example
101///
102/// ```rust
103/// # use std::collections::HashSet;
104/// # use yew::prelude::*;
105/// #
106/// use yew_hooks::prelude::*;
107///
108/// #[function_component(UseSet)]
109/// fn set() -> Html {
110///     let set = use_set(HashSet::from(["Mercury", "Venus", "Earth", "Mars"]));
111///
112///     let onset = {
113///         let set = set.clone();
114///         Callback::from(move |_| set.set(HashSet::from(["Moon", "Earth"])))
115///     };
116///     let oninsert = {
117///         let set = set.clone();
118///         Callback::from(move |_| {
119///             let _ = set.insert("Jupiter");
120///         })
121///     };
122///     let onreplace = {
123///         let set = set.clone();
124///         Callback::from(move |_| {
125///             let _ = set.replace("Earth");
126///         })
127///     };
128///     let onremove = {
129///         let set = set.clone();
130///         Callback::from(move |_| {
131///             let _ = set.remove(&"Moon");
132///         })
133///     };
134///     let onretain = {
135///         let set = set.clone();
136///         Callback::from(move |_| set.retain(|v| v.contains('a')))
137///     };
138///     let onclear = {
139///         let set = set.clone();
140///         Callback::from(move |_| set.clear())
141///     };
142///
143///     html! {
144///         <div>
145///             <button onclick={onset}>{ "Set" }</button>
146///             <button onclick={oninsert}>{ "Insert" }</button>
147///             <button onclick={onreplace}>{ "Replace" }</button>
148///             <button onclick={onremove}>{ "Remove" }</button>
149///             <button onclick={onretain}>{ "Retain" }</button>
150///             <button onclick={onclear}>{ "Clear all" }</button>
151///             <p>
152///                 <b>{ "Current value: " }</b>
153///             </p>
154///             {
155///                 for set.current().iter().map(|v| {
156///                     html! {
157///                         <p><b>{ v }</b></p>
158///                     }
159///                 })
160///             }
161///         </div>
162///     }
163/// }
164/// ```
165#[hook]
166pub fn use_set<T>(initial_value: HashSet<T>) -> UseSetHandle<T>
167where
168    T: 'static,
169{
170    let inner = use_mut_ref(|| initial_value);
171    let update = use_update();
172
173    UseSetHandle { inner, update }
174}