use std::collections::{HashMap, HashSet};
use std::net::SocketAddr;
#[derive(Default, Debug)]
pub struct PendingRequests {
piece_requested_from: HashMap<usize, HashSet<SocketAddr>>,
}
impl PendingRequests {
pub fn add(&mut self, piece: usize, peer: &SocketAddr) {
self.piece_requested_from.entry(piece).or_default().insert(*peer);
}
pub fn clear_requests_of(&mut self, piece: usize) {
self.piece_requested_from.remove(&piece);
}
pub fn clear_requests_to(&mut self, peer: &SocketAddr) {
for peers in self.piece_requested_from.values_mut() {
peers.remove(peer);
}
}
pub fn is_piece_requested(&self, piece: usize) -> bool {
self.piece_requested_from.get(&piece).is_some_and(|peers| !peers.is_empty())
}
pub fn is_piece_requested_from(&self, peer: &SocketAddr, piece: usize) -> bool {
self.piece_requested_from.get(&piece).is_some_and(|peers| peers.contains(peer))
}
pub fn requests_in_flight(&self) -> usize {
self.piece_requested_from.values().flatten().count()
}
pub fn pieces_requested(&self) -> usize {
self.piece_requested_from.values().filter(|peers| !peers.is_empty()).count()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
#[test]
fn test_pending_requests_from_single_peer() {
let peer = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 6666));
let mut pr = PendingRequests::default();
pr.add(42, &peer);
pr.add(43, &peer);
pr.add(44, &peer);
assert!(pr.is_piece_requested(42));
assert!(pr.is_piece_requested(43));
assert!(pr.is_piece_requested(44));
pr.clear_requests_of(43);
assert!(pr.is_piece_requested(42));
assert!(!pr.is_piece_requested(43));
assert!(pr.is_piece_requested(44));
pr.clear_requests_to(&peer);
assert!(!pr.is_piece_requested(42));
assert!(!pr.is_piece_requested(43));
assert!(!pr.is_piece_requested(44));
}
#[test]
fn test_pending_requests_from_multiple_peers() {
let peer1 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 6666));
let peer2 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 6667));
let peer3 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 6668));
let mut pr = PendingRequests::default();
pr.add(42, &peer1);
pr.add(42, &peer2);
pr.add(42, &peer3);
assert!(pr.is_piece_requested(42));
pr.clear_requests_to(&peer2);
assert!(pr.is_piece_requested(42));
pr.clear_requests_of(42);
assert!(!pr.is_piece_requested(42));
}
}