From d6c2e289ff2d2a8c89b54b9f326a12ccd9845290 Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 30 Jul 2022 14:33:22 -0600 Subject: [PATCH 1/3] use async mutexes in inmemorygateway and reimplement inmemorygateway transactions --- src/entity/gateway/inmemory.rs | 401 ++++++++++++++++++++++----------- 1 file changed, 273 insertions(+), 128 deletions(-) diff --git a/src/entity/gateway/inmemory.rs b/src/entity/gateway/inmemory.rs index 965b478..560d683 100644 --- a/src/entity/gateway/inmemory.rs +++ b/src/entity/gateway/inmemory.rs @@ -7,57 +7,199 @@ use crate::entity::character::*; use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction, GatewayError}; use crate::entity::item::*; -use std::sync::{Arc, Mutex}; +use async_std::sync::{Arc, Mutex}; // TODO: implement multiple banks - pub struct InMemoryGatewayTransaction<'a> { working_gateway: InMemoryGateway, original_gateway: &'a mut InMemoryGateway, } + +fn copy_if_needed(working_table: &mut BTreeMap, original_table: &BTreeMap, key: K) -> Option<()> +where + K: Ord + Copy, + V: Clone, +{ + if !working_table.contains_key(&key) { + working_table.insert(key, original_table.get(&key)?.clone()); + } + + Some(()) +} + +// functions here have been skipped as they are not used in transactions, add as needed #[async_trait::async_trait] -impl<'a> EntityGatewayTransaction for InMemoryGatewayTransaction<'a> { - fn gateway(&mut self) -> &mut dyn EntityGateway { - &mut self.working_gateway +impl<'a> EntityGateway for InMemoryGatewayTransaction<'a> { + async fn create_user(&mut self, user: NewUserAccountEntity) -> Result { + self.working_gateway.create_user(user).await } - async fn commit(mut self: Box) -> Result<(), GatewayError> { - self.original_gateway.users.lock().unwrap().clear(); - self.original_gateway.users.lock().unwrap().extend(self.working_gateway.users.lock().unwrap().clone()); + async fn get_user_by_id(&mut self, id: UserAccountId) -> Result { + match self.working_gateway.get_user_by_id(id).await { + Ok(user) => Ok(user), + Err(_) => { + self.original_gateway.get_user_by_id(id).await + } + } + } - self.original_gateway.user_settings.lock().unwrap().clear(); - self.original_gateway.user_settings.lock().unwrap().extend(self.working_gateway.user_settings.lock().unwrap().clone()); + async fn get_user_by_name(&mut self, username: String) -> Result { + match self.working_gateway.get_user_by_name(username.clone()).await { + Ok(user) => Ok(user), + Err(_) => { + self.original_gateway.get_user_by_name(username).await + } + } + } - self.original_gateway.characters.lock().unwrap().clear(); - self.original_gateway.characters.lock().unwrap().extend(self.working_gateway.characters.lock().unwrap().clone()); + async fn save_user(&mut self, user: &UserAccountEntity) -> Result<(), GatewayError> { + self.working_gateway.save_user(user).await + } - self.original_gateway.character_meseta.lock().unwrap().clear(); - self.original_gateway.character_meseta.lock().unwrap().extend(self.working_gateway.character_meseta.lock().unwrap().clone()); + async fn create_user_settings(&mut self, settings: NewUserSettingsEntity) -> Result { + self.working_gateway.create_user_settings(settings).await + } - self.original_gateway.bank_meseta.lock().unwrap().clear(); - self.original_gateway.bank_meseta.lock().unwrap().extend(self.working_gateway.bank_meseta.lock().unwrap().clone()); + async fn get_user_settings_by_user(&mut self, user: &UserAccountEntity) -> Result { + match self.working_gateway.get_user_settings_by_user(user).await { + Ok(user) => Ok(user), + Err(_) => { + self.original_gateway.get_user_settings_by_user(user).await + } + } + } + + async fn save_character(&mut self, char: &CharacterEntity) -> Result<(), GatewayError> { + copy_if_needed(&mut *self.working_gateway.characters.lock().await, + &*self.original_gateway.characters.lock().await, + char.id + ); + self.working_gateway.save_character(char).await + } + + async fn create_item(&mut self, item: NewItemEntity) -> Result { + self.working_gateway.create_item(item).await + } - self.original_gateway.items.lock().unwrap().clear(); - self.original_gateway.items.lock().unwrap().extend(self.working_gateway.items.lock().unwrap().clone()); + async fn add_item_note(&mut self, item_id: &ItemEntityId, item_note: ItemNote) -> Result<(), GatewayError> { + self.working_gateway.add_item_note(item_id, item_note).await + } - self.original_gateway.inventories.lock().unwrap().clear(); - self.original_gateway.inventories.lock().unwrap().extend(self.working_gateway.inventories.lock().unwrap().clone()); + async fn feed_mag(&mut self, mag_item_id: &ItemEntityId, tool_item_id: &ItemEntityId) -> Result<(), GatewayError> { + self.working_gateway.feed_mag(mag_item_id, tool_item_id).await + } - self.original_gateway.banks.lock().unwrap().clear(); - self.original_gateway.banks.lock().unwrap().extend(self.working_gateway.banks.lock().unwrap().clone()); + async fn change_mag_owner(&mut self, mag_item_id: &ItemEntityId, character: &CharacterEntity) -> Result<(), GatewayError> { + self.working_gateway.change_mag_owner(mag_item_id, character).await + } - self.original_gateway.equips.lock().unwrap().clear(); - self.original_gateway.equips.lock().unwrap().extend(self.working_gateway.equips.lock().unwrap().clone()); + async fn use_mag_cell(&mut self, mag_item_id: &ItemEntityId, mag_cell_id: &ItemEntityId) -> Result<(), GatewayError> { + self.working_gateway.use_mag_cell(mag_item_id, mag_cell_id).await + } - self.original_gateway.mag_modifiers.lock().unwrap().clear(); - self.original_gateway.mag_modifiers.lock().unwrap().extend(self.working_gateway.mag_modifiers.lock().unwrap().clone()); + async fn add_weapon_modifier(&mut self, item_id: &ItemEntityId, modifier: weapon::WeaponModifier) -> Result<(), GatewayError> { + self.working_gateway.add_weapon_modifier(item_id, modifier).await + } - self.original_gateway.weapon_modifiers.lock().unwrap().clear(); - self.original_gateway.weapon_modifiers.lock().unwrap().extend(self.working_gateway.weapon_modifiers.lock().unwrap().clone()); + async fn get_character_inventory(&mut self, char_id: &CharacterEntityId) -> Result { + match self.working_gateway.get_character_inventory(char_id).await { + Ok(inventory) => Ok(inventory), + Err(_) => { + self.original_gateway.get_character_inventory(char_id).await + } + } + } - self.original_gateway.trades.lock().unwrap().clear(); - self.original_gateway.trades.lock().unwrap().extend(self.working_gateway.trades.lock().unwrap().clone()); + async fn get_character_bank(&mut self, char_id: &CharacterEntityId, bank_name: &BankName) -> Result { + match self.working_gateway.get_character_bank(char_id, bank_name).await { + Ok(bank) => Ok(bank), + Err(_) => { + self.original_gateway.get_character_bank(char_id, bank_name).await + } + } + } + + async fn set_character_inventory(&mut self, char_id: &CharacterEntityId, inventory: &InventoryEntity) -> Result<(), GatewayError> { + self.working_gateway.set_character_inventory(char_id, inventory).await + } + + async fn set_character_bank(&mut self, char_id: &CharacterEntityId, bank: &BankEntity, bank_name: &BankName) -> Result<(), GatewayError> { + self.working_gateway.set_character_bank(char_id, bank, bank_name).await + } + + + async fn get_character_equips(&mut self, char_id: &CharacterEntityId) -> Result { + match self.working_gateway.get_character_equips(char_id).await { + Ok(equips) => Ok(equips), + Err(_) => { + self.original_gateway.get_character_equips(char_id).await + } + } + } + + async fn set_character_equips(&mut self, char_id: &CharacterEntityId, equipped: &EquippedEntity) -> Result<(), GatewayError> { + self.working_gateway.set_character_equips(char_id, equipped).await + } + + async fn set_character_meseta(&mut self, char_id: &CharacterEntityId, meseta: Meseta) -> Result<(), GatewayError> { + self.working_gateway.set_character_meseta(char_id, meseta).await + } + + async fn get_character_meseta(&mut self, char_id: &CharacterEntityId) -> Result { + match self.working_gateway.get_character_meseta(char_id).await { + Ok(meseta) => Ok(meseta), + Err(_) => { + self.original_gateway.get_character_meseta(char_id).await + } + } + } + + async fn set_bank_meseta(&mut self, char_id: &CharacterEntityId, bank: &BankName, meseta: Meseta) -> Result<(), GatewayError> { + self.working_gateway.set_bank_meseta(char_id, bank, meseta).await + } + + async fn get_bank_meseta(&mut self, char_id: &CharacterEntityId, bank: &BankName) -> Result { + match self.working_gateway.get_bank_meseta(char_id, bank).await { + Ok(meseta) => Ok(meseta), + Err(_) => { + self.original_gateway.get_bank_meseta(char_id, bank).await + } + } + } + + async fn create_trade(&mut self, char_id1: &CharacterEntityId, char_id2: &CharacterEntityId) -> Result { + self.working_gateway.create_trade(char_id1, char_id2).await + } + + async fn set_character_playtime(&mut self, char_id: &CharacterEntityId, playtime: u32) -> Result<(), GatewayError> { + copy_if_needed(&mut *self.working_gateway.characters.lock().await, + &*self.original_gateway.characters.lock().await, + *char_id + ); + self.working_gateway.set_character_playtime(char_id, playtime).await + } +} + +#[async_trait::async_trait] +impl<'a> EntityGatewayTransaction for InMemoryGatewayTransaction<'a> { + fn gateway(&mut self) -> &mut dyn EntityGateway { + self + } + + async fn commit(mut self: Box) -> Result<(), GatewayError> { + self.original_gateway.users.lock().await.extend(self.working_gateway.users.lock().await.clone()); + self.original_gateway.user_settings.lock().await.extend(self.working_gateway.user_settings.lock().await.clone()); + self.original_gateway.characters.lock().await.extend(self.working_gateway.characters.lock().await.clone()); + self.original_gateway.character_meseta.lock().await.extend(self.working_gateway.character_meseta.lock().await.clone()); + self.original_gateway.bank_meseta.lock().await.extend(self.working_gateway.bank_meseta.lock().await.clone()); + self.original_gateway.items.lock().await.extend(self.working_gateway.items.lock().await.clone()); + self.original_gateway.inventories.lock().await.extend(self.working_gateway.inventories.lock().await.clone()); + self.original_gateway.banks.lock().await.extend(self.working_gateway.banks.lock().await.clone()); + self.original_gateway.equips.lock().await.extend(self.working_gateway.equips.lock().await.clone()); + self.original_gateway.mag_modifiers.lock().await.extend(self.working_gateway.mag_modifiers.lock().await.clone()); + self.original_gateway.weapon_modifiers.lock().await.extend(self.working_gateway.weapon_modifiers.lock().await.clone()); + self.original_gateway.trades.lock().await.extend(self.working_gateway.trades.lock().await.clone()); Ok(()) } @@ -98,60 +240,60 @@ impl Default for InMemoryGateway { } } -impl InMemoryGateway { - fn apply_modifiers(&self, inventory: InventoryEntity ) -> InventoryEntity { - let items = self.items.lock().unwrap(); - let inventory_items = inventory.items.into_iter() - .map(|item| { - item.map_individual(|mut item| { - item.item = match item.item { - ItemDetail::Weapon(mut weapon) => { - if let Some(weapon_modifiers) = self.weapon_modifiers.lock().unwrap().get(&item.id) { - for weapon_modifier in weapon_modifiers.iter() { - weapon.apply_modifier(weapon_modifier); - } +fn apply_modifiers(items: &BTreeMap, + weapon_modifiers: &BTreeMap>, + mag_modifiers: &BTreeMap>, + inventory: InventoryEntity ) -> InventoryEntity { + let inventory_items = inventory.items.into_iter() + .map(|item| { + item.map_individual(|mut item| { + item.item = match item.item { + ItemDetail::Weapon(mut weapon) => { + if let Some(weapon_modifiers) = weapon_modifiers.get(&item.id) { + for weapon_modifier in weapon_modifiers.iter() { + weapon.apply_modifier(weapon_modifier); } - ItemDetail::Weapon(weapon) - }, - ItemDetail::Mag(mag) => { - let mut mag = mag::Mag::baby_mag(mag.color as u16); - if let Some(mag_modifiers) = self.mag_modifiers.lock().unwrap().get(&item.id) { - for mag_modifier in mag_modifiers.iter() { - match mag_modifier { - mag::MagModifier::FeedMag {food} => { - if let Some(mag_feed) = items.get(food) { - if let ItemDetail::Tool(mag_feed) = mag_feed.item { - mag.feed(mag_feed.tool) - } + } + ItemDetail::Weapon(weapon) + }, + ItemDetail::Mag(mag) => { + let mut mag = mag::Mag::baby_mag(mag.color as u16); + if let Some(mag_modifiers) = mag_modifiers.get(&item.id) { + for mag_modifier in mag_modifiers.iter() { + match mag_modifier { + mag::MagModifier::FeedMag {food} => { + if let Some(mag_feed) = items.get(food) { + if let ItemDetail::Tool(mag_feed) = mag_feed.item { + mag.feed(mag_feed.tool) } - }, - mag::MagModifier::OwnerChange(class, section_id) => { - mag.change_owner(*class, *section_id) - }, - mag::MagModifier::MagCell(mag_cell_id) => { - if let Some(mag_cell) = items.get(mag_cell_id) { - if let ItemDetail::Tool(mag_cell) = mag_cell.item { - mag.apply_mag_cell(mag_cell.tool.try_into().unwrap()).unwrap() - } + } + }, + mag::MagModifier::OwnerChange(class, section_id) => { + mag.change_owner(*class, *section_id) + }, + mag::MagModifier::MagCell(mag_cell_id) => { + if let Some(mag_cell) = items.get(mag_cell_id) { + if let ItemDetail::Tool(mag_cell) = mag_cell.item { + mag.apply_mag_cell(mag_cell.tool.try_into().unwrap()).unwrap() } - }, - _ => {} - } + } + }, + _ => {} } } - ItemDetail::Mag(mag) } - _ => { - item.item - } - }; - - item - }) + ItemDetail::Mag(mag) + } + _ => { + item.item + } + }; + + item }) - .collect(); - InventoryEntity::new(inventory_items) - } + }) + .collect(); + InventoryEntity::new(inventory_items) } #[async_trait::async_trait] @@ -159,18 +301,18 @@ impl EntityGateway for InMemoryGateway { async fn transaction<'a>(&'a mut self) -> Result, GatewayError> { let working_gateway = { - let users = self.users.lock().unwrap().clone(); - let user_settings = self.user_settings.lock().unwrap().clone(); - let characters = self.characters.lock().unwrap().clone(); - let character_meseta = self.character_meseta.lock().unwrap().clone(); - let bank_meseta = self.bank_meseta.lock().unwrap().clone(); - let items = self.items.lock().unwrap().clone(); - let inventories = self.inventories.lock().unwrap().clone(); - let banks = self.banks.lock().unwrap().clone(); - let equips = self.equips.lock().unwrap().clone(); - let mag_modifiers = self.mag_modifiers.lock().unwrap().clone(); - let weapon_modifiers = self.weapon_modifiers.lock().unwrap().clone(); - let trades = self.trades.lock().unwrap().clone(); + let users = self.users.lock().await.clone(); + let user_settings = self.user_settings.lock().await.clone(); + let characters = self.characters.lock().await.clone(); + let character_meseta = self.character_meseta.lock().await.clone(); + let bank_meseta = self.bank_meseta.lock().await.clone(); + let items = self.items.lock().await.clone(); + let inventories = self.inventories.lock().await.clone(); + let banks = self.banks.lock().await.clone(); + let equips = self.equips.lock().await.clone(); + let mag_modifiers = self.mag_modifiers.lock().await.clone(); + let weapon_modifiers = self.weapon_modifiers.lock().await.clone(); + let trades = self.trades.lock().await.clone(); InMemoryGateway { users: Arc::new(Mutex::new(users)), @@ -202,18 +344,18 @@ impl EntityGateway for InMemoryGateway { R: Send, E: From, { - let users = self.users.lock().unwrap().clone(); - let user_settings = self.user_settings.lock().unwrap().clone(); - let characters = self.characters.lock().unwrap().clone(); - let character_meseta = self.character_meseta.lock().unwrap().clone(); - let bank_meseta = self.bank_meseta.lock().unwrap().clone(); - let items = self.items.lock().unwrap().clone(); - let inventories = self.inventories.lock().unwrap().clone(); - let banks = self.banks.lock().unwrap().clone(); - let equips = self.equips.lock().unwrap().clone(); - let mag_modifiers = self.mag_modifiers.lock().unwrap().clone(); - let weapon_modifiers = self.weapon_modifiers.lock().unwrap().clone(); - let trades = self.trades.lock().unwrap().clone(); + let users = self.users.lock().await.clone(); + let user_settings = self.user_settings.lock().await.clone(); + let characters = self.characters.lock().await.clone(); + let character_meseta = self.character_meseta.lock().await.clone(); + let bank_meseta = self.bank_meseta.lock().await.clone(); + let items = self.items.lock().await.clone(); + let inventories = self.inventories.lock().await.clone(); + let banks = self.banks.lock().await.clone(); + let equips = self.equips.lock().await.clone(); + let mag_modifiers = self.mag_modifiers.lock().await.clone(); + let weapon_modifiers = self.weapon_modifiers.lock().await.clone(); + let trades = self.trades.lock().await.clone(); let working_gateway = InMemoryGateway { users: Arc::new(Mutex::new(users)), @@ -242,7 +384,7 @@ impl EntityGateway for InMemoryGateway { } async fn create_user(&mut self, user: NewUserAccountEntity) -> Result { - let mut users = self.users.lock().unwrap(); + let mut users = self.users.lock().await; let id = users .iter() .fold(0, |sum, (i, _)| std::cmp::max(sum, i.0)) @@ -267,12 +409,12 @@ impl EntityGateway for InMemoryGateway { } async fn get_user_by_id(&mut self, id: UserAccountId) -> Result { - let users = self.users.lock().unwrap(); + let users = self.users.lock().await; users.get(&id).cloned().ok_or(GatewayError::Error) } async fn get_user_by_name(&mut self, username: String) -> Result { - let users = self.users.lock().unwrap(); + let users = self.users.lock().await; users .iter() .find(|(_, k)| k.username == username) @@ -281,13 +423,13 @@ impl EntityGateway for InMemoryGateway { } async fn save_user(&mut self, user: &UserAccountEntity) -> Result<(), GatewayError> { - let mut users = self.users.lock().unwrap(); + let mut users = self.users.lock().await; users.insert(user.id, user.clone()); Ok(()) } async fn create_user_settings(&mut self, settings: NewUserSettingsEntity) -> Result { - let mut user_settings = self.user_settings.lock().unwrap(); + let mut user_settings = self.user_settings.lock().await; let id = user_settings .iter() .fold(0, |sum, (i, _)| std::cmp::max(sum, i.0)) @@ -302,7 +444,7 @@ impl EntityGateway for InMemoryGateway { } async fn get_user_settings_by_user(&mut self, user: &UserAccountEntity) -> Result { - let user_settings = self.user_settings.lock().unwrap(); + let user_settings = self.user_settings.lock().await; user_settings .iter() .find(|(_, k)| k.user_id == user.id) @@ -311,7 +453,7 @@ impl EntityGateway for InMemoryGateway { } async fn get_characters_by_user(&mut self, user: &UserAccountEntity) -> Result<[Option; 4], GatewayError> { - let characters = self.characters.lock().unwrap(); + let characters = self.characters.lock().await; const NONE: Option = None; let mut chars = [NONE; 4]; characters @@ -322,7 +464,7 @@ impl EntityGateway for InMemoryGateway { } async fn create_character(&mut self, character: NewCharacterEntity) -> Result { - let mut characters = self.characters.lock().unwrap(); + let mut characters = self.characters.lock().await; let id = characters .iter() .fold(0, |sum, (i, _)| std::cmp::max(sum, i.0)) @@ -353,7 +495,7 @@ impl EntityGateway for InMemoryGateway { } async fn save_character(&mut self, char: &CharacterEntity) -> Result<(), GatewayError> { - let mut characters = self.characters.lock().unwrap(); + let mut characters = self.characters.lock().await; characters.insert(char.id, char.clone()); Ok(()) } @@ -363,7 +505,7 @@ impl EntityGateway for InMemoryGateway { } async fn create_item(&mut self, item: NewItemEntity) -> Result { - let mut items = self.items.lock().unwrap(); + let mut items = self.items.lock().await; let id = items .iter() .fold(0, |sum, (i, _)| std::cmp::max(sum, i.0)) @@ -381,7 +523,7 @@ impl EntityGateway for InMemoryGateway { } async fn feed_mag(&mut self, mag_item_id: &ItemEntityId, tool_item_id: &ItemEntityId) -> Result<(), GatewayError> { - self.mag_modifiers.lock().unwrap() + self.mag_modifiers.lock().await .entry(*mag_item_id) .or_insert_with(Vec::new) .push(mag::MagModifier::FeedMag { @@ -391,7 +533,7 @@ impl EntityGateway for InMemoryGateway { } async fn change_mag_owner(&mut self, mag_item_id: &ItemEntityId, character: &CharacterEntity) -> Result<(), GatewayError> { - self.mag_modifiers.lock().unwrap() + self.mag_modifiers.lock().await .entry(*mag_item_id) .or_insert_with(Vec::new) .push(mag::MagModifier::OwnerChange(character.char_class, character.section_id)); @@ -399,7 +541,7 @@ impl EntityGateway for InMemoryGateway { } async fn use_mag_cell(&mut self, mag_item_id: &ItemEntityId, mag_cell_id: &ItemEntityId) -> Result<(), GatewayError> { - self.mag_modifiers.lock().unwrap() + self.mag_modifiers.lock().await .entry(*mag_item_id) .or_insert_with(Vec::new) .push(mag::MagModifier::MagCell(*mag_cell_id)); @@ -407,7 +549,7 @@ impl EntityGateway for InMemoryGateway { } async fn add_weapon_modifier(&mut self, item_id: &ItemEntityId, modifier: weapon::WeaponModifier) -> Result<(), GatewayError> { - self.weapon_modifiers.lock().unwrap() + self.weapon_modifiers.lock().await .entry(*item_id) .or_insert_with(Vec::new) .push(modifier); @@ -415,17 +557,20 @@ impl EntityGateway for InMemoryGateway { } async fn get_character_inventory(&mut self, char_id: &CharacterEntityId) -> Result { - let inventories = self.inventories.lock().unwrap(); + let inventories = self.inventories.lock().await; + let items = self.items.lock().await; + let weapon_modifiers = self.weapon_modifiers.lock().await; + let mag_modifiers = self.mag_modifiers.lock().await; Ok(inventories .iter() .find(|(id, _)| **id == *char_id) .map(|(_, inv)| inv.clone()) - .map(|inv| self.apply_modifiers(inv)) + .map(|inv| apply_modifiers(&items, &weapon_modifiers, &mag_modifiers, inv)) .unwrap_or_default()) } async fn get_character_bank(&mut self, char_id: &CharacterEntityId, _bank_name: &BankName) -> Result { - let banks = self.banks.lock().unwrap(); + let banks = self.banks.lock().await; Ok(banks .iter() .find(|(id, _)| **id == *char_id) @@ -434,20 +579,20 @@ impl EntityGateway for InMemoryGateway { } async fn set_character_inventory(&mut self, char_id: &CharacterEntityId, inventory: &InventoryEntity) -> Result<(), GatewayError> { - let mut inventories = self.inventories.lock().unwrap(); + let mut inventories = self.inventories.lock().await; inventories.insert(*char_id, inventory.clone()); Ok(()) } // TOOD: impl bank name async fn set_character_bank(&mut self, char_id: &CharacterEntityId, bank: &BankEntity, _bank_name: &BankName) -> Result<(), GatewayError> { - let mut banks = self.banks.lock().unwrap(); + let mut banks = self.banks.lock().await; banks.insert(*char_id, bank.clone()); Ok(()) } async fn get_character_equips(&mut self, char_id: &CharacterEntityId) -> Result { - let equips = self.equips.lock().unwrap(); + let equips = self.equips.lock().await; Ok(equips .iter() .find(|(id, _)| **id == *char_id) @@ -456,19 +601,19 @@ impl EntityGateway for InMemoryGateway { } async fn set_character_equips(&mut self, char_id: &CharacterEntityId, equipped: &EquippedEntity) -> Result<(), GatewayError> { - let mut equips = self.equips.lock().unwrap(); + let mut equips = self.equips.lock().await; equips.insert(*char_id, equipped.clone()); Ok(()) } async fn set_character_meseta(&mut self, char_id: &CharacterEntityId, meseta: Meseta) -> Result<(), GatewayError> { - let mut character_meseta = self.character_meseta.lock().unwrap(); + let mut character_meseta = self.character_meseta.lock().await; character_meseta.insert(*char_id, meseta); Ok(()) } async fn get_character_meseta(&mut self, char_id: &CharacterEntityId) -> Result { - let mut character_meseta = self.character_meseta.lock().unwrap(); + let mut character_meseta = self.character_meseta.lock().await; if let Some(meseta) = character_meseta.get_mut(char_id) { Ok(*meseta) } @@ -478,13 +623,13 @@ impl EntityGateway for InMemoryGateway { } async fn set_bank_meseta(&mut self, char_id: &CharacterEntityId, bank: &BankName, meseta: Meseta) -> Result<(), GatewayError> { - let mut bank_meseta = self.bank_meseta.lock().unwrap(); + let mut bank_meseta = self.bank_meseta.lock().await; bank_meseta.insert((*char_id, bank.clone()), meseta); Ok(()) } async fn get_bank_meseta(&mut self, char_id: &CharacterEntityId, bank: &BankName) -> Result { - let mut bank_meseta = self.bank_meseta.lock().unwrap(); + let mut bank_meseta = self.bank_meseta.lock().await; if let Some(meseta) = bank_meseta.get_mut(&(*char_id, bank.clone())) { Ok(*meseta) } @@ -494,7 +639,7 @@ impl EntityGateway for InMemoryGateway { } async fn create_trade(&mut self, char_id1: &CharacterEntityId, char_id2: &CharacterEntityId) -> Result { - let mut trades = self.trades.lock().unwrap(); + let mut trades = self.trades.lock().await; let id = trades.len() as u32; let new_trade = TradeEntity { id: TradeId(id), @@ -506,7 +651,7 @@ impl EntityGateway for InMemoryGateway { } async fn set_character_playtime(&mut self, char_id: &CharacterEntityId, playtime: u32) -> Result<(), GatewayError> { - let mut characters = self.characters.lock().unwrap(); + let mut characters = self.characters.lock().await; if let Some(character) = characters.get_mut(char_id) { character.playtime = playtime; Ok(()) From 16a46533600f488cb3cec319224c8acf8db91ca3 Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 30 Jul 2022 15:02:18 -0600 Subject: [PATCH 2/3] pass EntityGateway clones rather than letting functions borrow --- src/common/mainloop/interserver.rs | 4 +- src/common/mainloop/mod.rs | 6 +-- src/ship/packet/handler/auth.rs | 6 +-- src/ship/packet/handler/communication.rs | 2 +- src/ship/packet/handler/direct_message.rs | 49 ++++++----------- src/ship/packet/handler/lobby.rs | 4 +- src/ship/packet/handler/message.rs | 44 +++++++-------- src/ship/packet/handler/settings.rs | 10 ++-- src/ship/packet/handler/trade.rs | 4 +- src/ship/ship.rs | 66 +++++++++++------------ tests/common.rs | 14 ++--- tests/test_trade.rs | 6 +-- 12 files changed, 100 insertions(+), 115 deletions(-) diff --git a/src/common/mainloop/interserver.rs b/src/common/mainloop/interserver.rs index 3547f8b..ce1cb66 100644 --- a/src/common/mainloop/interserver.rs +++ b/src/common/mainloop/interserver.rs @@ -180,7 +180,7 @@ where -pub fn login_listen_mainloop(state: Arc>>, port: u16) -> Pin>> { +pub fn login_listen_mainloop(state: Arc>>, port: u16) -> Pin>> { Box::pin(async_std::task::spawn(async move { let listener = async_std::net::TcpListener::bind(&std::net::SocketAddr::from((std::net::Ipv4Addr::new(0,0,0,0), port))).await.unwrap(); let mut id = 0; @@ -210,7 +210,7 @@ pub fn login_listen_mainloop(state: Arc(state: Arc>>, ip: std::net::Ipv4Addr, port: u16) -> Pin>> { +pub fn ship_connect_mainloop(state: Arc>>, ip: std::net::Ipv4Addr, port: u16) -> Pin>> { Box::pin(async_std::task::spawn(async move { let mut id = 0; let (server_state_sender, server_state_receiver) = async_std::channel::bounded(1024); diff --git a/src/common/mainloop/mod.rs b/src/common/mainloop/mod.rs index 2a5b3ff..5e84d09 100644 --- a/src/common/mainloop/mod.rs +++ b/src/common/mainloop/mod.rs @@ -23,13 +23,13 @@ pub fn patch_mainloop(patch_state: PatchServerState, patch_port: u16) -> Pin(login_state: LoginServerState, login_port: u16) -> Pin>> { +pub fn login_mainloop(login_state: LoginServerState, login_port: u16) -> Pin>> { let login_state = Arc::new(Mutex::new(login_state)); let client_mainloop = client_accept_mainloop(login_state, login_port); Box::pin(client_mainloop) } -pub fn character_mainloop(character_state: CharacterServerState, character_port: u16, comm_port: u16) -> Pin>> { +pub fn character_mainloop(character_state: CharacterServerState, character_port: u16, comm_port: u16) -> Pin>> { let character_state = Arc::new(Mutex::new(character_state)); let client_mainloop = client_accept_mainloop(character_state.clone(), character_port); let ship_communication_mainloop = login_listen_mainloop(character_state, comm_port); @@ -37,7 +37,7 @@ pub fn character_mainloop(character_state: Characte } -pub fn ship_mainloop(ship_state: ShipServerState, ship_port: u16, comm_ip: std::net::Ipv4Addr, comm_port: u16) -> Pin>> { +pub fn ship_mainloop(ship_state: ShipServerState, ship_port: u16, comm_ip: std::net::Ipv4Addr, comm_port: u16) -> Pin>> { let ship_state = Arc::new(Mutex::new(ship_state)); let client_mainloop = client_accept_mainloop(ship_state.clone(), ship_port); let login_communication_mainloop = ship_connect_mainloop(ship_state, comm_ip, comm_port); diff --git a/src/ship/packet/handler/auth.rs b/src/ship/packet/handler/auth.rs index 50be751..e3ca60b 100644 --- a/src/ship/packet/handler/auth.rs +++ b/src/ship/packet/handler/auth.rs @@ -10,14 +10,14 @@ use crate::common::interserver::ShipMessage; #[allow(clippy::too_many_arguments)] pub async fn validate_login(id: ClientId, pkt: &Login, - entity_gateway: &mut EG, + mut entity_gateway: EG, clients: &mut Clients, item_state: &mut ItemState, shipgate_sender: &Option>, ship_name: &str, num_blocks: usize) -> Result, anyhow::Error> { - Ok(match get_login_status(entity_gateway, pkt).await { + Ok(match get_login_status(&mut entity_gateway, pkt).await { Ok(user) => { let mut response = LoginResponse::by_status(AccountStatus::Ok, Session::new()); response.guildcard = user.id.0 as u32; @@ -30,7 +30,7 @@ pub async fn validate_login(id: ClientId, .clone(); let settings = entity_gateway.get_user_settings_by_user(&user).await?; - item_state.load_character(entity_gateway, &character).await?; + item_state.load_character(&mut entity_gateway, &character).await?; if let Some(shipgate_sender) = shipgate_sender.as_ref() { shipgate_sender(ShipMessage::AddUser(user.id)); diff --git a/src/ship/packet/handler/communication.rs b/src/ship/packet/handler/communication.rs index 087913b..c8942ec 100644 --- a/src/ship/packet/handler/communication.rs +++ b/src/ship/packet/handler/communication.rs @@ -38,7 +38,7 @@ pub fn request_infoboard(id: ClientId, pub async fn write_infoboard(id: ClientId, new_infoboard: &WriteInfoboard, clients: &mut Clients, - entity_gateway: &mut EG) + mut entity_gateway: EG) -> Box + Send> { let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); client.character.info_board.update_infoboard(new_infoboard); diff --git a/src/ship/packet/handler/direct_message.rs b/src/ship/packet/handler/direct_message.rs index 4861b7b..1e196d5 100644 --- a/src/ship/packet/handler/direct_message.rs +++ b/src/ship/packet/handler/direct_message.rs @@ -70,7 +70,7 @@ pub fn guildcard_send(id: ClientId, pub async fn request_item(id: ClientId, request_item: &RequestItem, - entity_gateway: &mut EG, + mut entity_gateway: EG, client_location: &ClientLocation, clients: &mut Clients, rooms: &mut Rooms, @@ -109,7 +109,7 @@ where item: item_drop, }; let client = clients.get_mut(&area_client.client).ok_or(ShipError::ClientNotFound(area_client.client))?; - let floor_item = enemy_drops_item(item_state, entity_gateway, client.character.id, item_drop).await?; + let floor_item = enemy_drops_item(item_state, &mut entity_gateway, client.character.id, item_drop).await?; let item_drop_msg = builder::message::item_drop(request_item.client, request_item.target, &floor_item)?; item_drop_packets.push((area_client.client, SendShipPacket::Message(Message::new(GameMessage::ItemDrop(item_drop_msg))))); @@ -120,7 +120,7 @@ where pub async fn pickup_item(id: ClientId, pickup_item: &PickupItem, - entity_gateway: &mut EG, + mut entity_gateway: EG, client_location: &ClientLocation, clients: &mut Clients, item_state: &mut ItemState) @@ -133,30 +133,15 @@ where let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; let clients_in_area = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?; - // TODO: should not need to fetch the item here to construct this packet - //let (item, floor_type) = item_manager.get_floor_item_by_id(&client.character, ClientItemId(pickup_item.item_id))?; - /* - let (item, floor_type) = item_state.get_floor_item(&client.character, &ClientItemId(pickup_item.item_id))?; - let remove_item = builder::message::remove_item_from_floor(area_client, item)?; - let create_item = match item { - FloorItem::Individual(individual_floor_item) => Some(builder::message::create_individual_item(area_client, item.item_id(), &individual_floor_item.item)?), - FloorItem::Stacked(stacked_floor_item) => Some(builder::message::create_stacked_item(area_client, item.item_id(), &stacked_floor_item.tool, stacked_floor_item.count())?), - FloorItem::Meseta(_) => None, - //_ => Some(builder::message::create_item(area_client, &item)?), - }; - */ - let (item, floor_type) = item_state.get_floor_item(&client.character.id, &ClientItemId(pickup_item.item_id))?; let remove_item = builder::message::remove_item_from_floor(area_client, item)?; let create_item = match &item.item { FloorItemDetail::Individual(individual_floor_item) => Some(builder::message::create_individual_item(area_client, item.item_id, individual_floor_item)?), FloorItemDetail::Stacked(stacked_floor_item) => Some(builder::message::create_stacked_item(area_client, item.item_id, &stacked_floor_item.tool, stacked_floor_item.count())?), FloorItemDetail::Meseta(_) => None, - //_ => Some(builder::message::create_item(area_client, &item)?), }; - //match item_manager.character_picks_up_item(entity_gateway, &mut client.character, ClientItemId(pickup_item.item_id)).await { - match pick_up_item(item_state, entity_gateway, &client.character, &ClientItemId(pickup_item.item_id)).await { + match pick_up_item(item_state, &mut entity_gateway, &client.character, &ClientItemId(pickup_item.item_id)).await { Ok(trigger_create_item) => { let remove_packets: Box + Send> = match floor_type { FloorType::Local => { @@ -189,7 +174,7 @@ where pub async fn request_box_item(id: ClientId, box_drop_request: &BoxDropRequest, - entity_gateway: &mut EG, + mut entity_gateway: EG, client_location: &ClientLocation, clients: &mut Clients, rooms: &mut Rooms, @@ -228,7 +213,7 @@ EG: EntityGateway item: item_drop, }; let client = clients.get_mut(&area_client.client).ok_or(ShipError::ClientNotFound(area_client.client))?; - let floor_item = enemy_drops_item(item_state, entity_gateway, client.character.id, item_drop).await?; + let floor_item = enemy_drops_item(item_state, &mut entity_gateway, client.character.id, item_drop).await?; let item_drop_msg = builder::message::item_drop(box_drop_request.client, box_drop_request.target, &floor_item)?; item_drop_packets.push((area_client.client, SendShipPacket::Message(Message::new(GameMessage::ItemDrop(item_drop_msg))))) } @@ -251,7 +236,7 @@ pub async fn send_bank_list(id: ClientId, pub async fn bank_interaction(id: ClientId, bank_interaction: &BankInteraction, - entity_gateway: &mut EG, + mut entity_gateway: EG, client_location: &ClientLocation, clients: &mut Clients, item_state: &mut ItemState) @@ -265,22 +250,22 @@ where let bank_action_pkts = match bank_interaction.action { BANK_ACTION_DEPOSIT => { if bank_interaction.item_id == 0xFFFFFFFF { - deposit_meseta(item_state, entity_gateway, &client.character, bank_interaction.meseta_amount).await?; + deposit_meseta(item_state, &mut entity_gateway, &client.character, bank_interaction.meseta_amount).await?; Vec::new() } else { - deposit_item(item_state, entity_gateway, &client.character, &ClientItemId(bank_interaction.item_id), bank_interaction.item_amount as u32).await?; + deposit_item(item_state, &mut entity_gateway, &client.character, &ClientItemId(bank_interaction.item_id), bank_interaction.item_amount as u32).await?; let player_no_longer_has_item = builder::message::player_no_longer_has_item(area_client, ClientItemId(bank_interaction.item_id), bank_interaction.item_amount as u32); vec![SendShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(player_no_longer_has_item)))] } }, BANK_ACTION_WITHDRAW => { if bank_interaction.item_id == 0xFFFFFFFF { - withdraw_meseta(item_state, entity_gateway, &client.character, bank_interaction.meseta_amount).await?; + withdraw_meseta(item_state, &mut entity_gateway, &client.character, bank_interaction.meseta_amount).await?; Vec::new() } else { - let item_added_to_inventory = withdraw_item(item_state, entity_gateway, &client.character, &ClientItemId(bank_interaction.item_id), bank_interaction.item_amount as u32).await?; + let item_added_to_inventory = withdraw_item(item_state, &mut entity_gateway, &client.character, &ClientItemId(bank_interaction.item_id), bank_interaction.item_amount as u32).await?; let item_created = builder::message::create_withdrawn_inventory_item2(area_client, &item_added_to_inventory)?; vec![SendShipPacket::Message(Message::new(GameMessage::CreateItem(item_created)))] } @@ -342,7 +327,7 @@ pub async fn shop_request(id: ClientId, pub async fn buy_item(id: ClientId, buy_item: &BuyItem, - entity_gateway: &mut EG, + mut entity_gateway: EG, client_location: &ClientLocation, clients: &mut Clients, item_state: &mut ItemState) @@ -372,7 +357,7 @@ where } }; - let inventory_item = buy_shop_item(item_state, entity_gateway, &client.character, item, ClientItemId(buy_item.item_id), buy_item.amount as u32).await?; + let inventory_item = buy_shop_item(item_state, &mut entity_gateway, &client.character, item, ClientItemId(buy_item.item_id), buy_item.amount as u32).await?; let create = builder::message::create_withdrawn_inventory_item(area_client, &inventory_item)?; if remove { @@ -407,7 +392,7 @@ const TEK_PERCENT_MODIFIER: [item::weapon::TekPercentModifier; 5] = [item::weapo pub async fn request_tek_item(id: ClientId, tek_request: &TekRequest, - entity_gateway: &mut EG, + mut entity_gateway: EG, clients: &mut Clients, item_state: &mut ItemState) -> Result + Send>, anyhow::Error> @@ -441,7 +426,7 @@ where grind: grind_mod, }); - take_meseta(item_state, entity_gateway, &client.character.id, item::Meseta(100)).await?; + take_meseta(item_state, &mut entity_gateway, &client.character.id, item::Meseta(100)).await?; let preview_pkt = builder::message::tek_preview(ClientItemId(tek_request.item_id), &weapon)?; @@ -450,7 +435,7 @@ where pub async fn accept_tek_item(id: ClientId, tek_accept: &TekAccept, - entity_gateway: &mut EG, + mut entity_gateway: EG, client_location: &ClientLocation, clients: &mut Clients, item_state: &mut ItemState) @@ -471,7 +456,7 @@ where percent: percent_mod, grind: grind_mod, }; - let weapon = apply_modifier(item_state, entity_gateway, &client.character, item_id, item::ItemModifier::WeaponModifier(modifier)).await?; + let weapon = apply_modifier(item_state, &mut entity_gateway, &client.character, item_id, item::ItemModifier::WeaponModifier(modifier)).await?; let create_item_pkt = builder::message::create_individual_item(area_client, item_id, &weapon)?; diff --git a/src/ship/packet/handler/lobby.rs b/src/ship/packet/handler/lobby.rs index 2e1625c..fcbff40 100644 --- a/src/ship/packet/handler/lobby.rs +++ b/src/ship/packet/handler/lobby.rs @@ -72,7 +72,7 @@ pub async fn change_lobby(id: ClientId, item_state: &mut ItemState, level_table: &CharacterLevelTable, ship_rooms: &mut Rooms, - entity_gateway: &mut EG) + mut entity_gateway: EG) -> Result, anyhow::Error> { let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; let prev_area = client_location.get_area(id).map_err(|err| -> ClientLocationError {err.into()})?; @@ -103,7 +103,7 @@ pub async fn change_lobby(id: ClientId, } } } - item_state.load_character(entity_gateway, &client.character).await?; + item_state.load_character(&mut entity_gateway, &client.character).await?; let join_lobby = packet::builder::lobby::join_lobby(id, lobby, client_location, clients, item_state, level_table)?; let addto = packet::builder::lobby::add_to_lobby(id, lobby, client_location, clients, item_state, level_table)?; let neighbors = client_location.get_client_neighbors(id).unwrap(); diff --git a/src/ship/packet/handler/message.rs b/src/ship/packet/handler/message.rs index d0d4f44..456ed7d 100644 --- a/src/ship/packet/handler/message.rs +++ b/src/ship/packet/handler/message.rs @@ -13,7 +13,7 @@ use crate::ship::items::tasks::{drop_item, drop_partial_item, drop_meseta, equip pub async fn request_exp(id: ClientId, request_exp: &RequestExp, - entity_gateway: &mut EG, + mut entity_gateway: EG, client_location: &ClientLocation, clients: &mut Clients, rooms: &mut Rooms, @@ -67,7 +67,7 @@ pub async fn request_exp(id: ClientId, pub async fn player_drop_item(id: ClientId, player_drop_item: &PlayerDropItem, - entity_gateway: &mut EG, + mut entity_gateway: EG, client_location: &ClientLocation, clients: &mut Clients, rooms: &mut Rooms, @@ -83,7 +83,7 @@ where .as_mut() .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; let area = room.map_areas.get_area_map(player_drop_item.map_area)?; - drop_item(item_state, entity_gateway, &client.character, &ClientItemId(player_drop_item.item_id), *area, (player_drop_item.x, player_drop_item.y, player_drop_item.z)).await?; + drop_item(item_state, &mut entity_gateway, &client.character, &ClientItemId(player_drop_item.item_id), *area, (player_drop_item.x, player_drop_item.y, player_drop_item.z)).await?; let clients_in_area = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?; let pdi = player_drop_item.clone(); Ok(Box::new(clients_in_area.into_iter() @@ -118,7 +118,7 @@ pub fn drop_coordinates(id: ClientId, pub async fn no_longer_has_item(id: ClientId, no_longer_has_item: &PlayerNoLongerHasItem, - entity_gateway: &mut EG, + mut entity_gateway: EG, client_location: &ClientLocation, clients: &mut Clients, item_state: &mut ItemState) @@ -135,7 +135,7 @@ where } if no_longer_has_item.item_id == 0xFFFFFFFF { - let dropped_meseta = drop_meseta(item_state, entity_gateway, &client.character, drop_location.map_area, (drop_location.x, drop_location.z), no_longer_has_item.amount).await?; + let dropped_meseta = drop_meseta(item_state, &mut entity_gateway, &client.character, drop_location.map_area, (drop_location.x, drop_location.z), no_longer_has_item.amount).await?; let dropped_meseta_pkt = builder::message::drop_split_meseta_stack(area_client, &dropped_meseta)?; let no_longer_has_meseta_pkt = builder::message::player_no_longer_has_meseta(area_client, no_longer_has_item.amount as u32); @@ -159,7 +159,7 @@ where )) } else { - let dropped_item = drop_partial_item(item_state, entity_gateway, &client.character, &drop_location.item_id, drop_location.map_area, (drop_location.x, drop_location.z), no_longer_has_item.amount).await?; + let dropped_item = drop_partial_item(item_state, &mut entity_gateway, &client.character, &drop_location.item_id, drop_location.map_area, (drop_location.x, drop_location.z), no_longer_has_item.amount).await?; let dropped_item_pkt = builder::message::drop_split_stack(area_client, &dropped_item)?; client.item_drop_location = None; @@ -259,7 +259,7 @@ pub fn update_player_position(id: ClientId, pub async fn charge_attack(id: ClientId, charge: &ChargeAttack, - entity_gateway: &mut EG, + mut entity_gateway: EG, client_location: &ClientLocation, clients: &mut Clients, item_state: &mut ItemState) @@ -270,7 +270,7 @@ where let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; // TODO: should probably validate this to be a legit number, I'd just hardcode 200 but vjaya - take_meseta(item_state, entity_gateway, &client.character.id, Meseta(charge.meseta)).await?; + take_meseta(item_state, &mut entity_gateway, &client.character.id, Meseta(charge.meseta)).await?; let charge = charge.clone(); Ok(Box::new(client_location.get_client_neighbors(id).unwrap().into_iter() @@ -281,7 +281,7 @@ where pub async fn player_uses_item(id: ClientId, player_use_tool: &PlayerUseItem, - entity_gateway: &mut EG, + mut entity_gateway: EG, _client_location: &ClientLocation, clients: &mut Clients, item_state: &mut ItemState) @@ -290,13 +290,13 @@ where EG: EntityGateway { let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - use_item(item_state, entity_gateway, &mut client.character, &ClientItemId(player_use_tool.item_id), 1).await?; + use_item(item_state, &mut entity_gateway, &mut client.character, &ClientItemId(player_use_tool.item_id), 1).await?; Ok(Box::new(None.into_iter())) // TODO: should probably tell other players we used an item } pub async fn player_used_medical_center(id: ClientId, pumc: &PlayerUsedMedicalCenter, - entity_gateway: &mut EG, + mut entity_gateway: EG, client_location: &ClientLocation, clients: &mut Clients, item_state: &mut ItemState) @@ -306,7 +306,7 @@ where { let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - take_meseta(item_state, entity_gateway, &client.character.id, Meseta(10)).await?; + take_meseta(item_state, &mut entity_gateway, &client.character.id, Meseta(10)).await?; let pumc = pumc.clone(); Ok(Box::new(client_location.get_client_neighbors(id).unwrap().into_iter() @@ -318,7 +318,7 @@ where pub async fn player_feed_mag(id: ClientId, mag_feed: &PlayerFeedMag, - entity_gateway: &mut EG, + mut entity_gateway: EG, client_location: &ClientLocation, clients: &Clients, item_state: &mut ItemState) @@ -327,7 +327,7 @@ where EG: EntityGateway { let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; - feed_mag(item_state, entity_gateway, &client.character, &ClientItemId(mag_feed.mag_id), &ClientItemId(mag_feed.item_id)).await?; + feed_mag(item_state, &mut entity_gateway, &client.character, &ClientItemId(mag_feed.mag_id), &ClientItemId(mag_feed.item_id)).await?; let mag_feed = mag_feed.clone(); Ok(Box::new(client_location.get_client_neighbors(id).unwrap().into_iter() @@ -338,7 +338,7 @@ where pub async fn player_equips_item(id: ClientId, pkt: &PlayerEquipItem, - entity_gateway: &mut EG, + mut entity_gateway: EG, clients: &Clients, item_state: &mut ItemState) -> Result + Send>, anyhow::Error> @@ -352,13 +352,13 @@ where else { 0 }; - equip_item(item_state, entity_gateway, &client.character, &ClientItemId(pkt.item_id), equip_slot).await?; + equip_item(item_state, &mut entity_gateway, &client.character, &ClientItemId(pkt.item_id), equip_slot).await?; Ok(Box::new(None.into_iter())) // TODO: tell other players you equipped an item } pub async fn player_unequips_item(id: ClientId, pkt: &PlayerUnequipItem, - entity_gateway: &mut EG, + mut entity_gateway: EG, clients: &Clients, item_state: &mut ItemState) -> Result + Send>, anyhow::Error> @@ -366,13 +366,13 @@ where EG: EntityGateway { let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; - unequip_item(item_state, entity_gateway, &client.character, &ClientItemId(pkt.item_id)).await?; + unequip_item(item_state, &mut entity_gateway, &client.character, &ClientItemId(pkt.item_id)).await?; Ok(Box::new(None.into_iter())) // TODO: tell other players if you unequip an item } pub async fn player_sorts_items(id: ClientId, pkt: &SortItems, - entity_gateway: &mut EG, + mut entity_gateway: EG, clients: &Clients, item_state: &mut ItemState) -> Result + Send>, anyhow::Error> @@ -391,13 +391,13 @@ where } }) .collect(); - sort_inventory(item_state, entity_gateway, &client.character, item_ids).await?; + sort_inventory(item_state, &mut entity_gateway, &client.character, item_ids).await?; Ok(Box::new(None.into_iter())) // TODO: clients probably care about each others item orders } pub async fn player_sells_item (id: ClientId, sold_item: &PlayerSoldItem, - entity_gateway: &mut EG, + mut entity_gateway: EG, clients: &mut Clients, item_state: &mut ItemState) -> Result + Send>, anyhow::Error> @@ -405,7 +405,7 @@ where EG: EntityGateway { let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - sell_item(item_state, entity_gateway, &client.character, ClientItemId(sold_item.item_id), sold_item.amount as u32).await?; + sell_item(item_state, &mut entity_gateway, &client.character, ClientItemId(sold_item.item_id), sold_item.amount as u32).await?; // TODO: send the packet to other clients Ok(Box::new(None.into_iter())) } diff --git a/src/ship/packet/handler/settings.rs b/src/ship/packet/handler/settings.rs index 17d0d64..52b0e8f 100644 --- a/src/ship/packet/handler/settings.rs +++ b/src/ship/packet/handler/settings.rs @@ -6,7 +6,7 @@ use crate::entity::gateway::EntityGateway; pub async fn update_config(id: ClientId, update_config: &UpdateConfig, clients: &mut Clients, - entity_gateway: &mut EG) + mut entity_gateway: EG) -> Box + Send> { let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); client.character.config.update(update_config); @@ -17,7 +17,7 @@ pub async fn update_config(id: ClientId, pub async fn save_options(id: ClientId, save_options: &SaveOptions, clients: &mut Clients, - entity_gateway: &mut EG) + mut entity_gateway: EG) -> Box + Send> { // TODO: don't unwrap? let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); @@ -29,7 +29,7 @@ pub async fn save_options(id: ClientId, pub async fn keyboard_config(id: ClientId, keyboard_config: &KeyboardConfig, clients: &mut Clients, - entity_gateway: &mut EG) + mut entity_gateway: EG) -> Box + Send> { let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); client.character.keyboard_config.update(keyboard_config); @@ -40,10 +40,10 @@ pub async fn keyboard_config(id: ClientId, pub async fn gamepad_config(id: ClientId, gamepad_config: &GamepadConfig, clients: &mut Clients, - entity_gateway: &mut EG) + mut entity_gateway: EG) -> Box + Send> { let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); client.character.gamepad_config.update(gamepad_config); entity_gateway.save_character(&client.character).await.unwrap(); Box::new(None.into_iter()) -} \ No newline at end of file +} diff --git a/src/ship/packet/handler/trade.rs b/src/ship/packet/handler/trade.rs index 7b01ed6..465b76d 100644 --- a/src/ship/packet/handler/trade.rs +++ b/src/ship/packet/handler/trade.rs @@ -429,7 +429,7 @@ pub async fn items_to_trade(id: ClientId, } pub async fn trade_confirmed(id: ClientId, - entity_gateway: &mut EG, + mut entity_gateway: EG, client_location: &ClientLocation, clients: &mut Clients, item_state: &mut ItemState, @@ -493,7 +493,7 @@ where }); let (this_new_items, other_new_items) = trade_items(item_state, - entity_gateway, + &mut entity_gateway, (&this_local_client, &this_client.character, &this.items, Meseta(this.meseta as u32)), (&other_local_client, &other_client.character, &other.items, Meseta(other.meseta as u32))).await?; diff --git a/src/ship/ship.rs b/src/ship/ship.rs index 754ea7c..42bd0e5 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -373,7 +373,7 @@ impl Default for ItemShops { } -pub struct ShipServerStateBuilder { +pub struct ShipServerStateBuilder { entity_gateway: Option, name: Option, ip: Option, @@ -382,7 +382,7 @@ pub struct ShipServerStateBuilder { num_blocks: usize, } -impl Default for ShipServerStateBuilder { +impl Default for ShipServerStateBuilder { fn default() -> ShipServerStateBuilder { ShipServerStateBuilder { entity_gateway: None, @@ -395,7 +395,7 @@ impl Default for ShipServerStateBuilder { } } -impl ShipServerStateBuilder { +impl ShipServerStateBuilder { #[must_use] pub fn gateway(mut self, entity_gateway: EG) -> ShipServerStateBuilder { self.entity_gateway = Some(entity_gateway); @@ -478,7 +478,7 @@ impl Blocks { } } -pub struct ShipServerState { +pub struct ShipServerState { entity_gateway: EG, pub clients: Clients, level_table: CharacterLevelTable, @@ -496,7 +496,7 @@ pub struct ShipServerState { trades: TradeState, } -impl ShipServerState { +impl ShipServerState { pub fn builder() -> ShipServerStateBuilder { ShipServerStateBuilder::default() } @@ -509,11 +509,11 @@ impl ShipServerState { Ok(match &msg.msg { GameMessage::RequestExp(request_exp) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::message::request_exp(id, request_exp, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut block.rooms, &self.level_table).await? + handler::message::request_exp(id, request_exp, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut block.rooms, &self.level_table).await? }, GameMessage::PlayerDropItem(player_drop_item) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::message::player_drop_item(id, player_drop_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_state).await? + handler::message::player_drop_item(id, player_drop_item, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_state).await? }, GameMessage::DropCoordinates(drop_coordinates) => { let block = self.blocks.with_client(id, &self.clients)?; @@ -521,7 +521,7 @@ impl ShipServerState { }, GameMessage::PlayerNoLongerHasItem(no_longer_has_item) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::message::no_longer_has_item(id, no_longer_has_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await? + handler::message::no_longer_has_item(id, no_longer_has_item, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut self.item_state).await? }, GameMessage::PlayerChangedMap(_) | GameMessage::PlayerChangedMap2(_) | GameMessage::TellOtherPlayerMyLocation(_) | GameMessage::PlayerWarpingToFloor(_) | GameMessage::PlayerTeleported(_) | GameMessage::PlayerStopped(_) | @@ -532,31 +532,31 @@ impl ShipServerState { }, GameMessage::ChargeAttack(charge_attack) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::message::charge_attack(id, charge_attack, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await? + handler::message::charge_attack(id, charge_attack, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut self.item_state).await? }, GameMessage::PlayerUseItem(player_use_item) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::message::player_uses_item(id, player_use_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await? + handler::message::player_uses_item(id, player_use_item, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut self.item_state).await? }, GameMessage::PlayerUsedMedicalCenter(player_used_medical_center) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::message::player_used_medical_center(id, player_used_medical_center, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await? + handler::message::player_used_medical_center(id, player_used_medical_center, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut self.item_state).await? }, GameMessage::PlayerFeedMag(player_feed_mag) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::message::player_feed_mag(id, player_feed_mag, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? + handler::message::player_feed_mag(id, player_feed_mag, self.entity_gateway.clone(), &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerEquipItem(player_equip_item) => { - handler::message::player_equips_item(id, player_equip_item, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? + handler::message::player_equips_item(id, player_equip_item, self.entity_gateway.clone(), &self.clients, &mut self.item_state).await? }, GameMessage::PlayerUnequipItem(player_unequip_item) => { - handler::message::player_unequips_item(id, player_unequip_item, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? + handler::message::player_unequips_item(id, player_unequip_item, self.entity_gateway.clone(), &self.clients, &mut self.item_state).await? }, GameMessage::SortItems(sort_items) => { - handler::message::player_sorts_items(id, sort_items, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? + handler::message::player_sorts_items(id, sort_items, self.entity_gateway.clone(), &self.clients, &mut self.item_state).await? }, GameMessage::PlayerSoldItem(player_sold_item) => { - handler::message::player_sells_item(id, player_sold_item, &mut self.entity_gateway, &mut self.clients, &mut self.item_state).await? + handler::message::player_sells_item(id, player_sold_item, self.entity_gateway.clone(), &mut self.clients, &mut self.item_state).await? }, _ => { let cmsg = msg.clone(); @@ -577,31 +577,31 @@ impl ShipServerState { handler::direct_message::guildcard_send(id, guildcard_send, target, &block.client_location, &self.clients) }, GameMessage::RequestItem(request_item) => { - handler::direct_message::request_item(id, request_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_state).await? + handler::direct_message::request_item(id, request_item, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_state).await? }, GameMessage::PickupItem(pickup_item) => { - handler::direct_message::pickup_item(id, pickup_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await? + handler::direct_message::pickup_item(id, pickup_item, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut self.item_state).await? }, GameMessage::BoxDropRequest(box_drop_request) => { - handler::direct_message::request_box_item(id, box_drop_request, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_state).await? + handler::direct_message::request_box_item(id, box_drop_request, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_state).await? }, GameMessage::BankRequest(_bank_request) => { handler::direct_message::send_bank_list(id, &self.clients, &mut self.item_state).await? }, GameMessage::BankInteraction(bank_interaction) => { - handler::direct_message::bank_interaction(id, bank_interaction, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await? + handler::direct_message::bank_interaction(id, bank_interaction, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut self.item_state).await? }, GameMessage::ShopRequest(shop_request) => { handler::direct_message::shop_request(id, shop_request, &block.client_location, &mut self.clients, &block.rooms, &self.level_table, &mut self.shops).await? }, GameMessage::BuyItem(buy_item) => { - handler::direct_message::buy_item(id, buy_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await? + handler::direct_message::buy_item(id, buy_item, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut self.item_state).await? }, GameMessage::TekRequest(tek_request) => { - handler::direct_message::request_tek_item(id, tek_request, &mut self.entity_gateway, &mut self.clients, &mut self.item_state).await? + handler::direct_message::request_tek_item(id, tek_request, self.entity_gateway.clone(), &mut self.clients, &mut self.item_state).await? }, GameMessage::TekAccept(tek_accept) => { - handler::direct_message::accept_tek_item(id, tek_accept, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await? + handler::direct_message::accept_tek_item(id, tek_accept, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut self.item_state).await? }, GameMessage::TradeRequest(trade_request) => { handler::trade::trade_request(id, trade_request, target, &block.client_location, &mut self.clients, &mut self.item_state, &mut self.trades).await? @@ -619,7 +619,7 @@ impl ShipServerState { } #[async_trait::async_trait] -impl ServerState for ShipServerState { +impl ServerState for ShipServerState { type SendPacket = SendShipPacket; type RecvPacket = RecvShipPacket; type PacketError = anyhow::Error; @@ -647,7 +647,7 @@ impl ServerState for ShipServerState { Ok(match pkt { RecvShipPacket::Login(login) => { - Box::new(handler::auth::validate_login(id, login, &mut self.entity_gateway, &mut self.clients, &mut self.item_state, &self.shipgate_sender, &self.name, self.blocks.0.len()) + Box::new(handler::auth::validate_login(id, login, self.entity_gateway.clone(), &mut self.clients, &mut self.item_state, &self.shipgate_sender, &self.name, self.blocks.0.len()) .await?.into_iter().map(move |pkt| (id, pkt))) }, RecvShipPacket::QuestDetailRequest(questdetailrequest) => { @@ -721,14 +721,14 @@ impl ServerState for ShipServerState { handler::room::room_name_request(id, &block.client_location, &block.rooms) }, RecvShipPacket::UpdateConfig(pkt) => { - handler::settings::update_config(id, pkt, &mut self.clients, &mut self.entity_gateway).await + handler::settings::update_config(id, pkt, &mut self.clients, self.entity_gateway.clone()).await }, RecvShipPacket::ViewInfoboardRequest(_pkt) => { let block = self.blocks.with_client(id, &self.clients)?; handler::communication::request_infoboard(id, &block.client_location, &self.clients) }, RecvShipPacket::WriteInfoboard(pkt) => { - handler::communication::write_infoboard(id, pkt, &mut self.clients, &mut self.entity_gateway).await + handler::communication::write_infoboard(id, pkt, &mut self.clients, self.entity_gateway.clone()).await }, RecvShipPacket::RoomListRequest(_req) => { let block = self.blocks.with_client(id, &self.clients)?; @@ -752,7 +752,7 @@ impl ServerState for ShipServerState { }, RecvShipPacket::LobbySelect(pkt) => { let block = self.blocks.with_client(id, &self.clients)?; - Box::new(handler::lobby::change_lobby(id, pkt.lobby, &mut block.client_location, &self.clients, &mut self.item_state, &self.level_table, &mut block.rooms, &mut self.entity_gateway).await?.into_iter()) + Box::new(handler::lobby::change_lobby(id, pkt.lobby, &mut block.client_location, &self.clients, &mut self.item_state, &self.level_table, &mut block.rooms, self.entity_gateway.clone()).await?.into_iter()) }, RecvShipPacket::RequestQuestList(rql) => { let block = self.blocks.with_client(id, &self.clients)?; @@ -774,7 +774,7 @@ impl ServerState for ShipServerState { Box::new(None.into_iter()) }, RecvShipPacket::SaveOptions(save_options) => { - handler::settings::save_options(id, save_options, &mut self.clients, &mut self.entity_gateway).await + handler::settings::save_options(id, save_options, &mut self.clients, self.entity_gateway.clone()).await }, RecvShipPacket::RequestShipList(_) => { handler::ship::ship_list(id, &self.ship_list) @@ -788,13 +788,13 @@ impl ServerState for ShipServerState { }, RecvShipPacket::TradeConfirmed(_) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::trade::trade_confirmed(id, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state, &mut self.trades).await? + handler::trade::trade_confirmed(id, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut self.item_state, &mut self.trades).await? }, RecvShipPacket::KeyboardConfig(keyboard_config) => { - handler::settings::keyboard_config(id, keyboard_config, &mut self.clients, &mut self.entity_gateway).await + handler::settings::keyboard_config(id, keyboard_config, &mut self.clients, self.entity_gateway.clone()).await }, RecvShipPacket::GamepadConfig(gamepad_config) => { - handler::settings::gamepad_config(id, gamepad_config, &mut self.clients, &mut self.entity_gateway).await + handler::settings::gamepad_config(id, gamepad_config, &mut self.clients, self.entity_gateway.clone()).await }, }) } @@ -839,7 +839,7 @@ impl ServerState for ShipServerState { #[async_trait::async_trait] -impl InterserverActor for ShipServerState { +impl InterserverActor for ShipServerState { type SendMessage = ShipMessage; type RecvMessage = LoginMessage; type Error = (); diff --git a/tests/common.rs b/tests/common.rs index cf958c8..0243945 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -13,7 +13,7 @@ use libpso::packet::login::{Login, Session}; use libpso::{utf8_to_array, utf8_to_utf16_array}; -pub async fn new_user_character(entity_gateway: &mut EG, username: &str, password: &str, kb_conf_preset: usize) -> (UserAccountEntity, CharacterEntity) { +pub async fn new_user_character(entity_gateway: &mut EG, username: &str, password: &str, kb_conf_preset: usize) -> (UserAccountEntity, CharacterEntity) { let new_user = NewUserAccountEntity { email: format!("{}@pso.com", username), username: username.into(), @@ -34,7 +34,7 @@ pub async fn new_user_character(entity_gateway: &mut EG, user (user, character) } -pub async fn log_in_char(ship: &mut ShipServerState, id: ClientId, username: &str, password: &str) { +pub async fn log_in_char(ship: &mut ShipServerState, id: ClientId, username: &str, password: &str) { let username = username.to_string(); let password = password.to_string(); ship.handle(id, &RecvShipPacket::Login(Login { @@ -52,24 +52,24 @@ pub async fn log_in_char(ship: &mut ShipServerState, id: })).await.unwrap().for_each(drop); } -pub async fn join_lobby(ship: &mut ShipServerState, id: ClientId) { +pub async fn join_lobby(ship: &mut ShipServerState, id: ClientId) { ship.handle(id, &RecvShipPacket::CharData(CharData { _unknown: [0; 0x828] })).await.unwrap().for_each(drop); } -pub async fn create_room(ship: &mut ShipServerState, id: ClientId, name: &str, password: &str) { +pub async fn create_room(ship: &mut ShipServerState, id: ClientId, name: &str, password: &str) { create_room_with_difficulty(ship, id, name, password, Difficulty::Normal).await; } -pub async fn leave_room(ship: &mut ShipServerState, id: ClientId) { +pub async fn leave_room(ship: &mut ShipServerState, id: ClientId) { ship.handle(id, &RecvShipPacket::LobbySelect(LobbySelect { menu: 3, lobby: 0, })).await.unwrap().for_each(drop); } -pub async fn create_room_with_difficulty(ship: &mut ShipServerState, id: ClientId, name: &str, password: &str, difficulty: Difficulty) { +pub async fn create_room_with_difficulty(ship: &mut ShipServerState, id: ClientId, name: &str, password: &str, difficulty: Difficulty) { ship.handle(id, &RecvShipPacket::CreateRoom(CreateRoom { unknown: [0; 2], name: utf8_to_utf16_array!(name, 16), @@ -84,7 +84,7 @@ pub async fn create_room_with_difficulty(ship: &mut ShipServe ship.handle(id, &RecvShipPacket::DoneBursting(DoneBursting {})).await.unwrap().for_each(drop); } -pub async fn join_room(ship: &mut ShipServerState, id: ClientId, room_id: u32) { +pub async fn join_room(ship: &mut ShipServerState, id: ClientId, room_id: u32) { ship.handle(id, &RecvShipPacket::MenuSelect(MenuSelect { menu: ROOM_MENU_ID, item: room_id, diff --git a/tests/test_trade.rs b/tests/test_trade.rs index fd2c1b7..0d97cd7 100644 --- a/tests/test_trade.rs +++ b/tests/test_trade.rs @@ -15,7 +15,7 @@ use libpso::packet::messages::*; mod common; use common::*; -async fn initialize_trade(ship: &mut ShipServerState, client1: ClientId, client2: ClientId) { +async fn initialize_trade(ship: &mut ShipServerState, client1: ClientId, client2: ClientId) { ship.handle(client1, &RecvShipPacket::DirectMessage(DirectMessage::new(client2.0 as u32 -1, GameMessage::TradeRequest(TradeRequest { client: client1.0 as u8 -1, target: 0, @@ -29,7 +29,7 @@ async fn initialize_trade(ship: &mut ShipServerState, cli })))).await.unwrap().for_each(drop); } -async fn confirm_trade(ship: &mut ShipServerState, client1: ClientId, client2: ClientId) { +async fn confirm_trade(ship: &mut ShipServerState, client1: ClientId, client2: ClientId) { ship.handle(client1, &RecvShipPacket::DirectMessage(DirectMessage::new(client2.0 as u32 -1, GameMessage::TradeRequest(TradeRequest { client: client1.0 as u8 -1, target: 0, @@ -43,7 +43,7 @@ async fn confirm_trade(ship: &mut ShipServerState, client })))).await.unwrap().for_each(drop); } -async fn finalconfirm_trade(ship: &mut ShipServerState, client1: ClientId, client2: ClientId) { +async fn finalconfirm_trade(ship: &mut ShipServerState, client1: ClientId, client2: ClientId) { ship.handle(client1, &RecvShipPacket::DirectMessage(DirectMessage::new(client2.0 as u32 -1, GameMessage::TradeRequest(TradeRequest { client: client1.0 as u8 -1, target: 0, From e5ff75e36735e489a049d4c5c9291d1985c19c3f Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 30 Jul 2022 20:16:07 -0600 Subject: [PATCH 3/3] clippy --- src/entity/gateway/inmemory.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/entity/gateway/inmemory.rs b/src/entity/gateway/inmemory.rs index 560d683..ba6f665 100644 --- a/src/entity/gateway/inmemory.rs +++ b/src/entity/gateway/inmemory.rs @@ -21,8 +21,8 @@ where K: Ord + Copy, V: Clone, { - if !working_table.contains_key(&key) { - working_table.insert(key, original_table.get(&key)?.clone()); + if let std::collections::btree_map::Entry::Vacant(e) = working_table.entry(key) { + e.insert(original_table.get(&key)?.clone()); } Some(())