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::*;
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}
85
86/// The internal representation of the different states of an `Entry`,
87/// referencing the associated key and bucket.
88#[derive(Debug)]
89struct EntryRef<'a, TKey, TVal> {
90    bucket: &'a mut KBucket<TKey, TVal>,
91    key: &'a TKey,
92}
93
94impl<'a, TKey, TVal> Entry<'a, TKey, TVal>
95where
96    TKey: Clone + AsRef<KeyBytes>,
97    TVal: Clone,
98{
99    /// Creates a new `Entry` for a `Key`, encapsulating access to a bucket.
100    pub(super) fn new(bucket: &'a mut KBucket<TKey, TVal>, key: &'a TKey) -> Self {
101        if let Some(pos) = bucket.position(key) {
102            let status = bucket.status(pos);
103            Entry::Present(PresentEntry::new(bucket, key), status)
104        } else if let Some(pending) = bucket.as_pending(key) {
105            let status = pending.status();
106            Entry::Pending(PendingEntry::new(bucket, key), status)
107        } else {
108            Entry::Absent(AbsentEntry::new(bucket, key))
109        }
110    }
111
112    /// Creates an immutable by-reference view of the entry.
113    ///
114    /// Returns `None` if the entry is neither present in a bucket nor
115    /// pending insertion into a bucket.
116    pub(crate) fn view(&'a mut self) -> Option<EntryRefView<'a, TKey, TVal>> {
117        match self {
118            Entry::Present(entry, status) => Some(EntryRefView {
119                node: NodeRefView {
120                    key: entry.0.key,
121                    value: entry.value(),
122                },
123                status: *status,
124            }),
125            Entry::Pending(entry, status) => Some(EntryRefView {
126                node: NodeRefView {
127                    key: entry.0.key,
128                    value: entry.value(),
129                },
130                status: *status,
131            }),
132            _ => None,
133        }
134    }
135
136    /// Returns the value associated with the entry.
137    ///
138    /// Returns `None` if the entry is absent from any bucket or refers to the
139    /// local node.
140    pub(crate) fn value(&mut self) -> Option<&mut TVal> {
141        match self {
142            Entry::Present(entry, _) => Some(entry.value()),
143            Entry::Pending(entry, _) => Some(entry.value()),
144            Entry::Absent(_) => None,
145        }
146    }
147}
148
149/// An entry present in a bucket.
150#[derive(Debug)]
151pub(crate) struct PresentEntry<'a, TKey, TVal>(EntryRef<'a, TKey, TVal>);
152impl<'a, TKey, TVal> PresentEntry<'a, TKey, TVal>
153where
154    TKey: Clone + AsRef<KeyBytes>,
155    TVal: Clone,
156{
157    fn new(bucket: &'a mut KBucket<TKey, TVal>, key: &'a TKey) -> Self {
158        PresentEntry(EntryRef { bucket, key })
159    }
160
161    /// Returns the value associated with the key.
162    pub(crate) fn value(&mut self) -> &mut TVal {
163        &mut self
164            .0
165            .bucket
166            .get_mut(self.0.key)
167            .expect("We can only build a PresentEntry if the entry is in the bucket; QED")
168            .value
169    }
170
171    /// Sets the status of the entry to the provided [`NodeStatus`].
172    pub(crate) fn update(&mut self, status: NodeStatus) {
173        self.0.bucket.update(self.0.key, status);
174    }
175
176    /// Removes the entry from the bucket.
177    pub(crate) fn remove(self) -> EntryView<TKey, TVal> {
178        let (node, status, _pos) = self
179            .0
180            .bucket
181            .remove(self.0.key)
182            .expect("We can only build a PresentEntry if the entry is in the bucket; QED");
183        EntryView { node, status }
184    }
185}
186
187/// An entry waiting for a slot to be available in a bucket.
188#[derive(Debug)]
189pub(crate) struct PendingEntry<'a, TKey, TVal>(EntryRef<'a, TKey, TVal>);
190impl<'a, TKey, TVal> PendingEntry<'a, TKey, TVal>
191where
192    TKey: Clone + AsRef<KeyBytes>,
193    TVal: Clone,
194{
195    fn new(bucket: &'a mut KBucket<TKey, TVal>, key: &'a TKey) -> Self {
196        PendingEntry(EntryRef { bucket, key })
197    }
198
199    /// Returns the value associated with the key.
200    pub(crate) fn value(&mut self) -> &mut TVal {
201        self.0
202            .bucket
203            .pending_mut()
204            .expect("We can only build a ConnectedPendingEntry if the entry is pending; QED")
205            .value_mut()
206    }
207
208    /// Updates the status of the pending entry.
209    pub(crate) fn update(self, status: NodeStatus) -> PendingEntry<'a, TKey, TVal> {
210        self.0.bucket.update_pending(status);
211        PendingEntry::new(self.0.bucket, self.0.key)
212    }
213
214    /// Removes the pending entry from the bucket.
215    pub(crate) fn remove(self) -> EntryView<TKey, TVal> {
216        let pending = self.0.bucket.remove_pending().expect(
217            "We can only build a PendingEntry if the entry is pending insertion
218                    into the bucket; QED",
219        );
220        let status = pending.status();
221        let node = pending.into_node();
222        EntryView { node, status }
223    }
224}
225
226/// An entry that is not present in any bucket.
227#[derive(Debug)]
228pub(crate) struct AbsentEntry<'a, TKey, TVal>(EntryRef<'a, TKey, TVal>);
229impl<'a, TKey, TVal> AbsentEntry<'a, TKey, TVal>
230where
231    TKey: Clone + AsRef<KeyBytes>,
232    TVal: Clone,
233{
234    fn new(bucket: &'a mut KBucket<TKey, TVal>, key: &'a TKey) -> Self {
235        AbsentEntry(EntryRef { bucket, key })
236    }
237
238    /// Attempts to insert the entry into a bucket.
239    pub(crate) fn insert(self, value: TVal, status: NodeStatus) -> InsertResult<TKey> {
240        self.0.bucket.insert(
241            Node {
242                key: self.0.key.clone(),
243                value,
244            },
245            status,
246        )
247    }
248}