fn op(&self, gs: &mut GameState, _: PlayerId, piece: PieceId,
_p: &dyn Piece, _: &dyn Lens) -> PieceUpdateFromOp {
let pc = gs.pieces.byid_mut(piece).unwrap();
- pc.zlevel = ZLevel { z : self.z, zg : gs.gen };
- let update = PieceUpdateOp::SetZLevel(pc.zlevel);
+ pc.zlevel = ZLevel { z : self.z.clone(), zg : gs.gen };
+ let update = PieceUpdateOp::SetZLevel(());
(WhatResponseToClientOp::Predictable,
update, vec![])
}
#[serde(try_from="&str")]
pub struct Bigfloat(Innards);
+ unsafe impl Send for Bigfloat { }
+ unsafe impl Sync for Bigfloat { }
+
type Innards = NonNull<u8>;
pub(in super)
impl Bigfloat {
pub(in super)
- fn from_parts(sign: Sign, exp: Sz, limbs: &[Limb]) -> Bigfloat {
- let nlimbs : Sz = limbs.len().try_into().expect("limb count overflow");
+ fn from_limbs<L, I>(sign: Sign, exp: Sz, nlimbs: Sz, mut limbs: I)
+ -> Bigfloat
+ where L: Into<Limb> + Debug,
+ I: Iterator<Item=L>
+ {
unsafe {
let p = alloc::alloc(layout(nlimbs));
let (p_header, p_limbs) = ptrs(p);
ptr::write(p_header, Header { sign, exp, nlimbs });
- ptr::copy_nonoverlapping(limbs.as_ptr(), p_limbs, nlimbs as usize);
+ let mut count = 0..(nlimbs as usize);
+ loop {
+ match (limbs.next(), count.next()) {
+ (None, None) => break,
+ (Some(l), Some(i)) => {
+ p_limbs.add(i).write(l.into());
+ },
+ x => panic!("unexpected {:?}", x),
+ }
+ }
Bigfloat(NonNull::new(p).unwrap())
}
}
#[allow(dead_code)] // xxx
pub(in super)
- fn as_mut_limbs(&self) -> (&Header, &mut [Limb]) {
+ fn as_mut_limbs(&mut self) -> (&Header, &mut [Limb]) {
unsafe {
let (h, l) = ptrs(self.0.as_ptr());
let h = h.as_mut().unwrap();
(h, limbs)
}
}
+
+ pub(in super)
+ fn from_parts(sign: Sign, exp: Sz, limbs: &[Limb]) -> Bigfloat {
+ let nlimbs : Sz = limbs.len().try_into().expect("limb count overflow");
+ Self::from_limbs(sign, exp, nlimbs, limbs.iter().cloned())
+ }
}
impl Drop for Bigfloat {
}
+impl Default for Bigfloat {
+ fn default() -> Bigfloat {
+ Bigfloat::from_parts(Pos, 0, &[default()])
+ }
+}
+
impl From<LimbVal> for Limb {
fn from(u: LimbVal) -> Limb {
assert_eq!(0, u >> 48);
}
}
+#[derive(Error,Debug,Copy,Clone,Serialize,Deserialize)]
+pub struct Overflow;
+display_as_debug!(Overflow);
+
+impl From<TryFromIntError> for Overflow {
+ fn from(_: TryFromIntError) -> Overflow { Overflow }
+}
+
+impl TryFrom<&Mutable> for Bigfloat {
+ type Error = Overflow;
+ #[throws(Overflow)]
+ fn try_from(m: &Mutable) -> Bigfloat {
+ let exp = (-m.limbs.counter()).try_into()?;
+ let nlimbs = m.limbs.len().try_into()?;
+ let slices = m.limbs.inner().as_slices();
+ let it = slices.0.iter().chain(slices.1.iter()).cloned();
+ Bigfloat::from_limbs(m.sign, exp, nlimbs, it)
+ }
+}
+
impl Mutable {
pub fn add(&mut self, rhs: u32) {
self.add_to_limb(0, rhs);
let mut updates = Vec::with_capacity(count as usize);
let mut pos = pos.unwrap_or(DEFAULT_POS_START);
- for i in 0..count {
+ let mut z = gs.max_z.clone_mut();
+ for _ in 0..count {
let p = info.load()?;
let face = face.unwrap_or_default();
if p.nfaces() <= face.into() {
throw!(SpecError::FaceNotFound);
}
- let z = gs.max_z.add(i + 1);
+ z.add(1);
let pc = PieceState {
held: None,
- zlevel: ZLevel { z, zg: gs.gen },
+ zlevel: ZLevel { z: (&z).try_into()?, zg: gs.gen },
lastclient: Default::default(),
gen_before_lastclient: Generation(0),
pinned: pinned.unwrap_or(false),
#[derive(Debug,Default)]
struct UpdateHandlerBulk {
- pieces : slotmap::SparseSecondaryMap<PieceId, PieceUpdateOp<()>>,
+ pieces : slotmap::SparseSecondaryMap<PieceId, PieceUpdateOp<(),()>>,
logs : bool,
raw : Vec<PreparedUpdateEntry>,
}
PieceNotFound,
LimitExceeded,
ServerFailure(String),
+ ZCoordinateOverflow(#[from] bigfloat::Overflow),
BadGlob { pat: String, msg: String },
BadSpec(#[from] SpecError),
}
visible_slotmap_key!{ VisiblePieceId('.') }
-#[derive(Debug,Copy,Clone,PartialEq,PartialOrd)]
-#[derive(Serialize,Deserialize,Default)]
-#[serde(into="f64")]
-#[serde(try_from="f64")]
-pub struct ZCoord(f64);
+pub type ZCoord = Bigfloat;
#[derive(Clone,Serialize,Deserialize,Eq,Ord,PartialEq,PartialOrd)]
#[serde(transparent)]
// ---------- general data types ----------
-#[derive(Debug,Copy,Clone,Serialize,Deserialize,Eq,PartialEq,Ord,PartialOrd)]
+#[derive(Debug,Clone,Serialize,Deserialize,Eq,PartialEq,Ord,PartialOrd)]
pub struct ZLevel {
pub z: ZCoord,
pub zg: Generation,
}
}
-impl TryFrom<f64> for ZCoord {
- type Error = OnlineError;
- #[throws(OnlineError)]
- fn try_from(v: f64) -> ZCoord {
- if !v.is_finite() { throw!(OnlineError::InvalidZCoord) }
- ZCoord(v)
- }
-}
-impl From<ZCoord> for f64 {
- fn from(v: ZCoord) -> f64 { v.0 }
-}
-impl Ord for ZCoord {
- fn cmp(&self, other: &Self) -> cmp::Ordering {
- self.0.partial_cmp(&other.0).unwrap()
- }
-}
-impl Eq for ZCoord { }
-impl Display for ZCoord {
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- Display::fmt(&self.0,f)
- }
-}
-
-impl ZCoord {
- pub fn add(&self, v: u32) -> ZCoord {
- ZCoord(self.0 + (v as f64))
- }
-}
-
pub trait ClampTable : Sized {
fn clamped(self, range: Self) -> (Self, bool);
}
pos : self.pos,
held : self.held,
svg : p.make_defs(pri)?,
- z : self.zlevel.z,
+ z : self.zlevel.z.clone(),
zg : self.zlevel.zg,
pinned : self.pinned,
uos : p.ui_operations()?,
// These parts are straightforward and correct
table_size : self.c.g.gs.table_size,
gen : self.c.g.gs.gen,
- max_z : self.gs.max_z,
+ max_z : self.gs.max_z.clone(),
players,
// These have special handling
log : Default::default(),
pub use std::iter;
pub use std::iter::repeat_with;
pub use std::collections::VecDeque;
-pub use std::num::Wrapping;
+pub use std::num::{Wrapping, TryFromIntError};
pub use std::cmp::{self,min,max,Ordering};
pub use std::error::Error;
pub use std::marker::PhantomData;
pub use crate::spec::*;
pub use crate::debugreader::DebugReader;
pub use crate::shapelib;
+pub use crate::bigfloat::{self, Bigfloat};
pub use nix::unistd::Uid;
let for_info = SessionPieceLoadJson {
held : &pr.held,
- z : pr.zlevel.z,
+ z : pr.zlevel.z.clone(),
zg : pr.zlevel.zg,
pinned : pr.pinned,
uos : &p.ui_operations()?,
#[derive(Debug)] // not Default
pub struct ExecuteGameChangeUpdates {
- pub pcs: Vec<(PieceId,PieceUpdateOp<()>)>,
+ pub pcs: Vec<(PieceId,PieceUpdateOp<(),()>)>,
pub log: Vec<LogEntry>,
pub raw: Option<Vec<PreparedUpdateEntry>>,
}
Piece {
by_client: IsResponseToClientOp,
piece : VisiblePieceId,
- op : PieceUpdateOp<PreparedPieceState>,
+ op : PieceUpdateOp<PreparedPieceState,ZLevel>,
},
SetTableSize(Pos),
Log (Arc<LogEntry>),
// ---------- piece updates ----------
#[derive(Debug,Serialize)]
-pub enum PieceUpdateOp<NS> {
+pub enum PieceUpdateOp<NS,ZL> {
Delete(),
Insert(NS),
Modify(NS),
Move(Pos),
- SetZLevel(ZLevel),
+ SetZLevel(ZL),
}
pub type PieceUpdateFromOp = (WhatResponseToClientOp,
- PieceUpdateOp<()>, Vec<LogEntry>);
+ PieceUpdateOp<(),()>, Vec<LogEntry>);
pub type PieceUpdateResult = Result<PieceUpdateFromOp, ApiPieceOpError>;
// ---------- for traansmission ----------
},
Piece {
piece : VisiblePieceId,
- op : PieceUpdateOp<&'u PreparedPieceState>,
+ op : PieceUpdateOp<&'u PreparedPieceState, &'u ZLevel>,
},
RecordedUnpredictable {
piece : VisiblePieceId,
// ---------- PieceUpdatesOp ----------
-impl<NS> PieceUpdateOp<NS> {
+impl<NS,ZC> PieceUpdateOp<NS,ZC> {
pub fn new_state(&self) -> Option<&NS> {
use PieceUpdateOp::*;
match self {
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<NS2, ZC2, E:Error,
+ F: FnOnce(NS) -> Result<NS2,E>,
+ G: FnOnce(ZC) -> Result<ZC2,E>
+ > (self, f:F, g:G) -> Result<PieceUpdateOp<NS2,ZC2>,E>
{
use PieceUpdateOp::*;
Ok(match self {
Insert(ns) => Insert(f(ns)?),
Modify(ns) => Modify(f(ns)?),
Move(pos) => Move(pos),
- SetZLevel(zl) => SetZLevel(zl),
+ SetZLevel(zl) => SetZLevel(g(zl)?),
})
}
- pub fn map_ref_new_state(&self) -> PieceUpdateOp<&NS> {
+ pub fn map_ref(&self) -> PieceUpdateOp<&NS,&ZC> {
use PieceUpdateOp::*;
match self {
Delete() => Delete(),
Insert(ns) => Insert(ns),
Modify(ns) => Modify(ns),
Move(pos) => Move(*pos),
- SetZLevel(zl) => SetZLevel(*zl),
+ SetZLevel(zl) => SetZLevel(zl),
}
}
- pub fn map_new_state<NS2,F: FnOnce(NS) -> NS2>(self, f:F)
- -> PieceUpdateOp<NS2> {
+ pub fn map<NS2,ZC2,
+ F: FnOnce(NS) -> NS2,
+ G: FnOnce(ZC) -> ZC2
+ > (self, f:F, g:G) -> PieceUpdateOp<NS2,ZC2>
+ {
#[derive(Error,Debug)]
enum Never { }
- self.try_map_new_state(|ns| <Result<_,Never>>::Ok(f(ns))).unwrap()
+ self.try_map(
+ |ns| <Result<_,Never>>::Ok(f(ns)),
+ |zc| <Result<_,Never>>::Ok(g(zc)),
+ ).unwrap()
}
- pub fn new_z_generation(&self) -> Option<Generation> {
+ pub fn new_z_generation(&self) -> Option<Generation>
+ where ZC: Borrow<ZLevel>
+ {
use PieceUpdateOp::*;
match self {
Delete() => None,
Insert(_) => None,
Modify(_) => None,
Move(_) => None,
- SetZLevel(ZLevel{zg,..}) => Some(*zg),
+ SetZLevel(l) => Some(l.borrow().zg),
}
}
}
#[throws(InternalError)]
fn piece_update_fallible(&mut self, piece: PieceId,
- update: PieceUpdateOp<()>,
+ update: PieceUpdateOp<(),()>,
lens: &dyn Lens) -> PreparedUpdateEntry {
type WRC = WhatResponseToClientOp;
self.g.pieces.get(piece),
) {
(Ok(pc), Some(p)) => {
- gs.max_z.update_max(pc.zlevel.z);
+ gs.max_z.update_max(&pc.zlevel.z);
if let Some(new_lastclient) = match self.by_client {
Some((WRC::Predictable,tclient,_)) |
pc.gen = gen;
let pri_for_all = lens.svg_pri(piece,pc,Default::default());
- let update = update.try_map_new_state(
- |_|{
+ let update = update.try_map(
+ |()|{
let mut ns = pc.prep_piecestate(p.as_ref(), &pri_for_all)?;
lens.massage_prep_piecestate(&mut ns);
<Result<_,InternalError>>::Ok(ns)
},
+ |()|{
+ Ok(pc.zlevel.clone())
+ }
)?;
(update, pri_for_all.id)
}
}
- pub fn piece_update(&mut self, piece: PieceId, update: PieceUpdateOp<()>,
+ pub fn piece_update(&mut self, piece: PieceId, update: PieceUpdateOp<(),()>,
lens: &dyn Lens) {
// Caller needs us to be infallible since it is too late by
// this point to back out a game state change.
let zg = op.new_z_generation();
TUE::Recorded { piece, cseq, zg, svg: ns.map(|ns| &ns.svg) }
},
- FTG::Piece => TUE::Piece { piece, op: op.map_ref_new_state() },
+ FTG::Piece => TUE::Piece { piece, op: op.map_ref() },
FTG::Exactly(x) => x,
}
},
// SPDX-License-Identifier: AGPL-3.0-or-later
// There is NO WARRANTY.
-pub trait OrdExt : Ord + Sized {
- fn update_max(&mut self, new: Self) {
- if new > *self { *self = new }
+pub trait OrdExt : Ord + Sized + Clone {
+ fn update_max(&mut self, new: &Self) {
+ if *new > *self { *self = new.clone() }
}
}
-impl<T> OrdExt for T where T : Ord + Sized {
+impl<T> OrdExt for T where T : Ord + Sized + Clone {
}