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 quering 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, NodeStatus, K_VALUE};
25pub use super::key::*;
26
27use super::*;
28
29/// An immutable by-reference view of a bucket entry.
30pub struct EntryRefView<'a, TPeerId, TVal> {
31    /// The node represented by the entry.
32    pub node: NodeRefView<'a, TPeerId, TVal>,
33    /// The status of the node identified by the key.
34    pub status: NodeStatus,
35}
36
37/// An immutable by-reference view of a `Node`.
38pub struct NodeRefView<'a, TKey, TVal> {
39    pub key: &'a TKey,
40    pub value: &'a TVal,
41}
42
43impl<TKey, TVal> EntryRefView<'_, TKey, TVal> {
44    pub fn to_owned(&self) -> EntryView<TKey, TVal>
45    where
46        TKey: Clone,
47        TVal: Clone,
48    {
49        EntryView {
50            node: Node {
51                key: self.node.key.clone(),
52                value: self.node.value.clone(),
53            },
54            status: self.status,
55        }
56    }
57}
58
59/// A cloned, immutable view of an entry that is either present in a bucket
60/// or pending insertion.
61#[derive(Clone, Debug)]
62pub struct EntryView<TKey, TVal> {
63    /// The node represented by the entry.
64    pub node: Node<TKey, TVal>,
65    /// The status of the node.
66    pub status: NodeStatus,
67}
68
69impl<TKey: AsRef<KeyBytes>, TVal> AsRef<KeyBytes> for EntryView<TKey, TVal> {
70    fn as_ref(&self) -> &KeyBytes {
71        self.node.key.as_ref()
72    }
73}
74
75/// A reference into a single entry of a `KBucketsTable`.
76#[derive(Debug)]
77pub(crate) enum Entry<'a, TPeerId, TVal> {
78    /// The entry is present in a bucket.
79    Present(PresentEntry<'a, TPeerId, TVal>, NodeStatus),
80    /// The entry is pending insertion in a bucket.
81    Pending(PendingEntry<'a, TPeerId, TVal>, NodeStatus),
82    /// The entry is absent and may be inserted.
83    Absent(AbsentEntry<'a, TPeerId, TVal>),
84    /// The entry represents the local node.
85    SelfEntry,
86}
87
88/// The internal representation of the different states of an `Entry`,
89/// referencing the associated key and bucket.
90#[derive(Debug)]
91struct EntryRef<'a, TKey, TVal> {
92    bucket: &'a mut KBucket<TKey, TVal>,
93    key: &'a TKey,
94}
95
96impl<'a, TKey, TVal> Entry<'a, TKey, TVal>
97where
98    TKey: Clone + AsRef<KeyBytes>,
99    TVal: Clone,
100{
101    /// Creates a new `Entry` for a `Key`, encapsulating access to a bucket.
102    pub(super) fn new(bucket: &'a mut KBucket<TKey, TVal>, key: &'a TKey) -> Self {
103        if let Some(pos) = bucket.position(key) {
104            let status = bucket.status(pos);
105            Entry::Present(PresentEntry::new(bucket, key), status)
106        } else if let Some(pending) = bucket.as_pending(key) {
107            let status = pending.status();
108            Entry::Pending(PendingEntry::new(bucket, key), status)
109        } else {
110            Entry::Absent(AbsentEntry::new(bucket, key))
111        }
112    }
113
114    /// Creates an immutable by-reference view of the entry.
115    ///
116    /// Returns `None` if the entry is neither present in a bucket nor
117    /// pending insertion into a bucket.
118    pub(crate) fn view(&'a mut self) -> Option<EntryRefView<'a, TKey, TVal>> {
119        match self {
120            Entry::Present(entry, status) => Some(EntryRefView {
121                node: NodeRefView {
122                    key: entry.0.key,
123                    value: entry.value(),
124                },
125                status: *status,
126            }),
127            Entry::Pending(entry, status) => Some(EntryRefView {
128                node: NodeRefView {
129                    key: entry.0.key,
130                    value: entry.value(),
131                },
132                status: *status,
133            }),
134            _ => None,
135        }
136    }
137
138    /// Returns the value associated with the entry.
139    ///
140    /// Returns `None` if the entry is absent from any bucket or refers to the
141    /// local node.
142    pub(crate) fn value(&mut self) -> Option<&mut TVal> {
143        match self {
144            Entry::Present(entry, _) => Some(entry.value()),
145            Entry::Pending(entry, _) => Some(entry.value()),
146            Entry::Absent(_) => None,
147            Entry::SelfEntry => None,
148        }
149    }
150}
151
152/// An entry present in a bucket.
153#[derive(Debug)]
154pub(crate) struct PresentEntry<'a, TKey, TVal>(EntryRef<'a, TKey, TVal>);
155impl<'a, TKey, TVal> PresentEntry<'a, TKey, TVal>
156where
157    TKey: Clone + AsRef<KeyBytes>,
158    TVal: Clone,
159{
160    fn new(bucket: &'a mut KBucket<TKey, TVal>, key: &'a TKey) -> Self {
161        PresentEntry(EntryRef { bucket, key })
162    }
163
164    /// Returns the value associated with the key.
165    pub(crate) fn value(&mut self) -> &mut TVal {
166        &mut self
167            .0
168            .bucket
169            .get_mut(self.0.key)
170            .expect("We can only build a PresentEntry if the entry is in the bucket; QED")
171            .value
172    }
173
174    /// Sets the status of the entry to the provided [`NodeStatus`].
175    pub(crate) fn update(&mut self, status: NodeStatus) {
176        self.0.bucket.update(self.0.key, status);
177    }
178
179    /// Removes the entry from the bucket.
180    pub(crate) fn remove(self) -> EntryView<TKey, TVal> {
181        let (node, status, _pos) = self
182            .0
183            .bucket
184            .remove(self.0.key)
185            .expect("We can only build a PresentEntry if the entry is in the bucket; QED");
186        EntryView { node, status }
187    }
188}
189
190/// An entry waiting for a slot to be available in a bucket.
191#[derive(Debug)]
192pub(crate) struct PendingEntry<'a, TKey, TVal>(EntryRef<'a, TKey, TVal>);
193impl<'a, TKey, TVal> PendingEntry<'a, TKey, TVal>
194where
195    TKey: Clone + AsRef<KeyBytes>,
196    TVal: Clone,
197{
198    fn new(bucket: &'a mut KBucket<TKey, TVal>, key: &'a TKey) -> Self {
199        PendingEntry(EntryRef { bucket, key })
200    }
201
202    /// Returns the value associated with the key.
203    pub(crate) fn value(&mut self) -> &mut TVal {
204        self.0
205            .bucket
206            .pending_mut()
207            .expect("We can only build a ConnectedPendingEntry if the entry is pending; QED")
208            .value_mut()
209    }
210
211    /// Updates the status of the pending entry.
212    pub(crate) fn update(self, status: NodeStatus) -> PendingEntry<'a, TKey, TVal> {
213        self.0.bucket.update_pending(status);
214        PendingEntry::new(self.0.bucket, self.0.key)
215    }
216
217    /// Removes the pending entry from the bucket.
218    pub(crate) fn remove(self) -> EntryView<TKey, TVal> {
219        let pending = self.0.bucket.remove_pending().expect(
220            "We can only build a PendingEntry if the entry is pending insertion
221                    into the bucket; QED",
222        );
223        let status = pending.status();
224        let node = pending.into_node();
225        EntryView { node, status }
226    }
227}
228
229/// An entry that is not present in any bucket.
230#[derive(Debug)]
231pub(crate) struct AbsentEntry<'a, TKey, TVal>(EntryRef<'a, TKey, TVal>);
232impl<'a, TKey, TVal> AbsentEntry<'a, TKey, TVal>
233where
234    TKey: Clone + AsRef<KeyBytes>,
235    TVal: Clone,
236{
237    fn new(bucket: &'a mut KBucket<TKey, TVal>, key: &'a TKey) -> Self {
238        AbsentEntry(EntryRef { bucket, key })
239    }
240
241    /// Attempts to insert the entry into a bucket.
242    pub(crate) fn insert(self, value: TVal, status: NodeStatus) -> InsertResult<TKey> {
243        self.0.bucket.insert(
244            Node {
245                key: self.0.key.clone(),
246                value,
247            },
248            status,
249        )
250    }
251}