dioxus_signals/write.rs
1use std::{
2 collections::{HashMap, HashSet},
3 ops::{Deref, DerefMut, IndexMut},
4};
5
6use generational_box::{AnyStorage, UnsyncStorage};
7
8use crate::{ext_methods, read::Readable, read::ReadableExt, MappedMutSignal, WriteSignal};
9
10/// A reference to a value that can be written to.
11#[allow(type_alias_bounds)]
12pub type WritableRef<'a, T: Writable, O = <T as Readable>::Target> =
13 WriteLock<'a, O, <T as Readable>::Storage, <T as Writable>::WriteMetadata>;
14
15/// A trait for states that can be written to like [`crate::Signal`]. You may choose to accept this trait as a parameter instead of the concrete type to allow for more flexibility in your API.
16///
17/// # Example
18/// ```rust
19/// # use dioxus::prelude::*;
20/// enum MyEnum {
21/// String(String),
22/// Number(i32),
23/// }
24///
25/// fn MyComponent(mut count: Signal<MyEnum>) -> Element {
26/// rsx! {
27/// button {
28/// onclick: move |_| {
29/// // You can use any methods from the Writable trait on Signals
30/// match &mut *count.write() {
31/// MyEnum::String(s) => s.push('a'),
32/// MyEnum::Number(n) => *n += 1,
33/// }
34/// },
35/// "Add value"
36/// }
37/// }
38/// }
39/// ```
40pub trait Writable: Readable {
41 /// Additional data associated with the write reference.
42 type WriteMetadata;
43
44 /// Try to get a mutable reference to the value without checking the lifetime. This will update any subscribers.
45 ///
46 /// NOTE: This method is completely safe because borrow checking is done at runtime.
47 fn try_write_unchecked(
48 &self,
49 ) -> Result<WritableRef<'static, Self>, generational_box::BorrowMutError>
50 where
51 Self::Target: 'static;
52}
53
54/// A mutable reference to a writable value. This reference acts similarly to [`std::cell::RefMut`], but it has extra debug information
55/// and integrates with the reactive system to automatically update dependents.
56///
57/// [`WriteLock`] implements [`DerefMut`] which means you can call methods on the inner value just like you would on a mutable reference
58/// to the inner value. If you need to get the inner reference directly, you can call [`WriteLock::deref_mut`].
59///
60/// # Example
61/// ```rust
62/// # use dioxus::prelude::*;
63/// fn app() -> Element {
64/// let mut value = use_signal(|| String::from("hello"));
65///
66/// rsx! {
67/// button {
68/// onclick: move |_| {
69/// let mut mutable_reference = value.write();
70///
71/// // You call methods like `push_str` on the reference just like you would with the inner String
72/// mutable_reference.push_str("world");
73/// },
74/// "Click to add world to the string"
75/// }
76/// div { "{value}" }
77/// }
78/// }
79/// ```
80///
81/// ## Matching on WriteLock
82///
83/// You need to get the inner mutable reference with [`WriteLock::deref_mut`] before you match the inner value. If you try to match
84/// without calling [`WriteLock::deref_mut`], you will get an error like this:
85///
86/// ```compile_fail
87/// # use dioxus::prelude::*;
88/// #[derive(Debug)]
89/// enum Colors {
90/// Red(u32),
91/// Green
92/// }
93/// fn app() -> Element {
94/// let mut value = use_signal(|| Colors::Red(0));
95///
96/// rsx! {
97/// button {
98/// onclick: move |_| {
99/// let mut mutable_reference = value.write();
100///
101/// match mutable_reference {
102/// // Since we are matching on the `Write` type instead of &mut Colors, we can't match on the enum directly
103/// Colors::Red(brightness) => *brightness += 1,
104/// Colors::Green => {}
105/// }
106/// },
107/// "Click to add brightness to the red color"
108/// }
109/// div { "{value:?}" }
110/// }
111/// }
112/// ```
113///
114/// ```text
115/// error[E0308]: mismatched types
116/// --> src/main.rs:18:21
117/// |
118/// 16 | match mutable_reference {
119/// | ----------------- this expression has type `dioxus::prelude::Write<'_, Colors>`
120/// 17 | // Since we are matching on the `Write` t...
121/// 18 | Colors::Red(brightness) => *brightness += 1,
122/// | ^^^^^^^^^^^^^^^^^^^^^^^ expected `Write<'_, Colors>`, found `Colors`
123/// |
124/// = note: expected struct `dioxus::prelude::Write<'_, Colors, >`
125/// found enum `Colors`
126/// ```
127///
128/// Instead, you need to call deref mut on the reference to get the inner value **before** you match on it:
129///
130/// ```rust
131/// use std::ops::DerefMut;
132/// # use dioxus::prelude::*;
133/// #[derive(Debug)]
134/// enum Colors {
135/// Red(u32),
136/// Green
137/// }
138/// fn app() -> Element {
139/// let mut value = use_signal(|| Colors::Red(0));
140///
141/// rsx! {
142/// button {
143/// onclick: move |_| {
144/// let mut mutable_reference = value.write();
145///
146/// // DerefMut converts the `Write` into a `&mut Colors`
147/// match mutable_reference.deref_mut() {
148/// // Now we can match on the inner value
149/// Colors::Red(brightness) => *brightness += 1,
150/// Colors::Green => {}
151/// }
152/// },
153/// "Click to add brightness to the red color"
154/// }
155/// div { "{value:?}" }
156/// }
157/// }
158/// ```
159///
160/// ## Generics
161/// - T is the current type of the write
162/// - S is the storage type of the signal. This type determines if the signal is local to the current thread, or it can be shared across threads.
163/// - D is the additional data associated with the write reference. This is used by signals to track when the write is dropped
164pub struct WriteLock<'a, T: ?Sized + 'a, S: AnyStorage = UnsyncStorage, D = ()> {
165 write: S::Mut<'a, T>,
166 data: D,
167}
168
169impl<'a, T: ?Sized, S: AnyStorage> WriteLock<'a, T, S> {
170 /// Create a new write reference
171 pub fn new(write: S::Mut<'a, T>) -> Self {
172 Self { write, data: () }
173 }
174}
175
176impl<'a, T: ?Sized, S: AnyStorage, D> WriteLock<'a, T, S, D> {
177 /// Create a new write reference with additional data.
178 pub fn new_with_metadata(write: S::Mut<'a, T>, data: D) -> Self {
179 Self { write, data }
180 }
181
182 /// Get the inner value of the write reference.
183 pub fn into_inner(self) -> S::Mut<'a, T> {
184 self.write
185 }
186
187 /// Get the additional data associated with the write reference.
188 pub fn data(&self) -> &D {
189 &self.data
190 }
191
192 /// Split into the inner value and the additional data.
193 pub fn into_parts(self) -> (S::Mut<'a, T>, D) {
194 (self.write, self.data)
195 }
196
197 /// Map the metadata of the write reference to a new type.
198 pub fn map_metadata<O>(self, f: impl FnOnce(D) -> O) -> WriteLock<'a, T, S, O> {
199 WriteLock {
200 write: self.write,
201 data: f(self.data),
202 }
203 }
204
205 /// Map the mutable reference to the signal's value to a new type.
206 pub fn map<O: ?Sized>(
207 myself: Self,
208 f: impl FnOnce(&mut T) -> &mut O,
209 ) -> WriteLock<'a, O, S, D> {
210 let Self { write, data, .. } = myself;
211 WriteLock {
212 write: S::map_mut(write, f),
213 data,
214 }
215 }
216
217 /// Try to map the mutable reference to the signal's value to a new type
218 pub fn filter_map<O: ?Sized>(
219 myself: Self,
220 f: impl FnOnce(&mut T) -> Option<&mut O>,
221 ) -> Option<WriteLock<'a, O, S, D>> {
222 let Self { write, data, .. } = myself;
223 let write = S::try_map_mut(write, f);
224 write.map(|write| WriteLock { write, data })
225 }
226
227 /// Downcast the lifetime of the mutable reference to the signal's value.
228 ///
229 /// This function enforces the variance of the lifetime parameter `'a` in Mut. Rust will typically infer this cast with a concrete type, but it cannot with a generic type.
230 pub fn downcast_lifetime<'b>(mut_: Self) -> WriteLock<'b, T, S, D>
231 where
232 'a: 'b,
233 {
234 WriteLock {
235 write: S::downcast_lifetime_mut(mut_.write),
236 data: mut_.data,
237 }
238 }
239}
240
241impl<T, S, D> Deref for WriteLock<'_, T, S, D>
242where
243 S: AnyStorage,
244 T: ?Sized,
245{
246 type Target = T;
247
248 fn deref(&self) -> &Self::Target {
249 &self.write
250 }
251}
252
253impl<T, S, D> DerefMut for WriteLock<'_, T, S, D>
254where
255 S: AnyStorage,
256 T: ?Sized,
257{
258 fn deref_mut(&mut self) -> &mut Self::Target {
259 &mut self.write
260 }
261}
262
263/// An extension trait for [`Writable`] that provides some convenience methods.
264pub trait WritableExt: Writable {
265 /// Get a mutable reference to the value. If the value has been dropped, this will panic.
266 #[track_caller]
267 fn write(&mut self) -> WritableRef<'_, Self>
268 where
269 Self::Target: 'static,
270 {
271 self.try_write().unwrap()
272 }
273
274 /// Try to get a mutable reference to the value.
275 #[track_caller]
276 fn try_write(&mut self) -> Result<WritableRef<'_, Self>, generational_box::BorrowMutError>
277 where
278 Self::Target: 'static,
279 {
280 self.try_write_unchecked().map(WriteLock::downcast_lifetime)
281 }
282
283 /// Get a mutable reference to the value without checking the lifetime. This will update any subscribers.
284 ///
285 /// NOTE: This method is completely safe because borrow checking is done at runtime.
286 #[track_caller]
287 fn write_unchecked(&self) -> WritableRef<'static, Self>
288 where
289 Self::Target: 'static,
290 {
291 self.try_write_unchecked().unwrap()
292 }
293
294 /// Map the references and mutable references of the writable value to a new type. This lets you provide a view
295 /// into the writable value without creating a new signal or cloning the value.
296 ///
297 /// Anything that subscribes to the writable value will be rerun whenever the original value changes or you write to this
298 /// scoped value, even if the view does not change. If you want to memorize the view, you can use a [`crate::Memo`] instead.
299 /// For fine grained scoped updates, use stores instead
300 ///
301 /// # Example
302 /// ```rust
303 /// # use dioxus::prelude::*;
304 /// fn List(list: Signal<Vec<i32>>) -> Element {
305 /// rsx! {
306 /// for index in 0..list.len() {
307 /// // We can use the `map` method to provide a view into the single item in the list that the child component will render
308 /// Item { item: list.map_mut(move |v| &v[index], move |v| &mut v[index]) }
309 /// }
310 /// }
311 /// }
312 ///
313 /// // The child component doesn't need to know that the mapped value is coming from a list
314 /// #[component]
315 /// fn Item(item: WriteSignal<i32>) -> Element {
316 /// rsx! {
317 /// button {
318 /// onclick: move |_| *item.write() += 1,
319 /// "{item}"
320 /// }
321 /// }
322 /// }
323 /// ```
324 fn map_mut<O, F, FMut>(self, f: F, f_mut: FMut) -> MappedMutSignal<O, Self, F, FMut>
325 where
326 Self: Sized,
327 O: ?Sized,
328 F: Fn(&Self::Target) -> &O,
329 FMut: Fn(&mut Self::Target) -> &mut O,
330 {
331 MappedMutSignal::new(self, f, f_mut)
332 }
333
334 /// Run a function with a mutable reference to the value. If the value has been dropped, this will panic.
335 #[track_caller]
336 fn with_mut<O>(&mut self, f: impl FnOnce(&mut Self::Target) -> O) -> O
337 where
338 Self::Target: 'static,
339 {
340 f(&mut *self.write())
341 }
342
343 /// Set the value of the signal. This will trigger an update on all subscribers.
344 #[track_caller]
345 fn set(&mut self, value: Self::Target)
346 where
347 Self::Target: Sized + 'static,
348 {
349 *self.write() = value;
350 }
351
352 /// Invert the boolean value of the signal. This will trigger an update on all subscribers.
353 #[track_caller]
354 fn toggle(&mut self)
355 where
356 Self::Target: std::ops::Not<Output = Self::Target> + Clone + 'static,
357 {
358 let inverted = !(*self.peek()).clone();
359 self.set(inverted);
360 }
361
362 /// Index into the inner value and return a reference to the result.
363 #[track_caller]
364 fn index_mut<I>(
365 &mut self,
366 index: I,
367 ) -> WritableRef<'_, Self, <Self::Target as std::ops::Index<I>>::Output>
368 where
369 Self::Target: std::ops::IndexMut<I> + 'static,
370 {
371 WriteLock::map(self.write(), |v| v.index_mut(index))
372 }
373
374 /// Takes the value out of the Signal, leaving a Default in its place.
375 #[track_caller]
376 fn take(&mut self) -> Self::Target
377 where
378 Self::Target: Default + 'static,
379 {
380 self.with_mut(std::mem::take)
381 }
382
383 /// Replace the value in the Signal, returning the old value.
384 #[track_caller]
385 fn replace(&mut self, value: Self::Target) -> Self::Target
386 where
387 Self::Target: Sized + 'static,
388 {
389 self.with_mut(|v| std::mem::replace(v, value))
390 }
391}
392
393impl<W: Writable + ?Sized> WritableExt for W {}
394
395/// An extension trait for [`Writable`] values that can be boxed into a trait object.
396pub trait WritableBoxedExt: Writable<Storage = UnsyncStorage> {
397 /// Box the writable value into a trait object. This is useful for passing around writable values without knowing their concrete type.
398 fn boxed_mut(self) -> WriteSignal<Self::Target>
399 where
400 Self: Sized + 'static,
401 {
402 WriteSignal::new(self)
403 }
404}
405
406impl<T: Writable<Storage = UnsyncStorage> + 'static> WritableBoxedExt for T {
407 fn boxed_mut(self) -> WriteSignal<Self::Target> {
408 WriteSignal::new(self)
409 }
410}
411
412/// An extension trait for [`Writable<Option<T>>`]` that provides some convenience methods.
413pub trait WritableOptionExt<T>: Writable<Target = Option<T>> {
414 /// Gets the value out of the Option, or inserts the given value if the Option is empty.
415 #[track_caller]
416 fn get_or_insert(&mut self, default: T) -> WritableRef<'_, Self, T>
417 where
418 T: 'static,
419 {
420 self.get_or_insert_with(|| default)
421 }
422
423 /// Gets the value out of the Option, or inserts the value returned by the given function if the Option is empty.
424 #[track_caller]
425 fn get_or_insert_with(&mut self, default: impl FnOnce() -> T) -> WritableRef<'_, Self, T>
426 where
427 T: 'static,
428 {
429 let is_none = self.read().is_none();
430 if is_none {
431 self.with_mut(|v| *v = Some(default()));
432 WriteLock::map(self.write(), |v| v.as_mut().unwrap())
433 } else {
434 WriteLock::map(self.write(), |v| v.as_mut().unwrap())
435 }
436 }
437
438 /// Attempts to write the inner value of the Option.
439 #[track_caller]
440 fn as_mut(&mut self) -> Option<WritableRef<'_, Self, T>>
441 where
442 T: 'static,
443 {
444 WriteLock::filter_map(self.write(), |v: &mut Option<T>| v.as_mut())
445 }
446}
447
448impl<T, W> WritableOptionExt<T> for W where W: Writable<Target = Option<T>> {}
449
450/// An extension trait for [`Writable<Result<T, E>>`] that provides some convenience methods.
451pub trait WritableResultExt<T, E>: Writable<Target = Result<T, E>> {
452 /// Unwraps the inner value mutably, panicking if the Result is an error.
453 #[track_caller]
454 fn unwrap_mut(&mut self) -> WritableRef<'_, Self, T>
455 where
456 T: 'static,
457 E: 'static,
458 {
459 WriteLock::filter_map(self.write(), |v| v.as_mut().ok())
460 .expect("Tried to unwrap a Result that was an error")
461 }
462
463 /// Attempts to mutably access the inner value of the Result.
464 #[track_caller]
465 fn as_mut(&mut self) -> Result<WritableRef<'_, Self, T>, WritableRef<'_, Self, E>>
466 where
467 T: 'static,
468 E: 'static,
469 {
470 let write = self.write();
471 match write.as_ref() {
472 Ok(_) => Ok(WriteLock::map(write, |v| {
473 v.as_mut()
474 .ok()
475 .expect("Result variant changed between read and write")
476 })),
477 Err(_) => Err(WriteLock::map(write, |v| {
478 v.as_mut()
479 .err()
480 .expect("Result variant changed between read and write")
481 })),
482 }
483 }
484}
485
486impl<T, E, W> WritableResultExt<T, E> for W where W: Writable<Target = Result<T, E>> {}
487
488/// An extension trait for [`Writable<Vec<T>>`] that provides some convenience methods.
489pub trait WritableVecExt<T>: Writable<Target = Vec<T>> {
490 /// Pushes a new value to the end of the vector.
491 #[track_caller]
492 fn push(&mut self, value: T)
493 where
494 T: 'static,
495 {
496 self.with_mut(|v| v.push(value))
497 }
498
499 /// Pops the last value from the vector.
500 #[track_caller]
501 fn pop(&mut self) -> Option<T>
502 where
503 T: 'static,
504 {
505 self.with_mut(|v| v.pop())
506 }
507
508 /// Inserts a new value at the given index.
509 #[track_caller]
510 fn insert(&mut self, index: usize, value: T)
511 where
512 T: 'static,
513 {
514 self.with_mut(|v| v.insert(index, value))
515 }
516
517 /// Removes the value at the given index.
518 #[track_caller]
519 fn remove(&mut self, index: usize) -> T
520 where
521 T: 'static,
522 {
523 self.with_mut(|v| v.remove(index))
524 }
525
526 /// Clears the vector, removing all values.
527 #[track_caller]
528 fn clear(&mut self)
529 where
530 T: 'static,
531 {
532 self.with_mut(|v| v.clear())
533 }
534
535 /// Extends the vector with the given iterator.
536 #[track_caller]
537 fn extend(&mut self, iter: impl IntoIterator<Item = T>)
538 where
539 T: 'static,
540 {
541 self.with_mut(|v| v.extend(iter))
542 }
543
544 /// Truncates the vector to the given length.
545 #[track_caller]
546 fn truncate(&mut self, len: usize)
547 where
548 T: 'static,
549 {
550 self.with_mut(|v| v.truncate(len))
551 }
552
553 /// Swaps two values in the vector.
554 #[track_caller]
555 fn swap_remove(&mut self, index: usize) -> T
556 where
557 T: 'static,
558 {
559 self.with_mut(|v| v.swap_remove(index))
560 }
561
562 /// Retains only the values that match the given predicate.
563 #[track_caller]
564 fn retain(&mut self, f: impl FnMut(&T) -> bool)
565 where
566 T: 'static,
567 {
568 self.with_mut(|v| v.retain(f))
569 }
570
571 /// Splits the vector into two at the given index.
572 #[track_caller]
573 fn split_off(&mut self, at: usize) -> Vec<T>
574 where
575 T: 'static,
576 {
577 self.with_mut(|v| v.split_off(at))
578 }
579
580 /// Try to mutably get an element from the vector.
581 #[track_caller]
582 fn get_mut(&mut self, index: usize) -> Option<WritableRef<'_, Self, T>>
583 where
584 T: 'static,
585 {
586 WriteLock::filter_map(self.write(), |v: &mut Vec<T>| v.get_mut(index))
587 }
588
589 /// Gets an iterator over the values of the vector.
590 #[track_caller]
591 fn iter_mut(&mut self) -> WritableValueIterator<'_, Self>
592 where
593 Self: Sized + Clone,
594 {
595 WritableValueIterator {
596 index: 0,
597 value: self,
598 }
599 }
600}
601
602/// An iterator over the values of a [`Writable<Vec<T>>`].
603pub struct WritableValueIterator<'a, R> {
604 index: usize,
605 value: &'a mut R,
606}
607
608impl<'a, T: 'static, R: Writable<Target = Vec<T>>> Iterator for WritableValueIterator<'a, R> {
609 type Item = WritableRef<'a, R, T>;
610
611 fn next(&mut self) -> Option<Self::Item> {
612 let index = self.index;
613 self.index += 1;
614 WriteLock::filter_map(
615 self.value.try_write_unchecked().unwrap(),
616 |v: &mut Vec<T>| v.get_mut(index),
617 )
618 .map(WriteLock::downcast_lifetime)
619 }
620}
621
622impl<W, T> WritableVecExt<T> for W where W: Writable<Target = Vec<T>> {}
623
624/// An extension trait for [`Writable<String>`] that provides some convenience methods.
625pub trait WritableStringExt: Writable<Target = String> {
626 ext_methods! {
627 /// Pushes a character to the end of the string.
628 fn push_str(&mut self, s: &str) = String::push_str;
629
630 /// Pushes a character to the end of the string.
631 fn push(&mut self, c: char) = String::push;
632
633 /// Pops a character from the end of the string.
634 fn pop(&mut self) -> Option<char> = String::pop;
635
636 /// Inserts a string at the given index.
637 fn insert_str(&mut self, idx: usize, s: &str) = String::insert_str;
638
639 /// Inserts a character at the given index.
640 fn insert(&mut self, idx: usize, c: char) = String::insert;
641
642 /// Remove a character at the given index
643 fn remove(&mut self, idx: usize) -> char = String::remove;
644
645 /// Replace a range of the string with the given string.
646 fn replace_range(&mut self, range: impl std::ops::RangeBounds<usize>, replace_with: &str) = String::replace_range;
647
648 /// Clears the string, removing all characters.
649 fn clear(&mut self) = String::clear;
650
651 /// Extends the string with the given iterator of characters.
652 fn extend(&mut self, iter: impl IntoIterator<Item = char>) = String::extend;
653
654 /// Truncates the string to the given length.
655 fn truncate(&mut self, len: usize) = String::truncate;
656
657 /// Splits the string off at the given index, returning the tail as a new string.
658 fn split_off(&mut self, at: usize) -> String = String::split_off;
659 }
660}
661
662impl<W> WritableStringExt for W where W: Writable<Target = String> {}
663
664/// An extension trait for [`Writable<HashMap<K, V, H>>`] that provides some convenience methods.
665pub trait WritableHashMapExt<K: 'static, V: 'static, H: 'static>:
666 Writable<Target = HashMap<K, V, H>>
667{
668 ext_methods! {
669 /// Clears the map, removing all key-value pairs.
670 fn clear(&mut self) = HashMap::clear;
671
672 /// Retains only the key-value pairs that match the given predicate.
673 fn retain(&mut self, f: impl FnMut(&K, &mut V) -> bool) = HashMap::retain;
674 }
675
676 /// Inserts a key-value pair into the map. If the key was already present, the old value is returned.
677 #[track_caller]
678 fn insert(&mut self, k: K, v: V) -> Option<V>
679 where
680 K: std::cmp::Eq + std::hash::Hash,
681 H: std::hash::BuildHasher,
682 {
683 self.with_mut(|map: &mut HashMap<K, V, H>| map.insert(k, v))
684 }
685
686 /// Extends the map with the key-value pairs from the given iterator.
687 #[track_caller]
688 fn extend(&mut self, iter: impl IntoIterator<Item = (K, V)>)
689 where
690 K: std::cmp::Eq + std::hash::Hash,
691 H: std::hash::BuildHasher,
692 {
693 self.with_mut(|map: &mut HashMap<K, V, H>| map.extend(iter))
694 }
695
696 /// Removes a key from the map, returning the value at the key if the key was previously in the map.
697 #[track_caller]
698 fn remove(&mut self, k: &K) -> Option<V>
699 where
700 K: std::cmp::Eq + std::hash::Hash,
701 H: std::hash::BuildHasher,
702 {
703 self.with_mut(|map: &mut HashMap<K, V, H>| map.remove(k))
704 }
705
706 /// Get a mutable reference to the value at the given key.
707 #[track_caller]
708 fn get_mut(&mut self, k: &K) -> Option<WritableRef<'_, Self, V>>
709 where
710 K: std::cmp::Eq + std::hash::Hash,
711 H: std::hash::BuildHasher,
712 {
713 WriteLock::filter_map(self.write(), |map: &mut HashMap<K, V, H>| map.get_mut(k))
714 }
715}
716
717impl<K: 'static, V: 'static, H: 'static, R> WritableHashMapExt<K, V, H> for R where
718 R: Writable<Target = HashMap<K, V, H>>
719{
720}
721
722/// An extension trait for [`Writable<HashSet<V, H>>`] that provides some convenience methods.
723pub trait WritableHashSetExt<V: 'static, H: 'static>: Writable<Target = HashSet<V, H>> {
724 ext_methods! {
725 /// Clear the hash set.
726 fn clear(&mut self) = HashSet::clear;
727
728 /// Retain only the elements specified by the predicate.
729 fn retain(&mut self, f: impl FnMut(&V) -> bool) = HashSet::retain;
730 }
731
732 /// Inserts a value into the set. Returns true if the value was not already present.
733 #[track_caller]
734 fn insert(&mut self, k: V) -> bool
735 where
736 V: std::cmp::Eq + std::hash::Hash,
737 H: std::hash::BuildHasher,
738 {
739 self.with_mut(|set| set.insert(k))
740 }
741
742 /// Extends the set with the values from the given iterator.
743 #[track_caller]
744 fn extend(&mut self, iter: impl IntoIterator<Item = V>)
745 where
746 V: std::cmp::Eq + std::hash::Hash,
747 H: std::hash::BuildHasher,
748 {
749 self.with_mut(|set| set.extend(iter))
750 }
751
752 /// Removes a value from the set. Returns true if the value was present.
753 #[track_caller]
754 fn remove(&mut self, k: &V) -> bool
755 where
756 V: std::cmp::Eq + std::hash::Hash,
757 H: std::hash::BuildHasher,
758 {
759 self.with_mut(|set| set.remove(k))
760 }
761}
762
763impl<V: 'static, H: 'static, R> WritableHashSetExt<V, H> for R where
764 R: Writable<Target = HashSet<V, H>>
765{
766}