1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
use std::cell::{Ref, RefCell};
use std::collections::VecDeque;
use std::hash::Hash;
use std::rc::Rc;

use yew::prelude::*;

use super::use_update;

/// State handle for the [`use_queue`] hook.
pub struct UseQueueHandle<T> {
    inner: Rc<RefCell<VecDeque<T>>>,
    update: Rc<dyn Fn()>,
}

impl<T> UseQueueHandle<T> {
    /// Get immutable ref to the queue.
    ///
    /// # Panics
    ///
    /// Panics if the value is currently mutably borrowed
    pub fn current(&self) -> Ref<VecDeque<T>> {
        self.inner.borrow()
    }

    /// Set the queue.
    pub fn set(&self, queue: VecDeque<T>) {
        *self.inner.borrow_mut() = queue;
        (self.update)();
    }

    /// Appends an element to the back of the queue.
    pub fn push_back(&self, value: T)
    where
        T: Eq + Hash,
    {
        self.inner.borrow_mut().push_back(value);
        (self.update)();
    }

    /// Removes the first element and returns it, or None if the queue is empty.
    pub fn pop_front(&self) -> Option<T>
    where
        T: Eq + Hash,
    {
        let v = self.inner.borrow_mut().pop_front();
        (self.update)();
        v
    }

    /// Retains only the elements specified by the predicate.
    pub fn retain<F>(&self, f: F)
    where
        T: Eq + Hash,
        F: FnMut(&T) -> bool,
    {
        self.inner.borrow_mut().retain(f);
        (self.update)();
    }

    /// Clears the queue, removing all values.
    pub fn clear(&self) {
        self.inner.borrow_mut().clear();
        (self.update)();
    }
}

impl<T> Clone for UseQueueHandle<T> {
    fn clone(&self) -> Self {
        Self {
            inner: self.inner.clone(),
            update: self.update.clone(),
        }
    }
}

impl<T> PartialEq for UseQueueHandle<T>
where
    T: Eq + Hash,
{
    fn eq(&self, other: &Self) -> bool {
        *self.inner == *other.inner
    }
}

/// A hook that tracks a queue and provides methods to modify it.
///
/// # Example
///
/// ```rust
/// # use std::collections::VecDeque;
/// # use yew::prelude::*;
/// #
/// use yew_hooks::use_queue;
///
/// #[function_component(UseQueue)]
/// fn queue() -> Html {
///     let queue = use_queue(VecDeque::from(["Mercury", "Venus", "Earth", "Mars"]));
///
///     let onset = {
///         let queue = queue.clone();
///         Callback::from(move |_| queue.set(VecDeque::from(["Moon", "Earth"])))
///     };
///     let onpush_back = {
///         let queue = queue.clone();
///         Callback::from(move |_| {
///             queue.push_back("Jupiter");
///         })
///     };
///     let onpop_front = {
///         let queue = queue.clone();
///         Callback::from(move |_| {
///             let _ = queue.pop_front();
///         })
///     };
///     let onretain = {
///         let queue = queue.clone();
///         Callback::from(move |_| queue.retain(|v| v.contains('a')))
///     };
///     let onclear = {
///         let queue = queue.clone();
///         Callback::from(move |_| queue.clear())
///     };
///
///     html! {
///         <div>
///             <button onclick={onset}>{ "Set" }</button>
///             <button onclick={onpush_back}>{ "Push back" }</button>
///             <button onclick={onpop_front}>{ "Pop front" }</button>
///             <button onclick={onretain}>{ "Retain" }</button>
///             <button onclick={onclear}>{ "Clear all" }</button>
///             <p>
///                 <b>{ "Current value: " }</b>
///             </p>
///             {
///                 for queue.current().iter().map(|v| {
///                     html! {
///                         <p><b>{ v }</b></p>
///                     }
///                 })
///             }
///         </div>
///     }
/// }
/// ```
pub fn use_queue<T>(initial_value: VecDeque<T>) -> UseQueueHandle<T>
where
    T: 'static,
{
    let inner = use_mut_ref(|| initial_value);
    let update = use_update();

    UseQueueHandle { inner, update }
}