summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjetil Orbekk <kj@orbekk.com>2023-01-02 16:57:00 -0500
committerKjetil Orbekk <kj@orbekk.com>2023-01-02 16:57:00 -0500
commit0f7dacea15d6e22123c3290c52515a772fc7ee92 (patch)
tree75af47d988e6b4dca4466898bb73cc0bc30fc171
parent29dc8af0d9e01274eb1c520ea174e8a16f316562 (diff)
Switch Table trait to use generics
-rw-r--r--server/src/table.rs41
-rw-r--r--server/tests/table_test.rs37
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?;