chiark / gitweb /
make Pos a struct
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 27 Sep 2020 15:11:21 +0000 (16:11 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 27 Sep 2020 15:11:21 +0000 (16:11 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
src/bin/otter.rs
src/cmdlistener.rs
src/gamestate.rs
src/pieces.rs
src/shapelib.rs
src/spec.rs

index 109c4be62d21dc45cb6596f49b3b182dae8fa405..913d45b9e72b5abd90c6a280b8c45039fa83fe7c 100644 (file)
@@ -741,10 +741,10 @@ mod library_add {
       }
       Good([a, b]) => {
         // todo: take account of the space used by the markers themselves
-        let lhs = min(a[0], b[0]);
-        let rhs = max(a[0], b[0]);
-        let top = min(a[1], b[1]);
-        let bot = max(a[1], b[1]);
+        let lhs = min(a.0[0], b.0[0]);
+        let rhs = max(a.0[0], b.0[0]);
+        let top = min(a.0[1], b.0[1]);
+        let bot = max(a.0[1], b.0[1]);
         Placement {
           lhs, rhs, top, bot,
           cline_upto: lhs,
index 0387093d575730324d6e9aa7a0cf3a8589e10ae8..99e59c62028907fc7b64b5006b8add7d10081840 100644 (file)
@@ -28,8 +28,8 @@ from_instance_lock_error!{MgmtError}
 const USERLIST : &str = "/etc/userlist";
 const CREATE_PIECES_MAX : u32 = 300;
 
-const DEFAULT_POS_START : Pos = [20,20];
-const DEFAULT_POS_DELTA : Pos = [5,5];
+const DEFAULT_POS_START : Pos = PosC([20,20]);
+const DEFAULT_POS_DELTA : Pos = PosC([5,5]);
 
 pub struct CommandListener {
   listener : UnixListener,
@@ -152,7 +152,7 @@ fn execute_game_insn(cs: &CommandStream,
       (U{ pcs: vec![],
           log: vec![ LogEntry {
             html: Html(format!("The table was resized to {}x{}",
-                               size[0], size[1])),
+                               size.0[0], size.0[1])),
           }],
           raw: Some(vec![ PreparedUpdateEntry::SetTableSize(size) ]) },
        Fine)
@@ -281,8 +281,7 @@ fn execute_game_insn(cs: &CommandStream,
         let piece = gs.pieces.as_mut(modperm).insert(pc);
         ig.pieces.as_mut(modperm).insert(piece, p);
         updates.push((piece, PieceUpdateOp::Insert(())));
-        pos[0] += posd[0];
-        pos[1] += posd[1];
+        pos += posd;
       }
 
       (U{ pcs: updates,
index 77f98525348c2766990fff91c2d54a1586f7bfcc..db2f00e250bc924e226a0e078cddfb832fdd6f43 100644 (file)
@@ -29,7 +29,7 @@ pub struct ZCoord(pub f64);
 #[serde(transparent)]
 pub struct Html (pub String);
 
-pub const DEFAULT_TABLE_SIZE : Pos = [ 400, 200 ];
+pub const DEFAULT_TABLE_SIZE : Pos = PosC([ 400, 200 ]);
 
 // ---------- general data types ----------
 
@@ -171,12 +171,12 @@ impl ClampTable for Pos {
   fn clamped(self, range: Pos) -> (Pos, bool) {
     let mut output = ArrayVec::new();
     let mut did = false;
-    for (npos, tdid) in self.iter().zip(range.iter())
+    for (npos, tdid) in self.0.iter().zip(range.0.iter())
       .map(|(&pos, &rng)| pos.clamped(rng)) {
       output.push(npos);
       did |= tdid;
     }
-    (output.into_inner().unwrap(), did)
+    (PosC(output.into_inner().unwrap()), did)
   }
 }
 
index 95076f4ae410a9bf52fbc43c3f4ba46c8efa9570..f30e536101c56ac0c43231226bcc7748870c65b6 100644 (file)
@@ -100,7 +100,7 @@ pub fn svg_circle_path(diam: f64) -> Html {
 }
 
 #[throws(SE)]
-pub fn svg_rectangle_path([x, y] : [f64;2]) -> Html {
+pub fn svg_rectangle_path(PosC([x,y]) : PosC<f64>) -> Html {
   Html(format!("M {} {} h {} v {} h {} z",
                -x*0.5, -y*0.5, x, y, -x))
 }
@@ -179,13 +179,13 @@ impl PieceSpec for piece_specs::Disc {
 impl PieceSpec for piece_specs::Square {
   #[throws(SpecError)]
   fn load(&self) -> Box<dyn Piece> {
-    let (x, y) = match *self.size.as_slice() {
-      [s,] => (s,s),
-      [x, y] => (x,y),
+    let xy = match *self.size.as_slice() {
+      [s,]  => PosC([s,s]),
+      [x,y] => PosC([x,y]),
       _ => throw!(SpecError::ImproperSizeSpec),
     };
-    let outline = Box::new(shapelib::Square { xy: [x as f64, y as f64] });
-    let path = svg_rectangle_path([x as f64, y as f64])?;
+    let outline = Box::new(shapelib::Square { xy: xy.map(|v| v as f64) });
+    let path = svg_rectangle_path(xy.promote())?;
     let itemname = self.itemname.clone()
       .unwrap_or_else(||"simple-square".to_string());
     SimpleShape::new_from_path(Html::lit("square"), path,
index 8fa730fd3838e576c10a2ec2fd17a5d7a13c2ad6..bd46f0147a5ed54ff7d9e8eda493b15a3e2259d6 100644 (file)
@@ -451,7 +451,7 @@ impl Outline for Circle {
   }
   fn bbox_approx(&self) -> [Pos;2] {
     let d = (self.diam * 0.5).ceil() as Coord;
-    [[-d,-d], [d, d]]
+    [PosC([-d,-d]), PosC([d, d])]
   }
 }
 
@@ -479,31 +479,27 @@ impl CircleDefn {
 }
 
 #[derive(Serialize,Deserialize,Debug)]
-pub struct Square { pub xy: [f64;2] }
+pub struct Square { pub xy: PosC<f64> }
 
 #[typetag::serde(name="Square")]
 impl Outline for Square {
   #[throws(IE)]
   fn surround_path(&self, _pri : &PieceRenderInstructions) -> Html {
-    let size : ArrayVec<_> =
-      self.xy.iter().map(|s| s * SELECT_SCALE)
-      .collect();
-    svg_rectangle_path(size.into_inner().unwrap())?
+    let size = self.xy * SELECT_SCALE;
+    svg_rectangle_path(size)?
   }
   #[throws(IE)]
   fn thresh_dragraise(&self, _pri : &PieceRenderInstructions)
                       -> Option<Coord> {
-    let smallest : f64 = self.xy.iter().cloned()
+    let smallest : f64 = self.xy.0.iter().cloned()
       .map(OrderedFloat::from).min().unwrap().into();
     Some((smallest * 0.5) as Coord)
   }
   fn bbox_approx(&self) -> [Pos;2] {
-    let pos : Pos = self.xy.iter().map(
+    let pos : Pos = (self.xy * 0.5).map(
       |v| ((v * 0.5).ceil()) as Coord
-    ).collect::<ArrayVec<_>>().into_inner().unwrap();
-    let neg : Pos = pos.iter().map(
-      |v| -v
-    ).collect::<ArrayVec<_>>().into_inner().unwrap();
+    );
+    let neg = -pos;
     [ neg, pos ]
   }
 }
@@ -523,12 +519,14 @@ impl OutlineDefn for SquareDefn {
 impl SquareDefn {
   #[throws(LibraryLoadError)]
   fn get(group: &GroupData) -> Square {
-    match group.d.size.as_slice() {
-      &[s] => Square { xy: [s,s] },
-      s if s.len() == 2 => Square { xy: s.try_into().unwrap() },
-      size => throw!(LLE::WrongNumberOfSizeDimensions
-                     { got: size.len(), expected : [1,2]}),
-    }
+    Square { xy: PosC(
+      match group.d.size.as_slice() {
+        &[s] => [s,s],
+        s if s.len() == 2 => s.try_into().unwrap(),
+        size => throw!(LLE::WrongNumberOfSizeDimensions
+                       { got: size.len(), expected : [1,2]}),
+      }
+    )}
   }
 }
 
index 6e217ff94b1890d8214d902a3206706012e4a9fb..64512b3975397603e0b469041f7ae7114df6c015 100644 (file)
@@ -17,7 +17,11 @@ use crate::error::display_as_debug;
 
 pub type Coord = isize;
 
-pub type Pos = [Coord; 2];
+#[derive(Clone,Copy,Debug,Serialize,Deserialize,Hash)]
+#[derive(Eq,PartialEq,Ord,PartialOrd)]
+#[serde(transparent)]
+pub struct PosC<T> (pub [T; 2]);
+pub type Pos = PosC<Coord>;
 
 #[derive(Clone,Eq,PartialEq,Ord,PartialOrd,Hash,Serialize,Deserialize)]
 #[serde(transparent)]
@@ -105,6 +109,84 @@ pub mod piece_specs {
 
 }
 
+//---------- Pos ----------
+
+pub mod pos_traits {
+  use std::ops::{Add,Sub,Mul,Neg,AddAssign,SubAssign};
+  use crate::imports::*;
+
+  impl<T:Add<T,Output=T>+Copy+Clone+Debug> Add<PosC<T>> for PosC<T> {
+    type Output = PosC<T>;
+    fn add(self, rhs: PosC<T>) -> PosC<T> {
+      PosC(
+        itertools::zip_eq(
+          self.0.iter().cloned(),
+          rhs .0.iter().cloned(),
+        ).map(|(a,b)| a + b)
+          .collect::<ArrayVec<_>>().into_inner().unwrap()
+      )
+    }
+  }
+
+  impl<T:Sub<T,Output=T>+Copy+Clone+Debug> Sub<PosC<T>> for PosC<T> {
+    type Output = PosC<T>;
+    fn sub(self, rhs: PosC<T>) -> PosC<T> {
+      PosC(
+        itertools::zip_eq(
+          self.0.iter().cloned(),
+          rhs .0.iter().cloned(),
+        ).map(|(a,b)| a - b)
+          .collect::<ArrayVec<_>>().into_inner().unwrap()
+      )
+    }
+  }
+
+  impl<T:Add<T,Output=T>+Copy+Clone+Debug> AddAssign<PosC<T>> for PosC<T> {
+    fn add_assign(&mut self, rhs: PosC<T>) {
+      *self = *self + rhs;
+    }
+  }
+
+  impl<T:Sub<T,Output=T>+Copy+Clone+Debug> SubAssign<PosC<T>> for PosC<T> {
+    fn sub_assign(&mut self, rhs: PosC<T>) {
+      *self = *self - rhs;
+    }
+  }
+
+  impl<T:Mul<T,Output=T>+Copy+Clone+Debug> Mul<T> for PosC<T> {
+    type Output = PosC<T>;
+    fn mul(self, rhs: T) -> PosC<T> {
+      PosC(
+        self.0.iter().cloned().map(|a| a * rhs)
+          .collect::<ArrayVec<_>>().into_inner().unwrap()
+      )
+    }
+  }
+
+  impl<T:Neg<Output=T>+Copy+Clone+Debug> Neg for PosC<T> {
+    type Output = Self;
+    fn neg(self) -> Self {
+      PosC(
+        self.0.iter().cloned().map(|a| -a)
+          .collect::<ArrayVec<_>>().into_inner().unwrap()
+      )
+    }
+  }
+
+  impl<T:Copy+Clone+Debug> PosC<T> {
+    pub fn map<U:Copy+Clone+Debug, F: FnMut(T) -> U>(self, f: F) -> PosC<U> {
+      PosC(
+        self.0.iter().cloned().map(f)
+          .collect::<ArrayVec<_>>().into_inner().unwrap()
+      )
+    }
+  }
+
+  impl PosC<Coord> {
+    pub fn promote(&self) -> PosC<f64> { self.map(|v| v as f64) }
+  }
+}
+
 //---------- Implementation ----------
 
 pub mod implementation {