chiark / gitweb /
before undo PieceUpdateOp with ID
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 26 Jul 2020 14:50:13 +0000 (15:50 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 26 Jul 2020 14:50:13 +0000 (15:50 +0100)
src/api.rs
src/gamestate.rs
src/imports.rs
src/updates.rs

index 6b09c87ada640b07d6f091335be2b6becf9076ef..b99e1eac4924c290f4dd51ae49a379c04870c004 100644 (file)
@@ -14,10 +14,11 @@ trait ApiPieceOp : Debug {
   #[throws(GameError)]
   fn op(&self, gs: &mut GameState, player: PlayerId, piece: PieceId,
         lens: &dyn Lens /* used for LogEntry and PieceId but not Pos */)
-        -> (PieceUpdateOp<()>, Vec<LogEntry>);
+        -> (PieceUpdateOp<(),()>, Vec<LogEntry>);
 }
 
-trait Lens {
+pub trait Lens {
+  fn visible_pieceid(&self, piece: PieceId) -> VisiblePieceId;
   fn log_pri(&self, piece: PieceId, pc: &PieceState)
              -> PieceRenderInstructions;
   fn svg_pri(&self, piece: PieceId, pc: &PieceState, player: PlayerId)
@@ -28,10 +29,13 @@ trait Lens {
 }
 struct TransparentLens { }
 impl Lens for TransparentLens {
+  fn visible_pieceid(&self, piece: PieceId) -> VisiblePieceId {
+    let kd : slotmap::KeyData = piece.into();
+    VisiblePieceId(kd);
+  }
   fn log_pri(&self, piece: PieceId, pc: &PieceState)
              -> PieceRenderInstructions {
-    let kd : slotmap::KeyData = piece.into();
-    let id = VisiblePieceId(kd);
+    let id = self.make_piece_visible(piece);
     PieceRenderInstructions { id, face : pc.face }
   }
   fn svg_pri(&self, piece: PieceId, pc: &PieceState, _player: PlayerId)
@@ -85,48 +89,12 @@ fn api_piece_op<O: ApiPieceOp>(form : Json<ApiPiece<O>>)
       eprintln!("API {:?} => {:?}", &form, &err);
     },
     Ok((update, logents)) => {
-      let pc = gs.pieces.byid_mut(piece).expect("xxx piece deleted by op!");
-
-      gs.gen.increment();
-      let gen = gs.gen;
-      if client != pc.lastclient {
-        pc.gen_before_lastclient = pc.gen;
-        pc.lastclient = client;
-      }
-      pc.gen = gen;
-      eprintln!("PC GEN_LC={:?} LC={:?}", pc.gen, pc.lastclient);
-
-      let pri_for_all = lens.svg_pri(piece,pc,Default::default());
-
-      let update = update.try_map_new_state(|_|{
-        let mut ns = pc.prep_piecestate(&pri_for_all)?;
-        lens.massage_prep_piecestate(&mut ns);
-        <Result<_,SVGProcessingError>>::Ok(ns)
-      })?;
-
-      let mut us = Vec::with_capacity(1 + logents.len());
-
-      us.push(PreparedUpdateEntry::Piece {
-        client,
-        sameclient_cseq : form.cseq,
-        piece : pri_for_all.id,
-        op : update,
-      });
-
-      for logentry in logents {
-        let logentry = Arc::new(logentry);
-        gs.log.push((gen, logentry.clone()));
-        us.push(PreparedUpdateEntry::Log(logentry));
-      }
-
-      let update = PreparedUpdate { gen, us, };
-      let update = Arc::new(update);
-      eprintln!("UPDATE {:?}", &update);
-
-      for (_tplayer, tplupdates) in &mut g.updates {
-        tplupdates.log.push_back(update.clone());
-        tplupdates.cv.notify_all();
-      }
+      let mut buf = PrepareUpdatesBuffer::new(g, client, form.cseq,
+                                              1 + logents.len());
+      
+      buf.piece_update(piece, update, &lens);
+      buf.log_updates(logents);
+
       eprintln!("API {:?} OK", &form);
     }
   }
@@ -146,7 +114,7 @@ impl ApiPieceOp for ApiPieceGrab {
   #[throws(GameError)]
   fn op(&self, gs: &mut GameState, player: PlayerId, piece: PieceId,
         lens: &dyn Lens)
-        -> (PieceUpdateOp<()>, Vec<LogEntry>) {
+        -> (PieceUpdateOp<(),()>, Vec<LogEntry>) {
     let pl = gs.players.byid(player).unwrap();
     let pc = gs.pieces.byid_mut(piece).unwrap();
 
@@ -178,7 +146,7 @@ impl ApiPieceOp for ApiPieceUngrab {
   #[throws(GameError)]
   fn op(&self, gs: &mut GameState, player: PlayerId, piece: PieceId,
         lens: &dyn Lens)
-        -> (PieceUpdateOp<()>, Vec<LogEntry>) {
+        -> (PieceUpdateOp<(),()>, Vec<LogEntry>) {
     let pl = gs.players.byid(player).unwrap();
     let pc = gs.pieces.byid_mut(piece).unwrap();
 
@@ -211,7 +179,7 @@ impl ApiPieceOp for ApiPieceRaise {
   #[throws(GameError)]
   fn op(&self, gs: &mut GameState, _: PlayerId, piece: PieceId,
         _: &dyn Lens)
-        -> (PieceUpdateOp<()>, Vec<LogEntry>) {
+        -> (PieceUpdateOp<(),()>, Vec<LogEntry>) {
     let pc = gs.pieces.byid_mut(piece).unwrap();
     pc.zlevel = ZLevel { z : self.z, zg : gs.gen };
     let update = PieceUpdateOp::SetZLevel(pc.zlevel);
@@ -230,7 +198,7 @@ impl ApiPieceOp for ApiPieceMove {
   #[throws(GameError)]
   fn op(&self, gs: &mut GameState, _: PlayerId, piece: PieceId,
         _lens: &dyn Lens)
-        -> (PieceUpdateOp<()>, Vec<LogEntry>) {
+        -> (PieceUpdateOp<(),()>, Vec<LogEntry>) {
     let pc = gs.pieces.byid_mut(piece).unwrap();
 
     pc.pos = self.0;
index ce6633e3336c2a961f6f3fddca6cd7b08f87deb9..a3517c4989397130414fae547d310c5c50f5234d 100644 (file)
@@ -163,6 +163,7 @@ impl PieceState {
   pub fn prep_piecestate(&self, pri : &PieceRenderInstructions)
                          -> PreparedPieceState {
     PreparedPieceState {
+      piece      : pri.id,
       pos        : self.pos,
       held       : self.held,
       svg        : self.make_defs(pri)?,
index 5d810839006b53e6e9083a6fddb73e0faa349fa9..c0eac3bf1fbdc8b06d95de0689de3927dcfbbc2b 100644 (file)
@@ -64,6 +64,7 @@ pub use crate::error::*;
 pub use crate::commands::*;
 pub use crate::slotmap_slot_idx::*;
 pub use crate::cmdlistener::*;
+pub use crate::api::Lens;
 
 pub use libc::uid_t;
 
index 9b97d7499f586afbe1ef1716d45d574c01ea1829..f17fc7a25a7b8c3fb5ccd0793d10e8fdd1cbd8f5 100644 (file)
@@ -29,14 +29,14 @@ pub enum PreparedUpdateEntry {
   Piece {
     client : ClientId,
     sameclient_cseq : ClientSequence,
-    piece : VisiblePieceId,
-    op : PieceUpdateOp<PreparedPieceState>,
+    op : PieceUpdateOp<VisiblePieceId,PreparedPieceState>,
   },
   Log (Arc<LogEntry>),
 }
 
 #[derive(Debug,Serialize)]
 pub struct PreparedPieceState {
+  pub piece : VisiblePieceId,
   pub pos : Pos,
   pub svg : String,
   pub held : Option<PlayerId>,
@@ -47,12 +47,12 @@ pub struct PreparedPieceState {
 // ---------- piece updates ----------
 
 #[derive(Debug,Serialize)]
-pub enum PieceUpdateOp<NS> {
-  Delete(),
+pub enum PieceUpdateOp<ID,NS> {
+  Delete(ID),
   Insert(NS),
   Modify(NS),
-  Move(Pos),
-  SetZLevel(ZLevel),
+  Move(ID,Pos),
+  SetZLevel(ID,ZLevel),
 }
 
 // ---------- for traansmission ----------
@@ -71,8 +71,7 @@ enum TransmitUpdateEntry<'u> {
     zg : Option<Generation>,
   },
   Piece {
-    piece : VisiblePieceId,
-    op : &'u PieceUpdateOp<PreparedPieceState>,
+    op : &'u PieceUpdateOp<VisiblePieceId, PreparedPieceState>,
   },
   Log (&'u LogEntry),
 }
@@ -111,43 +110,141 @@ impl PreparedUpdateEntry {
 
 // ---------- PieceUpdatesOp ----------
 
-impl<NS> PieceUpdateOp<NS> {
+impl<ID,NS> PieceUpdateOp<ID,NS> {
   pub fn new_state(&self) -> Option<&NS> {
     use PieceUpdateOp::*;
     match self {
-      Delete() => None,
+      Delete(_) => None,
       Insert(ns) => Some(ns),
       Modify(ns) => Some(ns),
-      Move(_) => None,
-      SetZLevel(_) => None,
+      Move(..) => None,
+      SetZLevel(..) => None,
     }
   }
-  pub fn try_map_new_state<NS2,E:Error, F: FnOnce(NS) -> Result<NS2,E>>
-    (self, f:F) -> Result<PieceUpdateOp<NS2>,E>
+  pub fn try_map<ID2,NS2, E:Error,
+                 IDF: FnOnce(ID) -> Result<ID2,E>,
+                 NSF: FnOnce(NS) -> Result<NS2,E>>
+    (self, f:NSF, idf:IDF) -> Result<PieceUpdateOp<ID2,NS2>,E>
   {
     use PieceUpdateOp::*;
     Ok(match self {
-      Delete() => Delete(),
+      Delete(i) => Delete(idf(i)?),
       Insert(ns) => Insert(f(ns)?),
       Modify(ns) => Modify(f(ns)?),
-      Move(pos) => Move(pos),
-      SetZLevel(zl) => SetZLevel(zl),
+      Move(i,pos) => Move(idf(i)?,pos),
+      SetZLevel(i,zl) => SetZLevel(idf(i)?,zl),
     })
   }
-  pub fn map_new_state<NS2,F: FnOnce(NS) -> NS2>(self, f:F)
-                            -> PieceUpdateOp<NS2> {
-    #[derive(Error,Debug)]
-    enum Never { }
-    self.try_map_new_state(|ns| <Result<_,Never>>::Ok(f(ns))).unwrap()
+  pub fn map<ID2,NS2,
+             IDF: FnOnce(ID) -> ID2,
+             NSF: FnOnce(NS) -> NS2>
+    (self, nsf:NSF, idf:IDF) -> PieceUpdateOp<ID2,NS2>
+  {
+    #[derive(Error,Debug)] enum Never { }
+    self.try_map(
+      |ns| <Result<_,Never>>::Ok(nsf(ns)),
+      |id| <Result<_,Never>>::Ok(idf(id)),
+    ).unwrap()
   }
   pub fn new_z_generation(&self) -> Option<Generation> {
     use PieceUpdateOp::*;
     match self {
-      Delete() => None,
+      Delete(_) => None,
       Insert(_) => None,
       Modify(_) => None,
-      Move(_) => None,
-      SetZLevel(ZLevel{zg,..}) => Some(*zg),
+      Move(..) => None,
+      SetZLevel(_,ZLevel{zg,..}) => Some(*zg),
+    }
+  }
+  pub fn pieceid<'ns>(&'ns self) -> ID where &'ns NS : Into<ID>, ID : Copy {
+    use PieceUpdateOp::*;
+    match self {
+      Delete(i) => *i,
+      Insert(ns) | Modify(ns) => ns.into(),
+      Move(i,_) => *i,
+      SetZLevel(i,_) => *i,
+    }
+  }
+}
+
+pub struct PrepareUpdatesBuffer<'r> {
+  g : &'r mut Instance,
+  us : Vec<PreparedUpdateEntry>,
+  gen : Generation,
+  by_client : ClientId,
+  cseq : ClientSequence,
+}
+
+impl<'r> PrepareUpdatesBuffer<'r> {
+  pub fn new(g: &'r mut Instance, by_client: ClientId, cseq: ClientSequence,
+             estimate: usize) -> Self
+  {
+    g.gs.gen.increment();
+    PrepareUpdatesBuffer {
+      us: Vec::with_capacity(estimate),
+      gen: g.gs.gen,
+      g, by_client, cseq,
+    }
+  }
+
+  pub fn piece_update(&mut self, piece: PieceId, update: PieceUpdateOp<(),()>,
+                      lens: &dyn Lens) {
+    let gs = &mut self.g.gs;
+
+    let update = match gs.pieces.byid_mut(piece) {
+      Some(pc) => {
+        if self.by_client != pc.lastclient {
+          pc.gen_before_lastclient = pc.gen;
+          pc.lastclient = self.by_client;
+        }
+        pc.gen = self.gen;
+        eprintln!("PC GEN_LC={:?} LC={:?}", pc.gen, pc.lastclient);
+      
+        let pri_for_all = lens.svg_pri(piece,pc,Default::default());
+
+        let update = update.try_map(
+          |_|{
+            let mut ns = pc.prep_piecestate(&pri_for_all)?;
+            lens.massage_prep_piecestate(&mut ns);
+            <Result<_,SVGProcessingError>>::Ok(ns)
+          },
+          |_|{
+            <Result<_,SVGProcessingError>>::Ok(pri_for_all.id)
+          },
+        )?;
+
+        update
+      },
+      None => {
+        PieceUpdateOp::Delete(lens.make_piece_visible(piece))
+      }
+    };
+
+    self.us.push(PreparedUpdateEntry::Piece {
+      client : self.by_client,
+      sameclient_cseq : self.cseq,
+      op : update,
+    });
+  }
+
+  pub fn log_updates(&mut self, logents: Vec<LogEntry>) {
+    for logentry in logents {
+      let logentry = Arc::new(logentry);
+      self.g.gs.log.push((self.gen, logentry.clone()));
+      self.us.push(PreparedUpdateEntry::Log(logentry));
+    }
+  }
+}
+
+impl<'r> Drop for PrepareUpdatesBuffer<'r> {
+  fn drop(&mut self) {
+    let update = PreparedUpdate { gen: self.gen, us: self.us.take(), };
+    let update = Arc::new(update);
+    eprintln!("UPDATE {:?}", &update);
+
+    for (_tplayer, tplupdates) in &mut self.g.updates {
+      tplupdates.log.push_back(update.clone());
+      tplupdates.cv.notify_all();
     }
   }
 }