libp2p_kad/kbucket/
sub_bucket.rs1use std::time::Instant;
18use log::debug;
19
20enum ChangePosition {
21 AddDisconnected,
22 AppendConnected { num_entries: usize },
24 RemoveConnected,
25 RemoveDisconnected,
26}
27
28#[derive(PartialEq, Eq, Debug, Copy, Clone)]
34pub enum NodeStatus {
35 Connected,
37 Disconnected,
39}
40
41#[derive(Debug, Clone)]
43pub struct PendingNode<TKey, TVal> {
44 pub node: Node<TKey, TVal>,
46
47 pub status: NodeStatus,
49
50 pub replace: Instant,
52}
53
54impl<TKey, TVal> PendingNode<TKey, TVal> {
55 pub fn key(&self) -> &TKey {
56 &self.node.key
57 }
58
59 pub fn status(&self) -> NodeStatus {
60 self.status
61 }
62
63 pub fn value_mut(&mut self) -> &mut TVal {
64 &mut self.node.value
65 }
66
67 pub fn is_ready(&self) -> bool {
68 Instant::now() >= self.replace
69 }
70
71 pub fn set_ready_at(&mut self, t: Instant) {
72 self.replace = t;
73 }
74
75 pub fn into_node(self) -> Node<TKey, TVal> {
76 self.node
77 }
78}
79
80#[derive(Debug, Clone, PartialEq, Eq)]
84pub struct Node<TKey, TVal> {
85 pub key: TKey,
87 pub value: TVal,
89 pub weight: u32,
90}
91
92#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
95pub struct Position(pub usize);
96
97#[derive(Debug, Clone)]
98pub struct SubBucket<Node> {
99 pub nodes: Vec<Node>,
100 pub first_connected_pos: Option<usize>,
101 pub capacity: usize,
102}
103
104impl<Node> SubBucket<Node> {
105 pub fn new(capacity: usize) -> Self {
106 Self {
107 nodes: Vec::with_capacity(capacity + 1),
108 first_connected_pos: None,
109 capacity,
110 }
111 }
112
113 pub fn status(&self, pos: Position) -> NodeStatus {
114 if self.first_connected_pos.map_or(false, |i| pos.0 >= i) {
115 NodeStatus::Connected
116 } else {
117 NodeStatus::Disconnected
118 }
119 }
120
121 pub fn iter(&self) -> impl Iterator<Item = (&Node, NodeStatus)> {
123 self.nodes
124 .iter()
125 .enumerate()
126 .map(move |(p, n)| (n, self.status(Position(p))))
127 }
128
129 pub fn is_full(&self) -> bool {
130 self.nodes.len() >= self.capacity
131 }
132
133 pub fn all_nodes_connected(&self) -> bool {
134 self.first_connected_pos == Some(0)
135 }
136
137 pub fn append_connected_node(&mut self, node: Node) {
138 self.change_connected_pos(ChangePosition::AppendConnected {
140 num_entries: self.num_entries(),
141 });
142 self.nodes.push(node);
143 }
144
145 pub fn insert_disconnected_node(&mut self, node: Node) {
146 let current_position = self.first_connected_pos;
147 self.change_connected_pos(ChangePosition::AddDisconnected);
148 match current_position {
149 Some(p) => self.nodes.insert(p, node), None => self.nodes.push(node), }
152 }
153
154 fn change_connected_pos(&mut self, action: ChangePosition) {
155 match action {
156 ChangePosition::AddDisconnected => {
157 self.first_connected_pos = self.first_connected_pos.map(|p| p + 1)
159 }
160 ChangePosition::AppendConnected { num_entries } => {
161 self.first_connected_pos = self.first_connected_pos.or(Some(num_entries));
164 }
165 ChangePosition::RemoveConnected => {
166 if self.num_connected() == 1 {
167 self.first_connected_pos = None }
170 }
172 ChangePosition::RemoveDisconnected => {
173 self.first_connected_pos = self
176 .first_connected_pos
177 .map(|p| p.checked_sub(1).unwrap_or(0))
178 }
179 }
180 }
181
182 pub fn evict_node(&mut self, position: Position) -> Option<Node> {
183 match self.status(position) {
184 NodeStatus::Connected => self.change_connected_pos(ChangePosition::RemoveConnected),
185 NodeStatus::Disconnected => {
186 self.change_connected_pos(ChangePosition::RemoveDisconnected)
187 }
188 }
189 if position.0 >= self.nodes.len() {
190 debug!(
191 "WARNING: tried to evict node at {} while there's only {} nodes",
192 position.0,
193 self.nodes.len()
194 );
195 None
196 } else {
197 Some(self.nodes.remove(position.0))
198 }
199 }
200
201 pub fn pop_node(&mut self) -> Option<Node> {
202 self.evict_node(Position(0))
203 }
204
205 pub fn least_recently_connected(&self) -> Option<&Node> {
206 self.nodes.get(0)
207 }
208
209 pub fn is_least_recently_connected(&self, pos: Position) -> bool {
210 pos.0 == 0
211 }
212
213 pub fn is_connected(&self, pos: Position) -> bool {
215 self.status(pos) == NodeStatus::Connected
216 }
217
218 pub fn num_entries(&self) -> usize {
220 self.nodes.len()
221 }
222
223 pub fn num_connected(&self) -> usize {
225 self.first_connected_pos
226 .map_or(0, |i| self.num_entries() - i)
227 }
228
229 pub fn num_disconnected(&self) -> usize {
231 self.num_entries() - self.num_connected()
232 }
233
234 pub fn position<P>(&self, pred: P) -> Option<Position>
236 where
237 P: Fn(&Node) -> bool,
238 {
239 self.nodes.iter().position(pred).map(Position)
240 }
241
242 pub fn get_mut(&mut self, position: Position) -> Option<&mut Node> {
243 self.nodes.get_mut(position.0)
244 }
245}