From 92d5b882a43bc3651a392d141a6ad6fe5aea76b9 Mon Sep 17 00:00:00 2001 From: Adrien Burgun Date: Fri, 24 Jun 2022 11:15:34 +0200 Subject: [PATCH] :pencil: Document Pane --- stackline/src/pane.rs | 119 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 114 insertions(+), 5 deletions(-) diff --git a/stackline/src/pane.rs b/stackline/src/pane.rs index b08fc47..f9ce96a 100644 --- a/stackline/src/pane.rs +++ b/stackline/src/pane.rs @@ -10,6 +10,28 @@ pub struct Pane { } impl Pane { + /// Creates a new, empty `Pane` with the given dimensions. + /// If `width == 0` or `height == 0`, returns `None`. + /// + /// # Example + /// + /// ``` + /// use stackline::prelude::*; + /// use stackline::tile::Wire; + /// + /// // Create a new Pane with width 6 and height 4 + /// let mut pane = Pane::empty(6, 4).unwrap(); + /// + /// // Place a horizontal wire on (2, 1) and (3, 1) + /// pane.set_tile((2, 1), Wire::new(Orientation::Horizontal)); + /// pane.set_tile((3, 1), Wire::new(Orientation::Horizontal)); + /// + /// // Put a signal on (2, 1) + /// pane.set_signal((2, 1), stackline::signal!((2, 1))); + /// + /// // Perform a simulation step + /// pane.step(); + /// ``` pub fn empty(width: usize, height: usize) -> Option { // TODO: check that width * height is a valid usize let length = width.checked_mul(height)?; @@ -23,7 +45,24 @@ impl Pane { }) } - /// Returns `Some((x + Δx, y + Δy))` iff `(x + Δx, y + Δy)` is inside the world + /// Given a `position = (x, y)` and an `offset = (Δx, Δy)`, + /// returns `Some((x + Δx, y + Δy))` if `(x + Δx, y + Δy)` is inside the `Pane`. + /// + /// If `(x + Δx, y + Δy)` fall outside of the bounds of `Pane`, returns `None`. + /// + /// # Example + /// + /// ``` + /// # use stackline::prelude::*; + /// # + /// let pane = Pane::empty(4, 2).unwrap(); + /// + /// assert_eq!(pane.offset((1, 0), (2, 1)), Some((3, 1))); // (1 + 2, 0 + 1) = (3, 1), inside + /// + /// assert_eq!(pane.offset((1, 0), (-2, 0)), None); // (1 - 2, 0 + 0) = (-1, 0), outside + /// + /// assert_eq!(pane.offset((1, 0), (3, 0)), None); // (1 + 3, 0 + 0) = (4, 0), outside + /// ``` #[inline] pub fn offset(&self, position: (usize, usize), offset: (i8, i8)) -> Option<(usize, usize)> { if offset.0 < 0 && (-offset.0) as usize > position.0 @@ -46,6 +85,21 @@ impl Pane { } // TODO: Have a Result instead of an Option + /// Returns an immutable referenec to the [`Tile`] at `position`. + /// If `position` is out of bounds, returns `None`. + /// + /// # Example + /// + /// ``` + /// use stackline::prelude::*; + /// use stackline::tile::{FullTile, Wire}; + /// + /// let mut pane = Pane::empty(4, 4).unwrap(); + /// + /// pane.set_tile((0, 0), Wire::new(Orientation::Horizontal)); + /// + /// let tile = pane.get((0, 0)).unwrap(); + /// ``` #[inline] pub fn get<'b>(&'b self, position: (usize, usize)) -> Option<&'b FullTile> { if !self.in_bounds(position) { @@ -93,16 +147,58 @@ impl Pane { Some(()) } - /// Returns the [`State`] of the tile at `position`, if it exists. + /// Returns the [`State`] of the tile at `position`, if that tile exists. + /// If `position` is out of bounds, returns `None`. + /// + /// # Example + /// + /// ``` + /// use stackline::prelude::*; + /// use stackline::tile::Wire; + /// + /// let mut pane = Pane::empty(1, 1).unwrap(); + /// + /// // All tiles are initialized with the Idle state + /// assert_eq!(pane.get_state((0, 0)), Some(State::Idle)); + /// + /// // Creating a new tile gives it the Idle state + /// pane.set_tile((0, 0), Wire::new(Orientation::Horizontal)); + /// assert_eq!(pane.get_state((0, 0)), Some(State::Idle)); + /// + /// // We manually set the state to Dormant and observe the change + /// pane.get_mut((0, 0)).unwrap().set_state(State::Dormant); + /// assert_eq!(pane.get_state((0, 0)), Some(State::Dormant)); + /// ``` #[inline] pub fn get_state(&self, position: (usize, usize)) -> Option { self.get(position).map(|x| x.state().clone()) } /// Sets the signal for the tile at `position` to `signal`. - /// Returns `Some` iff: - /// - the tile exists - /// - the tile accepts a signal (ie. it isn't empty) + /// Returns `Some(())` if the tile exists and the tile can have a signal. + /// + /// This function does not check the tile's [`accepts_signal`](Tile::accepts_signal) method. + /// It will also overwrite any signal already present. + /// + /// # Example + /// + /// ``` + /// use stackline::prelude::*; + /// use stackline::tile::Diode; + /// + /// let mut pane = Pane::empty(2, 1).unwrap(); + /// + /// pane.set_tile((0, 0), Diode::new(Direction::Right)); + /// pane.set_tile((1, 0), Diode::new(Direction::Down)); + /// + /// // The signal for a tile is initially None + /// assert!(pane.get((0, 0)).unwrap().signal().is_none()); + /// + /// // We set it to something else + /// pane.set_signal((0, 0), stackline::signal!((0, 0), Direction::Right)).unwrap(); + /// + /// assert!(pane.get((0, 0)).unwrap().signal().is_some()); + /// ``` #[inline] pub fn set_signal(&mut self, position: (usize, usize), mut signal: Signal) -> Option<()> { signal.set_position(position); @@ -116,6 +212,19 @@ impl Pane { } } + /// Returns `true` if `position` is within the bounds of the pane. + /// Returns `false` otherwise. + /// + /// # Examples + /// + /// ``` + /// # use stackline::prelude::*; + /// let pane = Pane::empty(2, 3).unwrap(); + /// + /// assert!(pane.in_bounds((0, 0))); + /// assert!(pane.in_bounds((1, 2))); + /// assert!(!pane.in_bounds((10, 10))); + /// ``` #[inline] pub fn in_bounds(&self, position: (usize, usize)) -> bool { position.0 < self.width.get() && position.1 < self.height.get()