chiark / gitweb /
Refactor ApiPieceOp traits
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 27 Feb 2021 17:28:09 +0000 (17:28 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 27 Feb 2021 17:28:09 +0000 (17:28 +0000)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
daemon/api.rs
src/gamestate.rs
src/hand.rs
src/updates.rs

index f9f99d6500fa0b7bd5eeeb65d47b1748e53a3a31..3d865f4e6283db65234f2906ab82fb8abaa727b4 100644 (file)
@@ -27,7 +27,7 @@ impl<'r, Id> FromFormValue<'r> for InstanceAccess<'r, Id>
 }
 
 #[derive(Debug,Serialize,Deserialize)]
-struct ApiPiece<O:ApiPieceOp> {
+struct ApiPiece<O:op::Complex> {
   ctoken: RawToken,
   piece: VisiblePieceId,
   gen: Generation,
@@ -35,20 +35,32 @@ struct ApiPiece<O:ApiPieceOp> {
   op: O,
 }
 
-trait ApiPieceOp: Debug {
-  #[throws(ApiPieceOpError)]
-  fn op(&self, a: ApiPieceOpArgs) -> PieceUpdate;
+mod op {
+  use super::*;
 
-  #[throws(ApiPieceOpError)]
-  fn op_complex(&self, a: ApiPieceOpArgs)
-                -> (PieceUpdate, Vec<(PieceId, PieceUpdateOps)>) {
-    (self.op(a)?, vec![])
+  pub trait Core: Debug { 
+    #[throws(OnlineError)]
+    fn check_held(&self, pc: &GPiece, player: PlayerId) {
+      if pc.held != None && pc.held != Some(player) {
+        throw!(OnlineError::PieceHeld)
+      }
+    }
+  }
+
+  pub trait Simple: Core + Debug { 
+    #[throws(ApiPieceOpError)]
+    fn op(&self, a: ApiPieceOpArgs) -> PieceUpdate;
+  }
+  pub trait Complex: Core + Debug { 
+    #[throws(ApiPieceOpError)]
+    fn op_complex(&self, a: ApiPieceOpArgs) -> UpdateFromOpComplex;
   }
 
-  #[throws(OnlineError)]
-  fn check_held(&self, pc: &GPiece, player: PlayerId) {
-    if pc.held != None && pc.held != Some(player) {
-      throw!(OnlineError::PieceHeld)
+  impl<T> Complex for T where T: Simple {
+    #[throws(ApiPieceOpError)]
+    fn op_complex(&self, a: ApiPieceOpArgs) -> UpdateFromOpComplex {
+      (self.op(a)?, vec![])
     }
   }
 }
@@ -85,7 +97,7 @@ impl<'r> Responder<'r> for OnlineErrorResponse {
 }
 
 #[throws(OE)]
-fn api_piece_op<O: ApiPieceOp>(form: Json<ApiPiece<O>>)
+fn api_piece_op<O: op::Complex>(form: Json<ApiPiece<O>>)
                    -> impl response::Responder<'static> {
 //  thread::sleep(Duration::from_millis(2000));
   let iad = lookup_token(form.ctoken.borrow())?;
@@ -161,7 +173,8 @@ fn api_piece_op<O: ApiPieceOp>(form: Json<ApiPiece<O>>)
 
 macro_rules! api_route_core {
   { $fn:ident, $path:expr, $form:ident, $formdef:item,
-    $( $impl:tt )*
+    $( impl $trait:path as { $($impl:tt)* } )*
+    $( as: $($simple_impl:tt)* )?
   } => {
     #[derive(Debug,Serialize,Deserialize)]
     $formdef
@@ -173,9 +186,13 @@ macro_rules! api_route_core {
       api_piece_op(form)?
     }
 
-    impl ApiPieceOp for $form {
-      $( $impl )*
-    }
+    $(
+      impl $trait for $form { $($impl)* }
+    )*
+    $(
+      impl op::Core for $form { }
+      impl op::Simple for $form { $($simple_impl)* }
+    )?
   }
 }
 
@@ -206,6 +223,8 @@ api_route!{
   api_grab, "/_/api/grab",
   struct ApiPieceGrab {
   }
+
+  as:
   #[throws(ApiPieceOpError)]
   fn op(&self, a: ApiPieceOpArgs) -> PieceUpdate {
     let ApiPieceOpArgs { gs,player,piece,p, .. } = a;
@@ -230,35 +249,40 @@ api_route!{
   api_wrest, "/_/api/wrest",
   struct ApiPieceWrest {
   }
-  #[throws(OnlineError)]
-  fn check_held(&self, _pc: &GPiece, _player: PlayerId) { }
 
-  #[throws(ApiPieceOpError)]
-  fn op(&self, a: ApiPieceOpArgs) -> PieceUpdate {
-    let ApiPieceOpArgs { gs,player,piece,p, .. } = a;
-    let pc = gs.pieces.byid_mut(piece)?;
-    let players = &mut gs.players;
-    let was = pc.held;
-    let was = was.and_then(|p| players.get(p));
-    let was = was.map(|was| htmlescape::encode_minimal(&was.nick));
+  impl op::Core as {
+    #[throws(OnlineError)]
+    fn check_held(&self, _pc: &GPiece, _player: PlayerId) { }
+  }
 
-    let gpl = players.byid_mut(player)?;
-    let pri = piece_pri(&gs.occults, player, gpl, piece, pc);
-    let pcs = p.describe_pri(pc, &pri).0;
+  impl op::Simple as {
+    #[throws(ApiPieceOpError)]
+    fn op(&self, a: ApiPieceOpArgs) -> PieceUpdate {
+      let ApiPieceOpArgs { gs,player,piece,p, .. } = a;
+      let pc = gs.pieces.byid_mut(piece)?;
+      let players = &mut gs.players;
+      let was = pc.held;
+      let was = was.and_then(|p| players.get(p));
+      let was = was.map(|was| htmlescape::encode_minimal(&was.nick));
 
-    pc.held = Some(player);
+      let gpl = players.byid_mut(player)?;
+      let pri = piece_pri(&gs.occults, player, gpl, piece, pc);
+      let pcs = p.describe_pri(pc, &pri).0;
 
-    let update = PieceUpdateOp::Modify(());
+      pc.held = Some(player);
+
+      let update = PieceUpdateOp::Modify(());
 
-    let pls = &htmlescape::encode_minimal(&gpl.nick);
+      let pls = &htmlescape::encode_minimal(&gpl.nick);
 
-    let logent = LogEntry { html: Html(match was {
+      let logent = LogEntry { html: Html(match was {
         Some(was) => format!("{} wrested {} from {}", pls, pcs, was),
         None => format!("{} wrested {}", pls, pcs),
-    })};
+      })};
 
-    (WhatResponseToClientOp::Predictable,
-     update, vec![logent]).into()
+      (WhatResponseToClientOp::Predictable,
+       update, vec![logent]).into()
+    }
   }
 }
 
@@ -266,6 +290,8 @@ api_route!{
   api_ungrab, "/_/api/ungrab",
   struct ApiPieceUngrab {
   }
+
+  as:
   #[throws(ApiPieceOpError)]
   fn op(&self, a: ApiPieceOpArgs) -> PieceUpdate {
     let ApiPieceOpArgs { gs,player,piece,p,ipieces, .. } = a;
@@ -284,7 +310,7 @@ api_route!{
     let vanilla = (WhatResponseToClientOp::Predictable,
                    update,
                    logents);
-
+      
     let update=
       recalculate_occultation_piece(
         gs,
@@ -303,6 +329,8 @@ api_route!{
   struct ApiPieceSetZ {
     z: ZCoord,
   }
+
+  as:
   #[throws(ApiPieceOpError)]
   fn op(&self, a: ApiPieceOpArgs) -> PieceUpdate {
     // xxx prevent restzcking anything that is occulting
@@ -319,35 +347,39 @@ api_route!{
   api_move, "/_/api/m",
   struct ApiPieceMove(Pos);
 
-  #[throws(OnlineError)]
-  fn check_held(&self, pc: &GPiece, player: PlayerId) {
-    // This will ensure that occultations are (in general) properly
-    // updated, because the player will (have to) release the thing
-    // again
-    if pc.held != Some(player) {
-      throw!(OnlineError::PieceHeld)
+  impl op::Core as {
+    #[throws(OnlineError)]
+    fn check_held(&self, pc: &GPiece, player: PlayerId) {
+      // This will ensure that occultations are (in general) properly
+      // updated, because the player will (have to) release the thing
+      // again
+      if pc.held != Some(player) {
+        throw!(OnlineError::PieceHeld)
+      }
+      // xxx prevent moving anything that is occulting
     }
-    // xxx prevent moving anything that is occulting
   }
 
-  #[throws(ApiPieceOpError)]
-  fn op(&self, a: ApiPieceOpArgs) -> PieceUpdate {
-    let ApiPieceOpArgs { gs,piece, .. } = a;
-    let pc = gs.pieces.byid_mut(piece).unwrap();
-    let logents = vec![];
-    match self.0.clamped(gs.table_size) {
-      Ok(pos) => pc.pos = pos,
-      Err(pos) => {
-        pc.pos = pos;
-        throw!(ApiPieceOpError::PartiallyProcessed(
-          PieceOpError::PosOffTable,
-          logents,
-        ));
-      }
-    };
-    let update = PieceUpdateOp::Move(self.0);
-    (WhatResponseToClientOp::Predictable,
-     update, logents).into()
+  impl op::Simple as {
+    #[throws(ApiPieceOpError)]
+    fn op(&self, a: ApiPieceOpArgs) -> PieceUpdate {
+      let ApiPieceOpArgs { gs,piece, .. } = a;
+      let pc = gs.pieces.byid_mut(piece).unwrap();
+      let logents = vec![];
+      match self.0.clamped(gs.table_size) {
+        Ok(pos) => pc.pos = pos,
+        Err(pos) => {
+          pc.pos = pos;
+          throw!(ApiPieceOpError::PartiallyProcessed(
+            PieceOpError::PosOffTable,
+            logents,
+          ));
+        }
+      };
+      let update = PieceUpdateOp::Move(self.0);
+      (WhatResponseToClientOp::Predictable,
+       update, logents).into()
+    }
   }
 }
 
@@ -355,6 +387,7 @@ api_route!{
   api_rotate, "/_/api/rotate",
   struct ApiPieceRotate(CompassAngle);
 
+  as:
   #[throws(ApiPieceOpError)]
   fn op(&self, a: ApiPieceOpArgs) -> PieceUpdate {
     let ApiPieceOpArgs { gs,player,piece,p, .. } = a;
@@ -375,6 +408,7 @@ api_route!{
   api_pin, "/_/api/pin",
   struct ApiPiecePin (bool);
 
+  as:
   #[throws(ApiPieceOpError)]
   fn op(&self, a: ApiPieceOpArgs) -> PieceUpdate {
     let ApiPieceOpArgs { gs,player,piece,p, .. } = a;
@@ -399,40 +433,44 @@ api_route!{
     opname: String,
     wrc: WhatResponseToClientOp,
   }
-  #[throws(ApiPieceOpError)]
-  fn op(&self, mut a: ApiPieceOpArgs) -> PieceUpdate {
-    let ApiPieceOpArgs { player,piece,p, .. } = a;
-    let gs = &mut a.gs;
-    '_normal_global_ops__not_loop: loop {
-      let pc = gs.pieces.byid_mut(piece)?;
-      let gpl = gs.players.byid_mut(player)?;
-      let _: Void = match (self.opname.as_str(), self.wrc) {
-
-        ("flip", wrc@ WRC::UpdateSvg) => {
-          let nfaces = p.nfaces();
-          pc.face = ((RawFaceId::from(pc.face) + 1) % nfaces).into();
-          return (
-            wrc,
-            PieceUpdateOp::Modify(()),
-            log_did_to_piece(
-              &gs.occults, player, gpl, piece, pc, p,
-              "flipped"
-            ),
-          ).into()
-        },
-
-        _ => break,
-      };
-    }
 
-    '_abnormal_global_ops__notloop: loop {
-      let _: Void = match self {
+  impl op::Core as { }
+  impl op::Complex as {
+    #[throws(ApiPieceOpError)]
+    fn op_complex(&self, mut a: ApiPieceOpArgs) -> UpdateFromOpComplex {
+      let ApiPieceOpArgs { player,piece,p, .. } = a;
+      let gs = &mut a.gs;
+      '_normal_global_ops__not_loop: loop {
+        let pc = gs.pieces.byid_mut(piece)?;
+        let gpl = gs.players.byid_mut(player)?;
+        let _: Void = match (self.opname.as_str(), self.wrc) {
+
+          ("flip", wrc@ WRC::UpdateSvg) => {
+            let nfaces = p.nfaces();
+            pc.face = ((RawFaceId::from(pc.face) + 1) % nfaces).into();
+            return ((
+              wrc,
+              PieceUpdateOp::Modify(()),
+              log_did_to_piece(
+                &gs.occults, player, gpl, piece, pc, p,
+                "flipped"
+              ),
+            ).into(), vec![])
+          },
+
+          _ => break,
+        };
+      }
 
-        _ => break,
-      };
-    }
+      '_abnormal_global_ops__notloop: loop {
+        let _: Void = match self {
 
-    p.ui_operation(a, &self.opname, self.wrc)?
+          _ => break,
+        };
+      }
+
+      p.ui_operation(a, &self.opname, self.wrc)?
+    }
   }
 }
 
index cefb563a143b58e004d9fd2b6a94d0d56edf7a91..130f1caab6caf9111f1e412af04306c1e7cd1675 100644 (file)
@@ -149,7 +149,7 @@ pub trait PieceTrait: OutlineTrait + Send + Debug {
 
   fn ui_operation(&self, _a: ApiPieceOpArgs<'_>,
                   _opname: &str, _wrc: WhatResponseToClientOp)
-                  -> PieceUpdateResult {
+                  -> Result<UpdateFromOpComplex, ApiPieceOpError> {
     throw!(OE::BadOperation)
   }
 
index 34d14098045e887c5fdd6406ef96fdc9229b0d3e..b958d066e713cde6c8c5f9168b8bb51614318a59 100644 (file)
@@ -133,9 +133,10 @@ impl PieceTrait for Hand {
     })
   }
 
+  #[throws(ApiPieceOpError)]
   fn ui_operation(&self, a: ApiPieceOpArgs<'_>,
                   opname: &str, wrc: WhatResponseToClientOp)
-                  -> PieceUpdateResult {
+                  -> UpdateFromOpComplex {
     let ApiPieceOpArgs { gs,player,piece,ipieces,.. } = a;
     let gplayers = &mut gs.players;
     let gpieces = &mut gs.pieces;
@@ -209,10 +210,10 @@ impl PieceTrait for Hand {
 
     xdata.owner = new_owner;
 
-    Ok(PieceUpdate {
+    (PieceUpdate {
       wrc, log,
       ops: PUOs::Simple(PUO::Modify(())), // xxx
       // xxx want PUU::RecalculateOccultations
-    })
+    }, vec![])
   }
 }
index 5b246822e7ca23fcc47f5a7da7120135b464062c..6ce4b993696beb6e60d526ea5c124ffa943a5357 100644 (file)
@@ -104,6 +104,8 @@ pub enum PieceUpdateOp<NS,ZL> {
   SetZLevel(ZL),
 }
 
+pub type UpdateFromOpComplex = (PieceUpdate, Vec<(PieceId, PieceUpdateOps)>);
+
 pub type PieceUpdateFromOpSimple = (
   WhatResponseToClientOp,
   PieceUpdateOp<(),()>,