diff --git a/crates/lox-library/src/lib.rs b/crates/lox-library/src/lib.rs index 40e4d8c..b2b73a1 100644 --- a/crates/lox-library/src/lib.rs +++ b/crates/lox-library/src/lib.rs @@ -94,6 +94,12 @@ pub enum OpenInvitationError { NoBridgesAvailable, } +#[derive(Error, Debug)] +pub enum BridgeTableError { + #[error("The bucket corresponding to key {0} was not in the bridge table")] + MissingBucket(u32), +} + /// Private Key of the Issuer #[derive(Clone, Debug, Serialize, Deserialize)] pub struct IssuerPrivKey { @@ -510,6 +516,25 @@ impl BridgeAuth { res } + // Repurpose a bucket of spares into unallocated bridges + pub fn dissolve_spare_bucket(&mut self, key: u32) -> Result<(), BridgeTableError> { + self.bridge_table.spares.remove(&key); + // Get the actual bridges from the spare bucket + let spare_bucket = self + .bridge_table + .buckets + .remove(&key) + .ok_or(BridgeTableError::MissingBucket(key))?; + for bridge in spare_bucket.iter() { + self.bridge_table.unallocated_bridges.push(*bridge); + // Mark bucket as unreachable while it is unallocated + self.bridge_table.reachable.remove(bridge); + } + self.bridge_table.keys.remove(&key); + self.bridge_table.recycleable_keys.push(key); + Ok(()) + } + /// Attempt to remove a bridge that is failing tests and replace it with a bridge from /// available_bridge or from a spare bucket pub fn bridge_replace( @@ -573,28 +598,10 @@ impl BridgeAuth { else { return ReplaceSuccess::NotReplaced; }; - self.bridge_table.spares.remove(&spare); - // Get the actual bridges from the spare bucket - let spare_bucket = match self.bridge_table.buckets.remove(&spare) { - Some(spare_bucket) => spare_bucket, - // This should not happen if the rest of the functions are correct, we can assume unwrap will succeed - None => return ReplaceSuccess::NotReplaced, + let Ok(_) = self.dissolve_spare_bucket(spare) else { + return ReplaceSuccess::NotReplaced; }; - // Remove the spare bucket uid from the keys map - self.bridge_table.keys.remove(&spare); - self.bridge_table.recycleable_keys.push(spare); - let mut replacement: &BridgeLine = &BridgeLine::default(); - // Make the first spare the replacement bridge, add the others to the set of - // unallocated_bridges - for spare_bridge in spare_bucket.iter() { - if replacement.port > 0 { - self.bridge_table.unallocated_bridges.push(*spare_bridge); - // Mark bucket as unreachable while it is unallocated - self.bridge_table.reachable.remove(spare_bridge); - } else { - replacement = spare_bridge; - } - } + let replacement = &self.bridge_table.unallocated_bridges.pop().unwrap(); for (bucketnum, offset) in positions.iter() { let mut bridgelines = match self.bridge_table.buckets.get(bucketnum) { Some(bridgelines) => *bridgelines,