🔥 SendError

main
Shad Amethyst 2 years ago
parent da76a3f075
commit f04531c1d9
Signed by: amethyst
GPG Key ID: D970C8DD1D6DEE36

@ -45,14 +45,10 @@ use std::ptr::NonNull;
// Update the internal state // Update the internal state
self.0 += 1; self.0 += 1;
// Send the signal along: first, get the offset (Δx, Δy) associated with its direction and the tile at (x+Δx,y+Δy). // Send the signal along: first, get the offset (Δx, Δy) associated with its direction and the position at (x+Δx,y+Δy).
// Note that the next three lines can be shortened to `ctx.accepts_direction(signal.direction())` if let Some(pos) = ctx.offset(signal.direction().into_offset()) {
if let Some((pos, tile)) = ctx.get_offset(signal.direction().into_offset()) { // Finally, send the signal
// Then, check that `tile` accepts signals let _ = ctx.send(pos, signal.direction(), signal);
if tile.accepts_signal(signal.direction()) {
// Finally, send the signal
ctx.send(pos, signal).unwrap_or_else(|| unreachable!());
}
} }
} }
} }
@ -315,8 +311,8 @@ impl<'a> UpdateContext<'a> {
/// # impl Tile for MyTile { /// # impl Tile for MyTile {
/// fn update<'b>(&'b mut self, mut ctx: UpdateContext<'b>) { /// fn update<'b>(&'b mut self, mut ctx: UpdateContext<'b>) {
/// if let Some(signal) = ctx.take_signal() { /// if let Some(signal) = ctx.take_signal() {
/// if let Some(pos) = ctx.accepts_direction(Direction::Down) { /// if let Some(pos) = ctx.offset(Direction::Down.into_offset()) {
/// ctx.send(pos, signal); /// let _ = ctx.send(pos, Direction::Down, signal);
/// } /// }
/// } /// }
/// } /// }
@ -337,51 +333,57 @@ impl<'a> UpdateContext<'a> {
/// ///
/// Returns Some(()) if the signal was stored in a cell, None otherwise. /// Returns Some(()) if the signal was stored in a cell, None otherwise.
/// The target cell's state will be set to `Active` if it received the signal. /// The target cell's state will be set to `Active` if it received the signal.
/// The signal's `position` will be set to `pos`. /// The signal's `position` will be set to `position`.
///
/// You should change the `direction` of the signal before calling this function.
/// ///
/// # Note /// # Note
/// ///
/// The actions of this function will only be executed *after* all the tiles of the [`Pane`] were [`updated`](Pane::step). /// The actions of this function will only be executed *after* all the tiles of the [`Pane`] were [`updated`](Pane::step).
/// See [`keep`](UpdateContext::keep) for a variant of this method that takes effect immediately. /// See [`keep`](UpdateContext::keep) for a variant of this method that takes effect immediately.
#[ensures( #[ensures(
!self.in_bounds(position) -> ret.is_none(), !self.in_bounds(position) -> ret.is_err(),
"Should return None if position is out of bounds" "Should return None if position is out of bounds"
)] )]
#[ensures( #[ensures(
ret.is_some() -> self.commit.signals.iter().find(|(x, y, _)| position == (*x, *y)).is_some(), ret.is_ok() -> self.commit.signals.iter().find(|(x, y, _)| position == (*x, *y)).is_some(),
"Should add an entry in self.commit.signals if result is Some" "Should add an entry in self.commit.signals if result is Some"
)] )]
pub fn force_send(&mut self, position: (usize, usize), mut signal: Signal) -> Option<()> { pub fn force_send(&mut self, position: (usize, usize), mut signal: Signal) -> Result<(), SendError> {
signal.set_position(position);
if !self.in_bounds(position) { if !self.in_bounds(position) {
return None; return Err(SendError(signal));
} }
signal.set_position(position);
self.commit.send(position, signal); self.commit.send(position, signal);
Some(()) Ok(())
} }
/// Sends a signal to `position` if there is a tile at `position` that will accept our signal /// Sends a signal to `position` if there is a tile at `position` that will accept our signal.
/// Sets the signal direction to `direction` and its position to `position`.
/// ///
/// # Note /// # Note
/// ///
/// The actions of this function will only be executed *after* all the tiles of the [`Pane`] were [`updated`](Pane::step). /// The actions of this function will only be executed *after* all the tiles of the [`Pane`] were [`updated`](Pane::step).
/// See [`keep`](UpdateContext::keep) for a variant of this method that takes effect immediately. /// See [`keep`](UpdateContext::keep) for a variant of this method that takes effect immediately.
#[ensures( #[ensures(
!self.in_bounds(position) -> ret.is_none(), !self.in_bounds(position) -> ret.is_err(),
"Should return None if position is out of bounds" "Should return None if position is out of bounds"
)] )]
#[ensures( #[ensures(
ret.is_some() -> self.commit.signals.iter().find(|(x, y, _)| position == (*x, *y)).is_some(), ret.is_ok() -> self.commit.signals.iter().find(|(x, y, _)| position == (*x, *y)).is_some(),
"Should add an entry in self.commit.signals if result is Some" "Should add an entry in self.commit.signals if result is Some"
)] )]
pub fn send(&mut self, position: (usize, usize), signal: Signal) -> Option<()> { pub fn send(&mut self, position: (usize, usize), direction: Direction, signal: Signal) -> Result<(), SendError> {
if self.accepts_signal(position, signal.direction()) { if self.accepts_signal(position, direction) {
self.force_send(position, signal) let original_direction = signal.direction();
self.force_send(position, signal.moved(direction)).map_err(|e| {
SendError(e.0.moved(original_direction))
})
} else { } else {
None Err(SendError(signal))
} }
} }
@ -438,6 +440,22 @@ impl<'a> UpdateContext<'a> {
} }
} }
pub struct SendError(pub Signal);
impl std::fmt::Debug for SendError {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fmt.debug_struct("SendError")
.field("signal", &"Signal {{...}}")
.finish()
}
}
impl std::fmt::Display for SendError {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(fmt, "Couldn't send signal!")
}
}
/// Temporarily holds a list of actions to be made on a given Pane, which should be [applied](UpdateCommit::apply) /// Temporarily holds a list of actions to be made on a given Pane, which should be [applied](UpdateCommit::apply)
/// after every tile was updated. /// after every tile was updated.
pub(crate) struct UpdateCommit { pub(crate) struct UpdateCommit {

@ -98,7 +98,7 @@ impl Signal {
/// if let Some(signal) = ctx.take_signal() { /// if let Some(signal) = ctx.take_signal() {
/// // We have a signal, see if it can be sent down /// // We have a signal, see if it can be sent down
/// if let Some(pos) = ctx.accepts_direction(direction) { /// if let Some(pos) = ctx.accepts_direction(direction) {
/// ctx.send(pos, signal.moved(direction)); /// ctx.send(pos, direction, signal);
/// } /// }
/// } /// }
/// } /// }

@ -1,5 +1,3 @@
use super::*;
#[macro_export] #[macro_export]
macro_rules! test_tile_setup { macro_rules! test_tile_setup {
( $width:expr, $height:expr, [ $( $x:expr ),* ] ) => {{ ( $width:expr, $height:expr, [ $( $x:expr ),* ] ) => {{

@ -73,9 +73,9 @@ include!(concat!(env!("OUT_DIR"), "/anytile.rs"));
/// ///
/// // First, get the coordinates of the tile to our right: /// // First, get the coordinates of the tile to our right:
/// if let Some(right_position) = context.offset((1, 0)) { /// if let Some(right_position) = context.offset((1, 0)) {
/// // Then, send the signal! /// // Then, send the signal! We also need to tell `send`
/// // We also need to tell the signal that it is moving to the right. /// // that the signal is moving to the right.
/// context.send(right_position, signal.moved(Direction::Right)); /// context.send(right_position, Direction::Right, signal);
/// } /// }
/// } /// }
/// ///

@ -1,6 +1,5 @@
//! Wires and diodes //! Wires and diodes
// use super::*;
use crate::prelude::*; use crate::prelude::*;
use crate::tile::prelude::*; use crate::tile::prelude::*;
@ -22,7 +21,7 @@ impl Tile for Wire {
} }
if let Some(pos) = context.accepts_direction(direction) { if let Some(pos) = context.accepts_direction(direction) {
context.force_send(pos, signal.clone_move(direction)); context.force_send(pos, signal.clone_move(direction)).unwrap_or_else(|_| unreachable!());
} }
} }
} }
@ -65,7 +64,7 @@ impl Tile for Diode {
} }
if let Some(pos) = context.offset(self.0.into_offset()) { if let Some(pos) = context.offset(self.0.into_offset()) {
context.send(pos, signal.moved(self.0)); let _ = context.send(pos, self.0, signal);
} }
} }
@ -105,7 +104,7 @@ impl Tile for Resistor {
fn update<'b>(&'b mut self, mut context: UpdateContext<'b>) { fn update<'b>(&'b mut self, mut context: UpdateContext<'b>) {
if let Some(signal) = std::mem::take(&mut self.signal) { if let Some(signal) = std::mem::take(&mut self.signal) {
if let Some(pos) = context.offset(self.direction.into_offset()) { if let Some(pos) = context.offset(self.direction.into_offset()) {
context.send(pos, signal.moved(self.direction)); let _ = context.send(pos, self.direction, signal);
} }
} }

Loading…
Cancel
Save