#![deny(rustdoc::broken_intra_doc_links)]
use crate::{
CoordId, IntervalId,
grids::{HasCoordIdRange, traits::HasIntervalIdRange},
scalars::{IndexId, NumIntervals, PositiveIntTrait, PositiveNumPoints1D},
};
use serde::{Deserialize, Serialize};
pub(crate) mod sealed {
use crate::intervals::{IntervalLowerClosedUpperOpen, IntervalLowerOpenUpperClosed};
use num_valid::RealScalar;
pub trait SupportsCircularTopology {}
impl<T: RealScalar> SupportsCircularTopology for IntervalLowerClosedUpperOpen<T> {}
impl<T: RealScalar> SupportsCircularTopology for IntervalLowerOpenUpperClosed<T> {}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Topology1D {
RealLine,
Circle,
}
impl Topology1D {
#[inline(always)]
pub fn is_periodic(&self) -> bool {
matches!(self, Topology1D::Circle)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Side {
Left,
Right,
}
impl Side {
#[inline(always)]
pub fn is_left(&self) -> bool {
matches!(&self, Side::Left)
}
#[inline(always)]
pub fn is_right(&self) -> bool {
matches!(&self, Side::Right)
}
}
pub trait HasSide: Copy + Clone + std::fmt::Debug + PartialEq + Eq {
fn side(&self) -> Side;
}
impl HasSide for Side {
#[inline(always)]
fn side(&self) -> Side {
*self
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct IntervalSide {
pub interval_index: usize,
pub side: Side,
}
impl IntervalSide {
#[inline(always)]
pub fn new(interval_index: usize, side: Side) -> Self {
Self {
interval_index,
side,
}
}
#[inline(always)]
pub fn coord_index(&self) -> usize {
match self.side {
Side::Left => self.interval_index,
Side::Right => self.interval_index + 1,
}
}
#[inline(always)]
pub fn interval_index(&self) -> usize {
self.interval_index
}
}
impl HasSide for IntervalSide {
#[inline(always)]
fn side(&self) -> Side {
self.side
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Neighbors1D<Id> {
left: Option<Id>,
right: Option<Id>,
}
impl<Id: Copy> Neighbors1D<Id> {
#[inline(always)]
pub fn left(&self) -> Option<Id> {
self.left
}
#[inline(always)]
pub fn right(&self) -> Option<Id> {
self.right
}
}
pub trait IndexSpace1D {
type Counter: PositiveIntTrait;
type Id: IndexId;
fn topology(&self) -> &Topology1D;
fn count(&self) -> Self::Counter;
fn first_id(&self) -> Self::Id;
fn last_id(&self) -> Self::Id;
}
pub trait Adjacency1D: IndexSpace1D {
fn neighbor(&self, id: &Self::Id, side: &Side) -> Option<Self::Id> {
match side {
Side::Left => self.left_neighbor(id),
Side::Right => self.right_neighbor(id),
}
}
fn left_neighbor(&self, id: &Self::Id) -> Option<Self::Id> {
let first = *self.first_id().as_ref();
let last = *self.last_id().as_ref();
let raw = *id.as_ref();
more_asserts::debug_assert_ge!(raw, first, "ID {} is below first_id {}", raw, first);
more_asserts::debug_assert_le!(raw, last, "ID {} is above last_id {}", raw, last);
if raw == first {
match self.topology() {
Topology1D::RealLine => None,
Topology1D::Circle => Some(self.last_id()),
}
} else {
Some(Self::Id::new(raw - 1))
}
}
fn right_neighbor(&self, id: &Self::Id) -> Option<Self::Id> {
let first = *self.first_id().as_ref();
let last = *self.last_id().as_ref();
let raw = *id.as_ref();
more_asserts::debug_assert_ge!(raw, first, "ID {} is below first_id {}", raw, first);
more_asserts::debug_assert_le!(raw, last, "ID {} is above last_id {}", raw, last);
if raw == last {
match self.topology() {
Topology1D::RealLine => None,
Topology1D::Circle => Some(self.first_id()),
}
} else {
Some(Self::Id::new(raw + 1))
}
}
fn neighbors(&self, id: &Self::Id) -> Neighbors1D<Self::Id> {
Neighbors1D {
left: self.left_neighbor(id),
right: self.right_neighbor(id),
}
}
fn connectivity(&self) -> impl Iterator<Item = (Self::Id, Self::Id)> + '_ {
let first = *self.first_id().as_ref();
let last = *self.last_id().as_ref();
(first..=last).filter_map(move |raw| {
let id = Self::Id::new(raw);
self.right_neighbor(&id).map(|right| (id, right))
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct CoordIndexSpace1D {
topology: Topology1D,
first_coord_id: CoordId,
last_coord_id: CoordId,
}
impl CoordIndexSpace1D {
#[must_use]
pub fn new_non_periodic(num_intervals: NumIntervals) -> Self {
Self {
topology: Topology1D::RealLine,
first_coord_id: CoordId::new(0),
last_coord_id: CoordId::new(num_intervals.into_inner()), }
}
pub(crate) fn new_periodic_upper_open_interval(num_intervals: NumIntervals) -> Self {
let num_coords = num_intervals.into_inner() + 1;
Self {
topology: Topology1D::Circle,
first_coord_id: CoordId::new(0),
last_coord_id: CoordId::new(num_coords - 2),
}
}
pub(crate) fn new_periodic_lower_open_interval(num_intervals: NumIntervals) -> Self {
let num_coords = num_intervals.into_inner() + 1;
Self {
topology: Topology1D::Circle,
first_coord_id: CoordId::new(1),
last_coord_id: CoordId::new(num_coords - 1),
}
}
}
impl HasCoordIdRange for CoordIndexSpace1D {
fn first_coord_id(&self) -> CoordId {
self.first_coord_id
}
fn last_coord_id(&self) -> CoordId {
self.last_coord_id
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct IntervalIndexSpace1D {
topology: Topology1D,
count: NumIntervals,
}
impl IntervalIndexSpace1D {
#[must_use]
pub fn new(topology: Topology1D, count: NumIntervals) -> Self {
Self { topology, count }
}
}
impl HasIntervalIdRange for IntervalIndexSpace1D {
fn first_interval_id(&self) -> IntervalId {
IntervalId::new(0)
}
fn last_interval_id(&self) -> IntervalId {
IntervalId::new(*self.count.as_ref() - 1)
}
}
impl IndexSpace1D for CoordIndexSpace1D {
type Counter = PositiveNumPoints1D;
type Id = CoordId;
fn topology(&self) -> &Topology1D {
&self.topology
}
fn count(&self) -> Self::Counter {
self.num_coord_ids()
}
#[inline(always)]
fn first_id(&self) -> CoordId {
self.first_coord_id
}
#[inline(always)]
fn last_id(&self) -> CoordId {
self.last_coord_id
}
}
impl IndexSpace1D for IntervalIndexSpace1D {
type Counter = NumIntervals;
type Id = IntervalId;
fn topology(&self) -> &Topology1D {
&self.topology
}
fn count(&self) -> Self::Counter {
self.num_intervals()
}
#[inline(always)]
fn first_id(&self) -> IntervalId {
IntervalId::new(0)
}
#[inline(always)]
fn last_id(&self) -> IntervalId {
IntervalId::new(*self.count.as_ref() - 1)
}
}
impl Adjacency1D for CoordIndexSpace1D {}
impl Adjacency1D for IntervalIndexSpace1D {}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Grid1DIndexSpaces {
interval_index_space: IntervalIndexSpace1D,
coord_index_space: CoordIndexSpace1D,
}
impl Grid1DIndexSpaces {
pub(crate) fn new_non_periodic(num_intervals: NumIntervals) -> Self {
let interval_index_space = IntervalIndexSpace1D::new(Topology1D::RealLine, num_intervals);
let coord_index_space = CoordIndexSpace1D::new_non_periodic(num_intervals);
Self {
interval_index_space,
coord_index_space,
}
}
pub(crate) fn new_periodic_upper_open_interval(num_intervals: NumIntervals) -> Self {
let interval_index_space = IntervalIndexSpace1D::new(Topology1D::Circle, num_intervals);
let coord_index_space = CoordIndexSpace1D::new_periodic_upper_open_interval(num_intervals);
Self {
interval_index_space,
coord_index_space,
}
}
pub(crate) fn new_periodic_lower_open_interval(num_intervals: NumIntervals) -> Self {
let topology = Topology1D::Circle;
let interval_index_space = IntervalIndexSpace1D::new(topology, num_intervals);
let coord_index_space = CoordIndexSpace1D::new_periodic_lower_open_interval(num_intervals);
Self {
interval_index_space,
coord_index_space,
}
}
#[inline(always)]
pub fn interval_index_space(&self) -> &IntervalIndexSpace1D {
&self.interval_index_space
}
#[inline(always)]
pub fn coord_index_space(&self) -> &CoordIndexSpace1D {
&self.coord_index_space
}
#[inline(always)]
pub fn topology(&self) -> &Topology1D {
self.interval_index_space.topology()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::scalars::{CoordId, IntervalId, NumIntervals};
use try_create::TryNew;
fn interval_space(topology: Topology1D, n: usize) -> IntervalIndexSpace1D {
IntervalIndexSpace1D {
topology,
count: NumIntervals::try_new(n).unwrap(),
}
}
mod side {
use super::*;
#[test]
fn side_equality() {
assert_eq!(Side::Left, Side::Left);
assert_eq!(Side::Right, Side::Right);
assert_ne!(Side::Right, Side::Left);
}
#[test]
fn is_left() {
assert!(Side::Left.is_left());
assert!(!Side::Right.is_left());
}
#[test]
fn is_right() {
assert!(Side::Right.is_right());
assert!(!Side::Left.is_right());
}
#[test]
fn has_side_for_side_returns_self() {
assert_eq!(Side::Left.side(), Side::Left);
assert_eq!(Side::Right.side(), Side::Right);
}
#[test]
fn left_point_index() {
let data_3 = IntervalSide::new(3, Side::Left);
assert_eq!(data_3.coord_index(), 3);
let data_0 = IntervalSide::new(0, Side::Left);
assert_eq!(data_0.coord_index(), 0);
}
#[test]
fn right_point_index() {
let data_3 = IntervalSide::new(3, Side::Right);
assert_eq!(data_3.coord_index(), 4);
let data_0 = IntervalSide::new(0, Side::Right);
assert_eq!(data_0.coord_index(), 1);
}
#[test]
fn interval_side_interval_index_getter() {
let s = IntervalSide::new(7, Side::Left);
assert_eq!(s.interval_index(), 7);
let s2 = IntervalSide::new(0, Side::Right);
assert_eq!(s2.interval_index(), 0);
}
#[test]
fn has_side_for_interval_side() {
let left = IntervalSide::new(2, Side::Left);
assert_eq!(left.side(), Side::Left);
let right = IntervalSide::new(5, Side::Right);
assert_eq!(right.side(), Side::Right);
}
}
mod topology {
use super::*;
#[test]
fn topology1d_real_line_eq_self() {
assert_eq!(Topology1D::RealLine, Topology1D::RealLine);
}
#[test]
fn topology1d_circle_eq_self() {
assert_eq!(Topology1D::Circle, Topology1D::Circle);
}
#[test]
fn topology1d_real_line_ne_circle() {
assert_ne!(Topology1D::RealLine, Topology1D::Circle);
}
#[test]
fn topology1d_copy() {
let t = Topology1D::Circle;
let t2 = t; assert_eq!(t, t2);
}
#[test]
fn is_periodic_real_line_is_false() {
assert!(!Topology1D::RealLine.is_periodic());
}
#[test]
fn is_periodic_circle_is_true() {
assert!(Topology1D::Circle.is_periodic());
}
}
mod neighbors1d {
use super::*;
#[test]
fn neighbors1d_construction_and_eq() {
let a = Neighbors1D::<IntervalId> {
left: Some(IntervalId::new(0)),
right: Some(IntervalId::new(2)),
};
let b = Neighbors1D::<IntervalId> {
left: Some(IntervalId::new(0)),
right: Some(IntervalId::new(2)),
};
assert_eq!(a, b);
}
#[test]
fn neighbors1d_none_variants() {
let a = Neighbors1D::<IntervalId> {
left: None,
right: None,
};
assert_eq!(
a,
Neighbors1D::<IntervalId> {
left: None,
right: None
}
);
}
#[test]
fn neighbors1d_copy() {
let a = Neighbors1D::<IntervalId> {
left: Some(IntervalId::new(1)),
right: None,
};
let b = a; assert_eq!(a, b);
}
}
#[test]
fn point_index_space_topology_and_count() {
let s = CoordIndexSpace1D::new_non_periodic(NumIntervals::try_new(4).unwrap());
assert_eq!(*s.topology(), Topology1D::RealLine);
assert_eq!(*s.count().as_ref(), 5);
}
#[test]
fn interval_index_space_topology_and_count() {
let s = interval_space(Topology1D::Circle, 4);
assert_eq!(*s.topology(), Topology1D::Circle);
assert_eq!(*s.count().as_ref(), 4);
}
#[test]
fn left_neighbor_open_first_element_is_none() {
let s = interval_space(Topology1D::RealLine, 5);
assert_eq!(s.left_neighbor(&IntervalId::new(0)), None);
}
#[test]
fn left_neighbor_open_middle() {
let s = interval_space(Topology1D::RealLine, 5);
assert_eq!(
s.left_neighbor(&IntervalId::new(3)),
Some(IntervalId::new(2))
);
}
#[test]
fn left_neighbor_open_last_element() {
let s = interval_space(Topology1D::RealLine, 5);
assert_eq!(
s.left_neighbor(&IntervalId::new(4)),
Some(IntervalId::new(3))
);
}
#[test]
fn left_neighbor_periodic_first_element_wraps() {
let s = interval_space(Topology1D::Circle, 5);
assert_eq!(
s.left_neighbor(&IntervalId::new(0)),
Some(IntervalId::new(4))
);
}
#[test]
fn left_neighbor_periodic_middle() {
let s = interval_space(Topology1D::Circle, 5);
assert_eq!(
s.left_neighbor(&IntervalId::new(2)),
Some(IntervalId::new(1))
);
}
#[test]
fn left_neighbor_periodic_last_element() {
let s = interval_space(Topology1D::Circle, 5);
assert_eq!(
s.left_neighbor(&IntervalId::new(4)),
Some(IntervalId::new(3))
);
}
#[test]
fn right_neighbor_open_first_element() {
let s = interval_space(Topology1D::RealLine, 5);
assert_eq!(
s.right_neighbor(&IntervalId::new(0)),
Some(IntervalId::new(1))
);
}
#[test]
fn right_neighbor_open_middle() {
let s = interval_space(Topology1D::RealLine, 5);
assert_eq!(
s.right_neighbor(&IntervalId::new(2)),
Some(IntervalId::new(3))
);
}
#[test]
fn right_neighbor_open_last_element_is_none() {
let s = interval_space(Topology1D::RealLine, 5);
assert_eq!(s.right_neighbor(&IntervalId::new(4)), None);
}
#[test]
fn right_neighbor_periodic_first_element() {
let s = interval_space(Topology1D::Circle, 5);
assert_eq!(
s.right_neighbor(&IntervalId::new(0)),
Some(IntervalId::new(1))
);
}
#[test]
fn right_neighbor_periodic_middle() {
let s = interval_space(Topology1D::Circle, 5);
assert_eq!(
s.right_neighbor(&IntervalId::new(2)),
Some(IntervalId::new(3))
);
}
#[test]
fn right_neighbor_periodic_last_element_wraps() {
let s = interval_space(Topology1D::Circle, 5);
assert_eq!(
s.right_neighbor(&IntervalId::new(4)),
Some(IntervalId::new(0))
);
}
#[test]
fn neighbors_open_interior() {
let s = interval_space(Topology1D::RealLine, 5);
assert_eq!(
s.neighbors(&IntervalId::new(2)),
Neighbors1D {
left: Some(IntervalId::new(1)),
right: Some(IntervalId::new(3))
}
);
}
#[test]
fn neighbors_open_left_boundary() {
let s = interval_space(Topology1D::RealLine, 5);
assert_eq!(
s.neighbors(&IntervalId::new(0)),
Neighbors1D {
left: None,
right: Some(IntervalId::new(1))
}
);
}
#[test]
fn neighbors_open_right_boundary() {
let s = interval_space(Topology1D::RealLine, 5);
assert_eq!(
s.neighbors(&IntervalId::new(4)),
Neighbors1D {
left: Some(IntervalId::new(3)),
right: None
}
);
}
#[test]
fn neighbors_periodic_wraps_at_boundaries() {
let s = interval_space(Topology1D::Circle, 5);
assert_eq!(
s.neighbors(&IntervalId::new(0)),
Neighbors1D {
left: Some(IntervalId::new(4)),
right: Some(IntervalId::new(1))
}
);
assert_eq!(
s.neighbors(&IntervalId::new(4)),
Neighbors1D {
left: Some(IntervalId::new(3)),
right: Some(IntervalId::new(0))
}
);
}
#[test]
fn neighbors_open_single_element_both_none() {
let s = interval_space(Topology1D::RealLine, 1);
assert_eq!(
s.neighbors(&IntervalId::new(0)),
Neighbors1D {
left: None,
right: None
}
);
}
#[test]
fn neighbors_periodic_single_element_wraps_to_itself() {
let s = interval_space(Topology1D::Circle, 1);
assert_eq!(
s.neighbors(&IntervalId::new(0)),
Neighbors1D {
left: Some(IntervalId::new(0)),
right: Some(IntervalId::new(0))
}
);
}
#[test]
fn neighbor_dispatch_left_and_right_open() {
let s = interval_space(Topology1D::RealLine, 5);
assert_eq!(
s.neighbor(&IntervalId::new(2), &Side::Left),
s.left_neighbor(&IntervalId::new(2))
);
assert_eq!(
s.neighbor(&IntervalId::new(2), &Side::Right),
s.right_neighbor(&IntervalId::new(2))
);
assert_eq!(s.neighbor(&IntervalId::new(0), &Side::Left), None);
assert_eq!(s.neighbor(&IntervalId::new(4), &Side::Right), None);
}
#[test]
fn neighbor_dispatch_left_and_right_periodic() {
let s = interval_space(Topology1D::Circle, 4);
assert_eq!(
s.neighbor(&IntervalId::new(0), &Side::Left),
Some(IntervalId::new(3))
); assert_eq!(
s.neighbor(&IntervalId::new(0), &Side::Right),
Some(IntervalId::new(1))
);
assert_eq!(
s.neighbor(&IntervalId::new(3), &Side::Right),
Some(IntervalId::new(0))
); }
#[test]
fn point_index_space_new_constructor() {
let num_intervals = NumIntervals::try_new(7).unwrap();
let s = CoordIndexSpace1D::new_non_periodic(num_intervals);
assert_eq!(*s.topology(), Topology1D::RealLine);
assert_eq!(*s.count().as_ref(), 8); assert_eq!(s.first_coord_id(), CoordId::new(0));
assert_eq!(s.last_coord_id(), CoordId::new(7));
let s = CoordIndexSpace1D::new_periodic_upper_open_interval(num_intervals);
assert_eq!(*s.topology(), Topology1D::Circle);
assert_eq!(*s.count().as_ref(), 7);
assert_eq!(s.first_coord_id(), CoordId::new(0));
assert_eq!(s.last_coord_id(), CoordId::new(6));
let s = CoordIndexSpace1D::new_periodic_lower_open_interval(num_intervals);
assert_eq!(*s.topology(), Topology1D::Circle);
assert_eq!(*s.count().as_ref(), 7);
assert_eq!(s.first_coord_id(), CoordId::new(1));
assert_eq!(s.last_coord_id(), CoordId::new(7));
}
#[test]
fn interval_index_space_new_constructor() {
let count = NumIntervals::try_new(3).unwrap();
let s = IntervalIndexSpace1D::new(Topology1D::RealLine, count);
assert_eq!(*s.topology(), Topology1D::RealLine);
assert_eq!(*s.count().as_ref(), 3);
}
mod grid1d_index_spaces {
use super::*;
#[test]
fn new_sets_correct_interval_count() {
let g = Grid1DIndexSpaces::new_non_periodic(NumIntervals::try_new(4).unwrap());
assert_eq!(*g.interval_index_space().count().as_ref(), 4);
}
#[test]
fn new_sets_point_count_as_n_plus_1() {
let g = Grid1DIndexSpaces::new_non_periodic(NumIntervals::try_new(4).unwrap());
assert_eq!(*g.coord_index_space().count().as_ref(), 5);
}
#[test]
fn topology_is_propagated_to_both_spaces() {
let g = Grid1DIndexSpaces::new_periodic_lower_open_interval(
NumIntervals::try_new(3).unwrap(),
);
assert_eq!(*g.interval_index_space().topology(), Topology1D::Circle);
assert_eq!(*g.coord_index_space().topology(), Topology1D::Circle);
let g = Grid1DIndexSpaces::new_periodic_upper_open_interval(
NumIntervals::try_new(3).unwrap(),
);
assert_eq!(*g.interval_index_space().topology(), Topology1D::Circle);
assert_eq!(*g.coord_index_space().topology(), Topology1D::Circle);
}
#[test]
fn interval_index_space_adjacency_uses_topology() {
let g = Grid1DIndexSpaces::new_periodic_lower_open_interval(
NumIntervals::try_new(4).unwrap(),
);
assert_eq!(
g.interval_index_space().right_neighbor(&IntervalId::new(3)),
Some(IntervalId::new(0))
);
let g = Grid1DIndexSpaces::new_periodic_upper_open_interval(
NumIntervals::try_new(4).unwrap(),
);
assert_eq!(
g.interval_index_space().right_neighbor(&IntervalId::new(3)),
Some(IntervalId::new(0))
);
}
mod coord_adjacency {
use super::*;
#[test]
fn non_periodic_interior() {
let s = CoordIndexSpace1D::new_non_periodic(NumIntervals::try_new(4).unwrap());
assert_eq!(s.left_neighbor(&CoordId::new(2)), Some(CoordId::new(1)));
assert_eq!(s.right_neighbor(&CoordId::new(2)), Some(CoordId::new(3)));
}
#[test]
fn non_periodic_left_boundary_is_none() {
let s = CoordIndexSpace1D::new_non_periodic(NumIntervals::try_new(4).unwrap());
assert_eq!(s.left_neighbor(&CoordId::new(0)), None);
}
#[test]
fn non_periodic_right_boundary_is_none() {
let s = CoordIndexSpace1D::new_non_periodic(NumIntervals::try_new(4).unwrap());
assert_eq!(s.right_neighbor(&CoordId::new(4)), None);
}
#[test]
fn periodic_upper_open_interior() {
let s = CoordIndexSpace1D::new_periodic_upper_open_interval(
NumIntervals::try_new(4).unwrap(),
);
assert_eq!(s.left_neighbor(&CoordId::new(2)), Some(CoordId::new(1)));
assert_eq!(s.right_neighbor(&CoordId::new(2)), Some(CoordId::new(3)));
}
#[test]
fn periodic_upper_open_left_wraps() {
let s = CoordIndexSpace1D::new_periodic_upper_open_interval(
NumIntervals::try_new(4).unwrap(),
);
assert_eq!(s.left_neighbor(&CoordId::new(0)), Some(CoordId::new(3)));
}
#[test]
fn periodic_upper_open_right_wraps() {
let s = CoordIndexSpace1D::new_periodic_upper_open_interval(
NumIntervals::try_new(4).unwrap(),
);
assert_eq!(s.right_neighbor(&CoordId::new(3)), Some(CoordId::new(0)));
}
#[test]
fn periodic_lower_open_interior() {
let s = CoordIndexSpace1D::new_periodic_lower_open_interval(
NumIntervals::try_new(4).unwrap(),
);
assert_eq!(s.left_neighbor(&CoordId::new(2)), Some(CoordId::new(1)));
assert_eq!(s.right_neighbor(&CoordId::new(2)), Some(CoordId::new(3)));
}
#[test]
fn periodic_lower_open_left_wraps() {
let s = CoordIndexSpace1D::new_periodic_lower_open_interval(
NumIntervals::try_new(4).unwrap(),
);
assert_eq!(s.left_neighbor(&CoordId::new(1)), Some(CoordId::new(4)));
}
#[test]
fn periodic_lower_open_right_wraps() {
let s = CoordIndexSpace1D::new_periodic_lower_open_interval(
NumIntervals::try_new(4).unwrap(),
);
assert_eq!(s.right_neighbor(&CoordId::new(4)), Some(CoordId::new(1)));
}
#[test]
fn neighbors_combined_non_periodic_interior() {
let s = CoordIndexSpace1D::new_non_periodic(NumIntervals::try_new(4).unwrap());
assert_eq!(
s.neighbors(&CoordId::new(2)),
Neighbors1D {
left: Some(CoordId::new(1)),
right: Some(CoordId::new(3))
}
);
}
#[test]
fn neighbors_combined_periodic_lower_open_boundary() {
let s = CoordIndexSpace1D::new_periodic_lower_open_interval(
NumIntervals::try_new(4).unwrap(),
);
assert_eq!(
s.neighbors(&CoordId::new(1)),
Neighbors1D {
left: Some(CoordId::new(4)),
right: Some(CoordId::new(2))
}
);
assert_eq!(
s.neighbors(&CoordId::new(4)),
Neighbors1D {
left: Some(CoordId::new(3)),
right: Some(CoordId::new(1))
}
);
}
#[test]
#[cfg(debug_assertions)]
#[should_panic]
fn panics_on_id_above_last() {
let s = CoordIndexSpace1D::new_non_periodic(NumIntervals::try_new(4).unwrap());
let _ = s.left_neighbor(&CoordId::new(5)); }
#[test]
#[cfg(debug_assertions)]
#[should_panic]
fn panics_on_id_below_first_lower_open() {
let s = CoordIndexSpace1D::new_periodic_lower_open_interval(
NumIntervals::try_new(4).unwrap(),
);
let _ = s.right_neighbor(&CoordId::new(0)); }
}
#[test]
fn clone_and_equality() {
let g1 = Grid1DIndexSpaces::new_periodic_lower_open_interval(
NumIntervals::try_new(5).unwrap(),
);
let g2 = g1.clone();
assert_eq!(g1, g2);
}
}
#[test]
#[cfg(debug_assertions)]
#[should_panic]
fn left_neighbor_panics_on_out_of_bounds_open() {
let s = interval_space(Topology1D::RealLine, 5);
let _ = s.left_neighbor(&IntervalId::new(5)); }
#[test]
#[cfg(debug_assertions)]
#[should_panic]
fn left_neighbor_panics_on_out_of_bounds_periodic() {
let s = interval_space(Topology1D::Circle, 4);
let _ = s.left_neighbor(&IntervalId::new(4)); }
#[test]
#[cfg(debug_assertions)]
#[should_panic]
fn left_neighbor_panics_on_far_out_of_bounds() {
let s = interval_space(Topology1D::RealLine, 3);
let _ = s.left_neighbor(&IntervalId::new(100));
}
#[test]
#[cfg(debug_assertions)]
#[should_panic]
fn right_neighbor_panics_on_out_of_bounds_open() {
let s = interval_space(Topology1D::RealLine, 5);
let _ = s.right_neighbor(&IntervalId::new(5)); }
#[test]
#[cfg(debug_assertions)]
#[should_panic]
fn right_neighbor_panics_on_out_of_bounds_periodic() {
let s = interval_space(Topology1D::Circle, 4);
let _ = s.right_neighbor(&IntervalId::new(4)); }
#[test]
#[cfg(debug_assertions)]
#[should_panic]
fn right_neighbor_panics_on_far_out_of_bounds() {
let s = interval_space(Topology1D::RealLine, 3);
let _ = s.right_neighbor(&IntervalId::new(100));
}
#[test]
fn interval_space_first_and_last_id() {
let s = interval_space(Topology1D::RealLine, 5);
assert_eq!(s.first_id(), IntervalId::new(0));
assert_eq!(s.last_id(), IntervalId::new(4));
}
#[test]
fn coord_space_non_periodic_first_and_last_id() {
let s = CoordIndexSpace1D::new_non_periodic(NumIntervals::try_new(4).unwrap());
assert_eq!(s.first_id(), CoordId::new(0));
assert_eq!(s.last_id(), CoordId::new(4));
}
#[test]
fn coord_space_periodic_upper_open_first_and_last_id() {
let s =
CoordIndexSpace1D::new_periodic_upper_open_interval(NumIntervals::try_new(4).unwrap());
assert_eq!(s.first_id(), CoordId::new(0));
assert_eq!(s.last_id(), CoordId::new(3));
}
#[test]
fn coord_space_periodic_lower_open_first_and_last_id() {
let s =
CoordIndexSpace1D::new_periodic_lower_open_interval(NumIntervals::try_new(4).unwrap());
assert_eq!(s.first_id(), CoordId::new(1));
assert_eq!(s.last_id(), CoordId::new(4));
}
#[test]
fn interval_connectivity_real_line() {
let s = interval_space(Topology1D::RealLine, 4);
let pairs: Vec<_> = s.connectivity().collect();
assert_eq!(
pairs,
vec![
(IntervalId::new(0), IntervalId::new(1)),
(IntervalId::new(1), IntervalId::new(2)),
(IntervalId::new(2), IntervalId::new(3)),
]
);
}
#[test]
fn interval_connectivity_circle() {
let s = interval_space(Topology1D::Circle, 4);
let pairs: Vec<_> = s.connectivity().collect();
assert_eq!(
pairs,
vec![
(IntervalId::new(0), IntervalId::new(1)),
(IntervalId::new(1), IntervalId::new(2)),
(IntervalId::new(2), IntervalId::new(3)),
(IntervalId::new(3), IntervalId::new(0)), ]
);
}
#[test]
fn interval_connectivity_single_element_real_line() {
let s = interval_space(Topology1D::RealLine, 1);
let pairs: Vec<_> = s.connectivity().collect();
assert!(pairs.is_empty());
}
#[test]
fn interval_connectivity_single_element_circle() {
let s = interval_space(Topology1D::Circle, 1);
let pairs: Vec<_> = s.connectivity().collect();
assert_eq!(pairs, vec![(IntervalId::new(0), IntervalId::new(0))]);
}
#[test]
fn coord_connectivity_non_periodic() {
let s = CoordIndexSpace1D::new_non_periodic(NumIntervals::try_new(4).unwrap());
let pairs: Vec<_> = s.connectivity().collect();
assert_eq!(pairs.len(), 4);
assert_eq!(pairs[0], (CoordId::new(0), CoordId::new(1)));
assert_eq!(pairs[3], (CoordId::new(3), CoordId::new(4)));
}
#[test]
fn coord_connectivity_periodic_upper_open() {
let s =
CoordIndexSpace1D::new_periodic_upper_open_interval(NumIntervals::try_new(4).unwrap());
let pairs: Vec<_> = s.connectivity().collect();
assert_eq!(pairs.len(), 4);
assert_eq!(pairs[3], (CoordId::new(3), CoordId::new(0))); }
#[test]
fn coord_connectivity_periodic_lower_open() {
let s =
CoordIndexSpace1D::new_periodic_lower_open_interval(NumIntervals::try_new(4).unwrap());
let pairs: Vec<_> = s.connectivity().collect();
assert_eq!(pairs.len(), 4);
assert_eq!(pairs[0], (CoordId::new(1), CoordId::new(2)));
assert_eq!(pairs[3], (CoordId::new(4), CoordId::new(1))); }
}