Pane::get_as, Pane::get_mut_as, Pane::borrow_mut_as

main
Shad Amethyst 2 years ago
parent 236c97d2bc
commit 76cefb81a9
Signed by: amethyst
GPG Key ID: D970C8DD1D6DEE36

@ -10,7 +10,7 @@ edition = "2021"
palette = "0.6" palette = "0.6"
enum_dispatch = "0.3" enum_dispatch = "0.3"
contracts = { version = "0.6.3", features = ["override_debug"] } contracts = { version = "0.6.3", features = ["override_debug"] }
veccell = "0.2" veccell = "0.2.1"
pathfinding = "3.0" pathfinding = "3.0"
[dev-dependencies] [dev-dependencies]

@ -144,7 +144,7 @@ impl Pane {
} }
// TODO: Have a Result instead of an Option // TODO: Have a Result instead of an Option
/// Returns an immutable referenec to the [`Tile`] at `position`. /// Returns an immutable reference to the [`FullTile`] at `position`.
/// If `position` is out of bounds, returns `None`. /// If `position` is out of bounds, returns `None`.
/// ///
/// # Example /// # Example
@ -166,7 +166,42 @@ impl Pane {
return None; return None;
} }
self.tiles.borrow(position.1 * self.width.get() + position.0) self.tiles
.borrow(position.1 * self.width.get() + position.0)
}
/// Returns an immutable reference to the [`Tile`] at `position`.
/// If `position` is out of bounds, returns `None`.
/// If the tile at position isn't an instance of `T`, returns `None`.
///
/// `T` may be any [`Tile`] that is a member of [`AnyTile`].
///
/// # 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 wire = pane.get_as::<Wire>((0, 0)).unwrap();
/// assert_eq!(wire, Wire::new(Orientation::Horizontal));
/// ```
// TODO: error types
#[inline]
pub fn get_as<'b, T: Tile>(&'b self, position: (usize, usize)) -> Option<VecRef<'b, T>>
where
for<'c> &'c AnyTile: TryInto<&'c T>,
{
let tile = self.get(position)?;
VecRef::try_map(tile, |tile| {
tile.get()
.ok_or(())
.and_then(|anytile: &AnyTile| anytile.try_into().map_err(|_| ()))
})
.ok()
} }
/// Returns a mutable reference to the [`Tile`] at `position`. /// Returns a mutable reference to the [`Tile`] at `position`.
@ -195,7 +230,44 @@ impl Pane {
.get_mut(position.1 * self.width.get() + position.0) .get_mut(position.1 * self.width.get() + position.0)
} }
pub(crate) fn borrow_mut<'b>(&'b self, position: (usize, usize)) -> Option<VecRefMut<'b, FullTile>> { /// Returns a mutable reference to the [`Tile`] at `position`.
/// If `position` is out of bounds, returns `None`.
/// If the tile at position isn't an instance of `T`, returns `None`.
///
/// `T` may be any [`Tile`] that is a member of [`AnyTile`].
///
/// # 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 mut wire = pane.get_mut_as::<Wire>((0, 0)).unwrap();
/// assert_eq!(*wire, Wire::new(Orientation::Horizontal));
/// *wire = Wire::new(Orientation::Vertical);
/// ```
#[inline]
pub fn get_mut_as<'b, T: Tile>(&'b mut self, position: (usize, usize)) -> Option<&'b mut T>
where
for<'c> &'c mut AnyTile: TryInto<&'c mut T>,
{
let tile = self.get_mut(position)?.get_mut()?;
tile.try_into().ok()
}
/// Returns a mutable borrow to the [`Tile`] at `position`.
///
/// This function does not need a mutable reference to `self`, and makes use
/// of [`VecCell`]'s ability to provide interior mutability for one item at a time.
#[inline]
pub(crate) fn borrow_mut<'b>(
&'b self,
position: (usize, usize),
) -> Option<VecRefMut<'b, FullTile>> {
if !self.in_bounds(position) { if !self.in_bounds(position) {
return None; return None;
} }
@ -204,6 +276,45 @@ impl Pane {
.borrow_mut(position.1 * self.width.get() + position.0) .borrow_mut(position.1 * self.width.get() + position.0)
} }
/// Returns a mutable borrow to the [`Tile`] at `position`.
/// If `position` is out of bounds, returns `None`.
/// If the tile at position isn't an instance of `T`, returns `None`.
///
/// `T` may be any [`Tile`] that is a member of [`AnyTile`].
///
/// This function does not need a mutable reference to `self`, and makes use
/// of [`VecCell`]'s ability to provide interior mutability for one item at a time.
///
/// # 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 pane = pane;
///
/// let mut wire = pane.borrow_mut_as::<Wire>((0, 0)).unwrap();
/// assert_eq!(wire, Wire::new(Orientation::Horizontal));
/// *wire = Wire::new(Orientation::Vertical);
/// ```
#[inline]
pub fn borrow_mut_as<'b, T: Tile>(&'b self, position: (usize, usize)) -> Option<VecRefMut<'b, T>>
where
for<'c> &'c mut AnyTile: TryInto<&'c mut T>,
{
let tile = self.borrow_mut(position)?;
VecRefMut::try_map(tile, |tile| {
tile.get_mut()
.ok_or(())
.and_then(|anytile: &mut AnyTile| anytile.try_into().map_err(|_| ()))
})
.ok()
}
/// Sets the tile at `position` to `tile`. `T` must either implement [`Tile`] or be `()`. /// Sets the tile at `position` to `tile`. `T` must either implement [`Tile`] or be `()`.
#[inline] #[inline]
#[ensures(self.in_bounds(position) -> ret.is_some())] #[ensures(self.in_bounds(position) -> ret.is_some())]
@ -515,7 +626,8 @@ mod test {
assert_eq!(surface.get(5 + 2, 3 + 2).unwrap().ch, '+'); assert_eq!(surface.get(5 + 2, 3 + 2).unwrap().ch, '+');
for y in 0..9 { for y in 0..9 {
for x in 0..9 { for x in 0..9 {
if (x, y) != (5 + 2, 3 + 1) && (x, y) != (5 + 3, 3 + 1) && (x, y) != (5 + 2, 3 + 2) { if (x, y) != (5 + 2, 3 + 1) && (x, y) != (5 + 3, 3 + 1) && (x, y) != (5 + 2, 3 + 2)
{
assert_eq!(surface.get(x, y), Some(TextChar::default())); assert_eq!(surface.get(x, y), Some(TextChar::default()));
} }
} }

@ -353,11 +353,11 @@ mod test {
for n in 0..2 { for n in 0..2 {
world.step(); world.step();
// TODO: pane.get_as::<Sender>(coords) let sender: VecRef<'_, Sender> = world
let sender: VecRef<'_, Sender> = VecRef::map( .get_pane("main")
world.get_pane("main").unwrap().get((0, 0)).unwrap(), .unwrap()
|tile| tile.get().unwrap().try_into().unwrap(), .get_as::<Sender>((0, 0))
); .unwrap();
assert!(sender.signals.len() == 1); assert!(sender.signals.len() == 1);
assert!(sender.signals[0].1 == n); assert!(sender.signals[0].1 == n);
@ -370,10 +370,11 @@ mod test {
world.step(); world.step();
let sender: VecRef<'_, Sender> = VecRef::map( let sender: VecRef<'_, Sender> = world
world.get_pane("main").unwrap().get((0, 0)).unwrap(), .get_pane("main")
|tile| tile.get().unwrap().try_into().unwrap(), .unwrap()
); .get_as::<Sender>((0, 0))
.unwrap();
assert!(sender.signals.len() == 0); assert!(sender.signals.len() == 0);
@ -397,11 +398,11 @@ mod test {
world.set_pane(String::from("main"), main_pane); world.set_pane(String::from("main"), main_pane);
world.set_pane(String::from("second"), second_pane); world.set_pane(String::from("second"), second_pane);
// TODO: borrow_mut_as::<Sender>(coords) let mut tile = world
let mut tile: VecRefMut<Sender> = VecRefMut::map( .get_pane("main")
world.get_pane("main").unwrap().borrow_mut((0, 0)).unwrap(), .unwrap()
|tile| tile.get_mut().unwrap().try_into().unwrap(), .borrow_mut_as::<Sender>((0, 0))
); .unwrap();
tile.calculate_path((0, 0), &world); tile.calculate_path((0, 0), &world);
@ -412,10 +413,11 @@ mod test {
world.get_pane_mut("second").unwrap().set_position((2, 2)); world.get_pane_mut("second").unwrap().set_position((2, 2));
let mut tile: VecRefMut<Sender> = VecRefMut::map( let mut tile = world
world.get_pane("main").unwrap().borrow_mut((0, 0)).unwrap(), .get_pane("main")
|tile| tile.get_mut().unwrap().try_into().unwrap(), .unwrap()
); .borrow_mut_as::<Sender>((0, 0))
.unwrap();
tile.calculate_path((0, 0), &world); tile.calculate_path((0, 0), &world);

@ -3,7 +3,7 @@
use crate::prelude::*; use crate::prelude::*;
// use crate::tile::prelude::*; // use crate::tile::prelude::*;
#[derive(Clone, Debug)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct Wire(Orientation); pub struct Wire(Orientation);
impl Wire { impl Wire {

Loading…
Cancel
Save