libp2p_kad/kbucket/
entry.rs

1// Copyright 2019 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21//! The `Entry` API for querying and modifying the entries of a `KBucketsTable`
22//! representing the nodes participating in the Kademlia DHT.
23
24pub(crate) use super::bucket::{AppliedPending, InsertResult, Node, K_VALUE};
25pub use super::key::*;
26use super::*;
27
28/// An immutable by-reference view of a bucket entry.
29pub struct EntryRefView<'a, TPeerId, TVal> {
30    /// The node represented by the entry.
31    pub node: NodeRefView<'a, TPeerId, TVal>,
32    /// The status of the node identified by the key.
33    pub status: NodeStatus,
34}
35
36/// An immutable by-reference view of a `Node`.
37pub struct NodeRefView<'a, TKey, TVal> {
38    pub key: &'a TKey,
39    pub value: &'a TVal,
40}
41
42impl<TKey, TVal> EntryRefView<'_, TKey, TVal> {
43    pub fn to_owned(&self) -> EntryView<TKey, TVal>
44    where
45        TKey: Clone,
46        TVal: Clone,
47    {
48        EntryView {
49            node: Node {
50                key: self.node.key.clone(),
51                value: self.node.value.clone(),
52            },
53            status: self.status,
54        }
55    }
56}
57
58/// A cloned, immutable view of an entry that is either present in a bucket
59/// or pending insertion.
60#[derive(Clone, Debug)]
61pub struct EntryView<TKey, TVal> {
62    /// The node represented by the entry.
63    pub node: Node<TKey, TVal>,
64    /// The status of the node.
65    pub status: NodeStatus,
66}
67
68impl<TKey: AsRef<KeyBytes>, TVal> AsRef<KeyBytes> for EntryView<TKey, TVal> {
69    fn as_ref(&self) -> &KeyBytes {
70        self.node.key.as_ref()
71    }
72}
73
74/// A reference into a single entry of a `KBucketsTable`.
75#[derive(Debug)]
76pub(crate) enum Entry<'a, TPeerId, TVal> {
77    /// The entry is present in a bucket.
78    Present(PresentEntry<'a, TPeerId, TVal>, NodeStatus),
79    /// The entry is pending insertion in a bucket.
80    Pending(PendingEntry<'a, TPeerId, TVal>, NodeStatus),
81    /// The entry is absent and may be inserted.
82    Absent(AbsentEntry<'a, TPeerId, TVal>),
83}
84
85/// The internal representation of the different states of an `Entry`,
86/// referencing the associated key and bucket.
87#[derive(Debug)]
88struct EntryRef<'a, TKey, TVal> {
89    bucket: &'a mut KBucket<TKey, TVal>,
90    key: &'a TKey,
91}
92
93impl<'a, TKey, TVal> Entry<'a, TKey, TVal>
94where
95    TKey: Clone + AsRef<KeyBytes>,
96    TVal: Clone,
97{
98    /// Creates a new `Entry` for a `Key`, encapsulating access to a bucket.
99    pub(super) fn new(bucket: &'a mut KBucket<TKey, TVal>, key: &'a TKey) -> Self {
100        if let Some(pos) = bucket.position(key) {
101            let status = bucket.status(pos);
102            Entry::Present(PresentEntry::new(bucket, key), status)
103        } else if let Some(pending) = bucket.as_pending(key) {
104            let status = pending.status();
105            Entry::Pending(PendingEntry::new(bucket, key), status)
106        } else {
107            Entry::Absent(AbsentEntry::new(bucket, key))
108        }
109    }
110
111    /// Creates an immutable by-reference view of the entry.
112    ///
113    /// Returns `None` if the entry is neither present in a bucket nor
114    /// pending insertion into a bucket.
115    pub(crate) fn view(&'a mut self) -> Option<EntryRefView<'a, TKey, TVal>> {
116        match self {
117            Entry::Present(entry, status) => Some(EntryRefView {
118                node: NodeRefView {
119                    key: entry.0.key,
120                    value: entry.value(),
121                },
122                status: *status,
123            }),
124            Entry::Pending(entry, status) => Some(EntryRefView {
125                node: NodeRefView {
126                    key: entry.0.key,
127                    value: entry.value(),
128                },
129                status: *status,
130            }),
131            _ => None,
132        }
133    }
134
135    /// Returns the value associated with the entry.
136    ///
137    /// Returns `None` if the entry is absent from any bucket or refers to the
138    /// local node.
139    pub(crate) fn value(&mut self) -> Option<&mut TVal> {
140        match self {
141            Entry::Present(entry, _) => Some(entry.value()),
142            Entry::Pending(entry, _) => Some(entry.value()),
143            Entry::Absent(_) => None,
144        }
145    }
146}
147
148/// An entry present in a bucket.
149#[derive(Debug)]
150pub(crate) struct PresentEntry<'a, TKey, TVal>(EntryRef<'a, TKey, TVal>);
151impl<'a, TKey, TVal> PresentEntry<'a, TKey, TVal>
152where
153    TKey: Clone + AsRef<KeyBytes>,
154    TVal: Clone,
155{
156    fn new(bucket: &'a mut KBucket<TKey, TVal>, key: &'a TKey) -> Self {
157        PresentEntry(EntryRef { bucket, key })
158    }
159
160    /// Returns the value associated with the key.
161    pub(crate) fn value(&mut self) -> &mut TVal {
162        &mut self
163            .0
164            .bucket
165            .get_mut(self.0.key)
166            .expect("We can only build a PresentEntry if the entry is in the bucket; QED")
167            .value
168    }
169
170    /// Sets the status of the entry to the provided [`NodeStatus`].
171    pub(crate) fn update(&mut self, status: NodeStatus) {
172        self.0.bucket.update(self.0.key, status);
173    }
174
175    /// Removes the entry from the bucket.
176    pub(crate) fn remove(self) -> EntryView<TKey, TVal> {
177        let (node, status, _pos) = self
178            .0
179            .bucket
180            .remove(self.0.key)
181            .expect("We can only build a PresentEntry if the entry is in the bucket; QED");
182        EntryView { node, status }
183    }
184}
185
186/// An entry waiting for a slot to be available in a bucket.
187#[derive(Debug)]
188pub(crate) struct PendingEntry<'a, TKey, TVal>(EntryRef<'a, TKey, TVal>);
189impl<'a, TKey, TVal> PendingEntry<'a, TKey, TVal>
190where
191    TKey: Clone + AsRef<KeyBytes>,
192    TVal: Clone,
193{
194    fn new(bucket: &'a mut KBucket<TKey, TVal>, key: &'a TKey) -> Self {
195        PendingEntry(EntryRef { bucket, key })
196    }
197
198    /// Returns the value associated with the key.
199    pub(crate) fn value(&mut self) -> &mut TVal {
200        self.0
201            .bucket
202            .pending_mut()
203            .expect("We can only build a ConnectedPendingEntry if the entry is pending; QED")
204            .value_mut()
205    }
206
207    /// Updates the status of the pending entry.
208    pub(crate) fn update(self, status: NodeStatus) -> PendingEntry<'a, TKey, TVal> {
209        self.0.bucket.update_pending(status);
210        PendingEntry::new(self.0.bucket, self.0.key)
211    }
212
213    /// Removes the pending entry from the bucket.
214    pub(crate) fn remove(self) -> EntryView<TKey, TVal> {
215        let pending = self.0.bucket.remove_pending().expect(
216            "We can only build a PendingEntry if the entry is pending insertion
217                    into the bucket; QED",
218        );
219        let status = pending.status();
220        let node = pending.into_node();
221        EntryView { node, status }
222    }
223}
224
225/// An entry that is not present in any bucket.
226#[derive(Debug)]
227pub(crate) struct AbsentEntry<'a, TKey, TVal>(EntryRef<'a, TKey, TVal>);
228impl<'a, TKey, TVal> AbsentEntry<'a, TKey, TVal>
229where
230    TKey: Clone + AsRef<KeyBytes>,
231    TVal: Clone,
232{
233    fn new(bucket: &'a mut KBucket<TKey, TVal>, key: &'a TKey) -> Self {
234        AbsentEntry(EntryRef { bucket, key })
235    }
236
237    /// Attempts to insert the entry into a bucket.
238    pub(crate) fn insert(self, value: TVal, status: NodeStatus) -> InsertResult<TKey> {
239        self.0.bucket.insert(
240            Node {
241                key: self.0.key.clone(),
242                value,
243            },
244            status,
245        )
246    }
247}