#[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)
}
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)
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);
}
}
#[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();
#[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();
#[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);
#[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;
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>,
// ---------- 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 ----------
zg : Option<Generation>,
},
Piece {
- piece : VisiblePieceId,
- op : &'u PieceUpdateOp<PreparedPieceState>,
+ op : &'u PieceUpdateOp<VisiblePieceId, PreparedPieceState>,
},
Log (&'u LogEntry),
}
// ---------- 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();
}
}
}