diff options
author | Kjetil Orbekk <kj@orbekk.com> | 2023-01-02 16:57:00 -0500 |
---|---|---|
committer | Kjetil Orbekk <kj@orbekk.com> | 2023-01-02 16:57:00 -0500 |
commit | 0f7dacea15d6e22123c3290c52515a772fc7ee92 (patch) | |
tree | 75af47d988e6b4dca4466898bb73cc0bc30fc171 | |
parent | 29dc8af0d9e01274eb1c520ea174e8a16f316562 (diff) |
Switch Table trait to use generics
-rw-r--r-- | server/src/table.rs | 41 | ||||
-rw-r--r-- | server/tests/table_test.rs | 37 |
2 files changed, 43 insertions, 35 deletions
diff --git a/server/src/table.rs b/server/src/table.rs index 55fa8fb..1dc0fb7 100644 --- a/server/src/table.rs +++ b/server/src/table.rs @@ -20,14 +20,14 @@ pub trait Table { async fn bid( self: Box<Self>, bid: Bid, - ) -> Result<Box<dyn Table + Send>, BridgeError>; + ) -> Result<Box<Self>, BridgeError>; async fn play( self: Box<Self>, card: Card, - ) -> Result<Box<dyn Table + Send>, BridgeError>; + ) -> Result<Box<Self>, BridgeError>; async fn new_deal( self: Box<Self>, - ) -> Result<Box<dyn Table + Send>, BridgeError>; + ) -> Result<Box<Self>, BridgeError>; } pub struct InMemoryTable { @@ -51,7 +51,7 @@ impl Table for InMemoryTable { async fn bid( self: Box<Self>, bid: Bid, - ) -> Result<Box<dyn Table + Send>, BridgeError> { + ) -> Result<Box<Self>, BridgeError> { let game = match self.state { TableState::Game(game) => game, _ => { @@ -65,7 +65,7 @@ impl Table for InMemoryTable { async fn play( self: Box<Self>, card: Card, - ) -> Result<Box<dyn Table + Send>, BridgeError> { + ) -> Result<Box<Self>, BridgeError> { let game = match self.state { TableState::Game(game) => game, _ => { @@ -78,16 +78,16 @@ impl Table for InMemoryTable { async fn new_deal( self: Box<Self>, - ) -> Result<Box<dyn Table + Send>, BridgeError> { + ) -> Result<Box<Self>, BridgeError> { Ok(Box::new(Self { state: GameState::new(random(), random()).into(), })) } } -pub async fn advance_play( - table: Box<dyn Table>, -) -> Result<Box<dyn Table + Send>, BridgeError> { +pub async fn advance_play<T: Table + Send>( + table: Box<T>, +) -> Result<Box<T>, BridgeError> { let game = match table.state() { TableState::Game(game) => game, _ => return Err(BridgeError::InvalidRequest("no game".to_string())), @@ -115,21 +115,21 @@ pub async fn advance_play( table } -pub struct DbTable { +pub struct DbTable<Inner: Table> { db: PgPool, id: Uuid, - pub inner: Box<dyn Table + Send>, + pub inner: Box<Inner>, } -impl DbTable { - pub async fn new(db: PgPool, id: Uuid) -> Result<Self, BridgeError> { +impl<Inner: Table> DbTable<Inner> { + pub async fn new(db: PgPool, id: Uuid, inner: Inner) -> Result<Self, BridgeError> { let mut txn = db.begin().await?; if let Some(_) = sqlx::query!("select id from bridge_table where id = $1", id) .fetch_optional(&mut txn) .await? { - return Self::restore(db, txn, id).await; + return Self::restore(db, txn, id, inner).await; } sqlx::query!("insert into bridge_table (id) values($1)", id) @@ -140,7 +140,7 @@ impl DbTable { Ok(Self { db, id, - inner: Box::new(InMemoryTable::new()), + inner: Box::new(inner), }) } @@ -148,18 +148,19 @@ impl DbTable { db: PgPool, txn: Transaction<'_, Postgres>, id: Uuid, + inner: Inner, ) -> Result<Self, BridgeError> { txn.rollback().await?; Ok(Self { db, id, - inner: Box::new(InMemoryTable::new()), + inner: Box::new(inner), }) } } #[async_trait] -impl Table for DbTable { +impl<Inner: Table + Send> Table for DbTable<Inner> { fn state(&self) -> &TableState { self.inner.state() } @@ -167,7 +168,7 @@ impl Table for DbTable { async fn bid( self: Box<Self>, bid: Bid, - ) -> Result<Box<dyn Table + Send>, BridgeError> { + ) -> Result<Box<Self>, BridgeError> { Ok(Box::new(Self { inner: self.inner.bid(bid).await?, ..*self @@ -177,7 +178,7 @@ impl Table for DbTable { async fn play( self: Box<Self>, card: Card, - ) -> Result<Box<dyn Table + Send>, BridgeError> { + ) -> Result<Box<Self>, BridgeError> { Ok(Box::new(Self { inner: self.inner.play(card).await?, ..*self @@ -186,7 +187,7 @@ impl Table for DbTable { async fn new_deal( self: Box<Self>, - ) -> Result<Box<dyn Table + Send>, BridgeError> { + ) -> Result<Box<Self>, BridgeError> { let inner = self.inner.new_deal().await?; let deal: Deal = random(); diff --git a/server/tests/table_test.rs b/server/tests/table_test.rs index 87547c3..1db7aa8 100644 --- a/server/tests/table_test.rs +++ b/server/tests/table_test.rs @@ -8,9 +8,10 @@ use uuid::Uuid; mod common; -async fn table_basic_test( - mut table: Box<dyn Table + Send>, -) -> Result<(), anyhow::Error> { +async fn table_basic_test<T>(mut table: Box<T>) -> Result<(), anyhow::Error> +where + T: Table + Send, +{ assert!(matches!(table.state(), TableState::Unknown)); table = table.new_deal().await?; assert!(matches!(table.state(), TableState::Game(_))); @@ -24,13 +25,14 @@ async fn table_basic_test( Ok(()) } -async fn advance_table( - table: Box<dyn Table + Send>, -) -> Result<Box<dyn Table + Send>, BridgeError> { +async fn advance_table<T>(table: Box<T>) -> Result<Box<T>, BridgeError> +where + T: Table + Send, +{ match table.state() { TableState::Unknown => panic!("unexpected state"), - TableState::Game(g) => server::table::advance_play(table).await, - TableState::Result(g) => table.new_deal().await, + TableState::Game(_) => server::table::advance_play(table).await, + TableState::Result(_) => table.new_deal().await, } } @@ -47,7 +49,8 @@ async fn in_memory_table() -> Result<(), anyhow::Error> { async fn db_table() -> Result<(), anyhow::Error> { let db = common::TestDb::new().await; table_basic_test(Box::new( - DbTable::new(db.db().clone(), Uuid::new_v4()).await?, + DbTable::new(db.db().clone(), Uuid::new_v4(), InMemoryTable::new()) + .await?, )) .await?; Ok(()) @@ -62,10 +65,12 @@ async fn db_table() -> Result<(), anyhow::Error> { async fn db_table_idempotent() -> Result<(), anyhow::Error> { let db = common::TestDb::new().await; let uuid = Uuid::new_v4(); - let table1: Box<dyn Table + Send> = - Box::new(DbTable::new(db.db().clone(), uuid).await?); - let table2: Box<dyn Table + Send> = - Box::new(DbTable::new(db.db().clone(), uuid).await?); + let table1 = Box::new( + DbTable::new(db.db().clone(), uuid, InMemoryTable::new()).await?, + ); + let table2 = Box::new( + DbTable::new(db.db().clone(), uuid, InMemoryTable::new()).await?, + ); assert_eq!(table1.state(), table2.state()); Ok(()) } @@ -74,8 +79,10 @@ async fn db_table_idempotent() -> Result<(), anyhow::Error> { #[ignore] async fn db_table_persistence() -> Result<(), anyhow::Error> { let db = common::TestDb::new().await; - let mut table: Box<dyn Table + Send> = - Box::new(DbTable::new(db.db().clone(), Uuid::new_v4()).await?); + let mut table = Box::new( + DbTable::new(db.db().clone(), Uuid::new_v4(), InMemoryTable::new()) + .await?, + ); table = table.new_deal().await?; for i in 0..(thread_rng().gen_range(0..200)) { table = advance_table(table).await?; |