🔥 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
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).
// Note that the next three lines can be shortened to `ctx.accepts_direction(signal.direction())`
if let Some((pos, tile)) = ctx.get_offset(signal.direction().into_offset()) {
// Then, check that `tile` accepts signals
if tile.accepts_signal(signal.direction()) {
// Finally, send the signal
ctx.send(pos, signal).unwrap_or_else(|| unreachable!());
}
// Send the signal along: first, get the offset (Δx, Δy) associated with its direction and the position at (x+Δx,y+Δy).
if let Some(pos) = ctx.offset(signal.direction().into_offset()) {
// Finally, send the signal
let _ = ctx.send(pos, signal.direction(), signal);
}
}
}
@ -315,8 +311,8 @@ impl<'a> UpdateContext<'a> {
/// # impl Tile for MyTile {
/// fn update<'b>(&'b mut self, mut ctx: UpdateContext<'b>) {
/// if let Some(signal) = ctx.take_signal() {
/// if let Some(pos) = ctx.accepts_direction(Direction::Down) {
/// ctx.send(pos, signal);
/// if let Some(pos) = ctx.offset(Direction::Down.into_offset()) {
/// 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.
/// 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
///
/// 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.
#[ensures(
!self.in_bounds(position) -> ret.is_none(),
!self.in_bounds(position) -> ret.is_err(),
"Should return None if position is out of bounds"
)]
#[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"
)]
pub fn force_send(&mut self, position: (usize, usize), mut signal: Signal) -> Option<()> {
signal.set_position(position);
pub fn force_send(&mut self, position: (usize, usize), mut signal: Signal) -> Result<(), SendError> {
if !self.in_bounds(position) {
return None;
return Err(SendError(signal));
}
signal.set_position(position);
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
///
/// 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.
#[ensures(
!self.in_bounds(position) -> ret.is_none(),
!self.in_bounds(position) -> ret.is_err(),
"Should return None if position is out of bounds"
)]
#[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"
)]
pub fn send(&mut self, position: (usize, usize), signal: Signal) -> Option<()> {
if self.accepts_signal(position, signal.direction()) {
self.force_send(position, signal)
pub fn send(&mut self, position: (usize, usize), direction: Direction, signal: Signal) -> Result<(), SendError> {
if self.accepts_signal(position, direction) {
let original_direction = signal.direction();
self.force_send(position, signal.moved(direction)).map_err(|e| {
SendError(e.0.moved(original_direction))
})
} 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)
/// after every tile was updated.
pub(crate) struct UpdateCommit {

@ -98,7 +98,7 @@ impl Signal {
/// if let Some(signal) = ctx.take_signal() {
/// // We have a signal, see if it can be sent down
/// 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_rules! test_tile_setup {
( $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:
/// if let Some(right_position) = context.offset((1, 0)) {
/// // Then, send the signal!
/// // We also need to tell the signal that it is moving to the right.
/// context.send(right_position, signal.moved(Direction::Right));
/// // Then, send the signal! We also need to tell `send`
/// // that the signal is moving to the right.
/// context.send(right_position, Direction::Right, signal);
/// }
/// }
///

@ -1,6 +1,5 @@
//! Wires and diodes
// use super::*;
use crate::prelude::*;
use crate::tile::prelude::*;
@ -22,7 +21,7 @@ impl Tile for Wire {
}
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()) {
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>) {
if let Some(signal) = std::mem::take(&mut self.signal) {
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