use anyhow::Context;
use crate::{
attributes::{AttrSparseVec, AttributeBind, AttributeError, AttributeUpdate},
cmap::{CMap3, CMapBuilder, DartIdType, LinkError, OrbitPolicy, SewError, VertexIdType},
geometry::Vertex3,
stm::{StmError, TVar, TransactionError, atomically, atomically_with_err},
};
#[cfg(test)]
impl std::process::Termination for CMap3<f64> {
fn report(self) -> std::process::ExitCode {
std::process::ExitCode::SUCCESS
}
}
#[test]
fn build_tet() -> anyhow::Result<CMap3<f64>> {
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(12).build()?;
map.link::<1>(1, 2)?;
map.link::<1>(2, 3)?;
map.link::<1>(3, 1)?;
map.link::<1>(4, 5)?;
map.link::<1>(5, 6)?;
map.link::<1>(6, 4)?;
map.link::<1>(7, 8)?;
map.link::<1>(8, 9)?;
map.link::<1>(9, 7)?;
map.link::<1>(10, 11)?;
map.link::<1>(11, 12)?;
map.link::<1>(12, 10)?;
map.link::<2>(1, 4)?;
map.link::<2>(2, 7)?;
map.link::<2>(3, 10)?;
map.link::<2>(5, 12)?;
map.link::<2>(6, 8)?;
map.link::<2>(9, 11)?;
{
let mut vertices = map.iter_vertices();
assert_eq!(vertices.next(), Some(1));
assert_eq!(vertices.next(), Some(2));
assert_eq!(vertices.next(), Some(3));
assert_eq!(vertices.next(), Some(6));
assert_eq!(vertices.next(), None);
let darts: Vec<_> = map.orbit(OrbitPolicy::FaceLinear, 2).collect();
assert_eq!(&darts, &[2, 3, 1]);
}
map.write_vertex(1, (1.0, 0.0, 0.0));
map.write_vertex(2, (0.0, 0.0, 0.0));
map.write_vertex(3, (0.0, 0.5, 0.0));
map.write_vertex(6, (0.5, 0.25, 1.0));
Ok(map)
}
#[test]
fn sew_tets() -> anyhow::Result<CMap3<f64>> {
let mut map = build_tet().context("Failed to build first tetrahedron")?;
let _ = map.allocate_used_darts(12);
map.link::<1>(13, 14)?;
map.link::<1>(14, 15)?;
map.link::<1>(15, 13)?;
map.link::<1>(16, 17)?;
map.link::<1>(17, 18)?;
map.link::<1>(18, 16)?;
map.link::<1>(19, 20)?;
map.link::<1>(20, 21)?;
map.link::<1>(21, 19)?;
map.link::<1>(22, 23)?;
map.link::<1>(23, 24)?;
map.link::<1>(24, 22)?;
map.link::<2>(13, 16)?;
map.link::<2>(14, 19)?;
map.link::<2>(15, 22)?;
map.link::<2>(17, 24)?;
map.link::<2>(18, 20)?;
map.link::<2>(21, 23)?;
map.write_vertex(13, (2.5, 1.5, 0.0));
map.write_vertex(14, (1.5, 2.0, 0.0));
map.write_vertex(15, (2.5, 2.0, 0.0));
map.write_vertex(18, (1.5, 1.75, 1.0));
{
let mut volumes = map.iter_volumes();
assert_eq!(volumes.next(), Some(1));
assert_eq!(volumes.next(), Some(13));
assert_eq!(volumes.next(), None);
let mut faces = map.iter_faces();
assert_eq!(faces.next(), Some(1));
assert_eq!(faces.next(), Some(4));
assert_eq!(faces.next(), Some(7));
assert_eq!(faces.next(), Some(10));
assert_eq!(faces.next(), Some(13));
assert_eq!(faces.next(), Some(16));
assert_eq!(faces.next(), Some(19));
assert_eq!(faces.next(), Some(22));
assert_eq!(faces.next(), None);
let mut edges = map.iter_edges();
assert_eq!(edges.next(), Some(1));
assert_eq!(edges.next(), Some(2));
assert_eq!(edges.next(), Some(3));
assert_eq!(edges.next(), Some(5));
assert_eq!(edges.next(), Some(6));
assert_eq!(edges.next(), Some(9));
assert_eq!(edges.next(), Some(13));
assert_eq!(edges.next(), Some(14));
assert_eq!(edges.next(), Some(15));
assert_eq!(edges.next(), Some(17));
assert_eq!(edges.next(), Some(18));
assert_eq!(edges.next(), Some(21));
assert_eq!(edges.next(), None);
}
assert_eq!(map.n_vertices(), 8);
map.sew::<3>(10, 16)?;
assert_eq!(map.n_vertices(), 5);
{
let mut faces = map.iter_faces();
assert_eq!(faces.next(), Some(1));
assert_eq!(faces.next(), Some(4));
assert_eq!(faces.next(), Some(7));
assert_eq!(faces.next(), Some(10));
assert_eq!(faces.next(), Some(13));
assert_eq!(faces.next(), Some(19));
assert_eq!(faces.next(), Some(22));
assert_eq!(faces.next(), None);
assert_eq!(map.iter_edges().count(), 9);
let darts: Vec<_> = map.orbit(OrbitPolicy::Face, 10).collect();
assert!(darts.contains(&10));
assert!(darts.contains(&11));
assert!(darts.contains(&12));
assert!(darts.contains(&16));
assert!(darts.contains(&17));
assert!(darts.contains(&18));
}
Ok(map)
}
#[test]
fn unsew_tets() -> anyhow::Result<()> {
let map = sew_tets().context("Failed to sew first tetrahedra")?;
map.unsew::<3>(10)?;
assert_eq!(map.n_vertices(), 8);
{
let mut vertices = map.iter_vertices();
assert_eq!(vertices.next(), Some(1));
assert_eq!(vertices.next(), Some(2));
assert_eq!(vertices.next(), Some(3));
assert_eq!(vertices.next(), Some(6));
assert_eq!(vertices.next(), Some(13));
assert_eq!(vertices.next(), Some(14));
assert_eq!(vertices.next(), Some(15));
assert_eq!(vertices.next(), Some(18));
assert_eq!(vertices.next(), None);
let darts: Vec<_> = map.orbit(OrbitPolicy::FaceLinear, 2).collect();
assert_eq!(&darts, &[2, 3, 1]);
let mut volumes = map.iter_volumes();
assert_eq!(volumes.next(), Some(1));
assert_eq!(volumes.next(), Some(13));
assert_eq!(volumes.next(), None);
let mut faces = map.iter_faces();
assert_eq!(faces.next(), Some(1));
assert_eq!(faces.next(), Some(4));
assert_eq!(faces.next(), Some(7));
assert_eq!(faces.next(), Some(10));
assert_eq!(faces.next(), Some(13));
assert_eq!(faces.next(), Some(16));
assert_eq!(faces.next(), Some(19));
assert_eq!(faces.next(), Some(22));
assert_eq!(faces.next(), None);
let mut edges = map.iter_edges();
assert_eq!(edges.next(), Some(1));
assert_eq!(edges.next(), Some(2));
assert_eq!(edges.next(), Some(3));
assert_eq!(edges.next(), Some(5));
assert_eq!(edges.next(), Some(6));
assert_eq!(edges.next(), Some(9));
assert_eq!(edges.next(), Some(13));
assert_eq!(edges.next(), Some(14));
assert_eq!(edges.next(), Some(15));
assert_eq!(edges.next(), Some(17));
assert_eq!(edges.next(), Some(18));
assert_eq!(edges.next(), Some(21));
assert_eq!(edges.next(), None);
let darts: Vec<_> = map.orbit(OrbitPolicy::Face, 10).collect();
assert!(darts.len() == 3);
assert!(darts.contains(&10));
assert!(darts.contains(&11));
assert!(darts.contains(&12));
let darts: Vec<_> = map.orbit(OrbitPolicy::Face, 16).collect();
assert!(darts.len() == 3);
assert!(darts.contains(&16));
assert!(darts.contains(&17));
assert!(darts.contains(&18));
}
Ok(())
}
#[test]
fn merge_tets_into_pyramid() -> anyhow::Result<()> {
fn rebuild_edge(map: &CMap3<f64>, dart: DartIdType) -> anyhow::Result<()> {
let b3d = map.beta::<3>(dart);
let ld = map.beta::<2>(dart);
let rd = map.beta::<2>(b3d);
map.unsew::<2>(dart)?;
map.unsew::<2>(b3d)?;
map.sew::<2>(ld, rd)?;
Ok(())
}
let map = sew_tets().context("Failed to sew first tetrahedra")?;
assert_eq!(
map.write_vertex(3, (0.0, 1.0, 0.0)),
Some(Vertex3(0.75, 1.25, 0.0))
);
assert_eq!(
map.write_vertex(1, (1.0, 0.0, 0.0)),
Some(Vertex3(1.75, 0.75, 0.0))
);
assert_eq!(
map.write_vertex(6, (0.5, 0.5, 1.0)),
Some(Vertex3(1.0, 1.0, 1.0))
);
assert_eq!(
map.write_vertex(15, (1.0, 1.0, 0.0)),
Some(Vertex3(2.5, 2.0, 0.0))
);
rebuild_edge(&map, 10)?;
rebuild_edge(&map, 11)?;
rebuild_edge(&map, 12)?;
map.unlink::<1>(10)?;
map.unlink::<1>(11)?;
map.unlink::<1>(12)?;
map.unlink::<3>(10)?;
map.unlink::<3>(11)?;
map.unlink::<3>(12)?;
map.release_dart(10)?;
map.release_dart(11)?;
map.release_dart(12)?;
map.release_dart(16)?;
map.release_dart(17)?;
map.release_dart(18)?;
{
let mut volumes = map.iter_volumes();
assert_eq!(volumes.next(), Some(1));
assert_eq!(volumes.next(), None);
let mut faces = map.iter_faces();
assert_eq!(faces.next(), Some(1)); assert_eq!(faces.next(), Some(4)); assert_eq!(faces.next(), Some(7)); assert_eq!(faces.next(), Some(13)); assert_eq!(faces.next(), Some(19)); assert_eq!(faces.next(), Some(22)); assert_eq!(faces.next(), None);
}
Ok(())
}
#[test]
fn build_tet_tx() -> anyhow::Result<CMap3<f64>> {
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(12).build().unwrap();
atomically_with_err(|t| {
map.link_tx::<1>(t, 1, 2)?;
map.link_tx::<1>(t, 2, 3)?;
map.link_tx::<1>(t, 3, 1)?;
map.link_tx::<1>(t, 4, 5)?;
map.link_tx::<1>(t, 5, 6)?;
map.link_tx::<1>(t, 6, 4)?;
map.link_tx::<1>(t, 7, 8)?;
map.link_tx::<1>(t, 8, 9)?;
map.link_tx::<1>(t, 9, 7)?;
map.link_tx::<1>(t, 10, 11)?;
map.link_tx::<1>(t, 11, 12)?;
map.link_tx::<1>(t, 12, 10)?;
map.link_tx::<2>(t, 1, 4)?;
map.link_tx::<2>(t, 2, 7)?;
map.link_tx::<2>(t, 3, 10)?;
map.link_tx::<2>(t, 5, 12)?;
map.link_tx::<2>(t, 6, 8)?;
map.link_tx::<2>(t, 9, 11)?;
Ok(())
})?;
{
let mut vertices = map.iter_vertices();
assert_eq!(vertices.next(), Some(1));
assert_eq!(vertices.next(), Some(2));
assert_eq!(vertices.next(), Some(3));
assert_eq!(vertices.next(), Some(6));
assert_eq!(vertices.next(), None);
let darts: Vec<_> = atomically(|t| {
Ok(map
.orbit_tx(t, OrbitPolicy::FaceLinear, 2)
.map(Result::unwrap)
.collect())
});
assert_eq!(&darts, &[2, 3, 1]);
}
atomically(|t| {
map.write_vertex_tx(t, 1, (1.0, 0.0, 0.0))?;
map.write_vertex_tx(t, 2, (0.0, 0.0, 0.0))?;
map.write_vertex_tx(t, 3, (0.0, 0.5, 0.0))?;
map.write_vertex_tx(t, 6, (0.5, 0.25, 1.0))?;
Ok(())
});
Ok(map)
}
#[test]
fn sew_tets_tx() -> anyhow::Result<CMap3<f64>> {
let mut map = build_tet_tx().context("Failed to build first tetrahedron")?;
let _ = map.allocate_used_darts(12);
atomically_with_err(|t| {
map.link_tx::<1>(t, 13, 14)?;
map.link_tx::<1>(t, 14, 15)?;
map.link_tx::<1>(t, 15, 13)?;
map.link_tx::<1>(t, 16, 17)?;
map.link_tx::<1>(t, 17, 18)?;
map.link_tx::<1>(t, 18, 16)?;
map.link_tx::<1>(t, 19, 20)?;
map.link_tx::<1>(t, 20, 21)?;
map.link_tx::<1>(t, 21, 19)?;
map.link_tx::<1>(t, 22, 23)?;
map.link_tx::<1>(t, 23, 24)?;
map.link_tx::<1>(t, 24, 22)?;
map.link_tx::<2>(t, 13, 16)?;
map.link_tx::<2>(t, 14, 19)?;
map.link_tx::<2>(t, 15, 22)?;
map.link_tx::<2>(t, 17, 24)?;
map.link_tx::<2>(t, 18, 20)?;
map.link_tx::<2>(t, 21, 23)?;
map.write_vertex_tx(t, 13, (2.5, 1.5, 0.0))?;
map.write_vertex_tx(t, 14, (1.5, 2.0, 0.0))?;
map.write_vertex_tx(t, 15, (2.5, 2.0, 0.0))?;
map.write_vertex_tx(t, 18, (1.5, 1.75, 1.0))?;
Ok(())
})?;
{
let mut volumes = map.iter_volumes();
assert_eq!(volumes.next(), Some(1));
assert_eq!(volumes.next(), Some(13));
assert_eq!(volumes.next(), None);
let mut faces = map.iter_faces();
assert_eq!(faces.next(), Some(1));
assert_eq!(faces.next(), Some(4));
assert_eq!(faces.next(), Some(7));
assert_eq!(faces.next(), Some(10));
assert_eq!(faces.next(), Some(13));
assert_eq!(faces.next(), Some(16));
assert_eq!(faces.next(), Some(19));
assert_eq!(faces.next(), Some(22));
assert_eq!(faces.next(), None);
let mut edges = map.iter_edges();
assert_eq!(edges.next(), Some(1));
assert_eq!(edges.next(), Some(2));
assert_eq!(edges.next(), Some(3));
assert_eq!(edges.next(), Some(5));
assert_eq!(edges.next(), Some(6));
assert_eq!(edges.next(), Some(9));
assert_eq!(edges.next(), Some(13));
assert_eq!(edges.next(), Some(14));
assert_eq!(edges.next(), Some(15));
assert_eq!(edges.next(), Some(17));
assert_eq!(edges.next(), Some(18));
assert_eq!(edges.next(), Some(21));
assert_eq!(edges.next(), None);
}
assert_eq!(map.n_vertices(), 8);
atomically_with_err(|t| map.sew_tx::<3>(t, 10, 16))?;
assert_eq!(map.n_vertices(), 5);
{
let mut faces = map.iter_faces();
assert_eq!(faces.next(), Some(1));
assert_eq!(faces.next(), Some(4));
assert_eq!(faces.next(), Some(7));
assert_eq!(faces.next(), Some(10));
assert_eq!(faces.next(), Some(13));
assert_eq!(faces.next(), Some(19));
assert_eq!(faces.next(), Some(22));
assert_eq!(faces.next(), None);
assert_eq!(map.iter_edges().count(), 9);
let darts: Vec<_> = atomically(|t| {
Ok(map
.orbit_tx(t, OrbitPolicy::Face, 10)
.map(Result::unwrap)
.collect())
});
assert!(darts.contains(&10));
assert!(darts.contains(&11));
assert!(darts.contains(&12));
assert!(darts.contains(&16));
assert!(darts.contains(&17));
assert!(darts.contains(&18));
}
Ok(map)
}
#[test]
fn unsew_tets_tx() -> anyhow::Result<()> {
let map = sew_tets_tx().context("Failed to sew first tetrahedra")?;
atomically_with_err(|t| map.unsew_tx::<3>(t, 10))?;
assert_eq!(map.n_vertices(), 8);
{
let mut vertices = map.iter_vertices();
assert_eq!(vertices.next(), Some(1));
assert_eq!(vertices.next(), Some(2));
assert_eq!(vertices.next(), Some(3));
assert_eq!(vertices.next(), Some(6));
assert_eq!(vertices.next(), Some(13));
assert_eq!(vertices.next(), Some(14));
assert_eq!(vertices.next(), Some(15));
assert_eq!(vertices.next(), Some(18));
assert_eq!(vertices.next(), None);
let darts: Vec<_> = atomically(|t| {
let mut tmp = Vec::with_capacity(3);
for d in map.orbit_tx(t, OrbitPolicy::FaceLinear, 2) {
tmp.push(d?);
}
Ok(tmp)
});
assert_eq!(&darts, &[2, 3, 1]);
let mut volumes = map.iter_volumes();
assert_eq!(volumes.next(), Some(1));
assert_eq!(volumes.next(), Some(13));
assert_eq!(volumes.next(), None);
let mut faces = map.iter_faces();
assert_eq!(faces.next(), Some(1));
assert_eq!(faces.next(), Some(4));
assert_eq!(faces.next(), Some(7));
assert_eq!(faces.next(), Some(10));
assert_eq!(faces.next(), Some(13));
assert_eq!(faces.next(), Some(16));
assert_eq!(faces.next(), Some(19));
assert_eq!(faces.next(), Some(22));
assert_eq!(faces.next(), None);
let mut edges = map.iter_edges();
assert_eq!(edges.next(), Some(1));
assert_eq!(edges.next(), Some(2));
assert_eq!(edges.next(), Some(3));
assert_eq!(edges.next(), Some(5));
assert_eq!(edges.next(), Some(6));
assert_eq!(edges.next(), Some(9));
assert_eq!(edges.next(), Some(13));
assert_eq!(edges.next(), Some(14));
assert_eq!(edges.next(), Some(15));
assert_eq!(edges.next(), Some(17));
assert_eq!(edges.next(), Some(18));
assert_eq!(edges.next(), Some(21));
assert_eq!(edges.next(), None);
let darts: Vec<_> = atomically(|t| {
let mut tmp = Vec::with_capacity(3);
for d in map.orbit_tx(t, OrbitPolicy::Face, 10) {
tmp.push(d?);
}
Ok(tmp)
});
assert!(darts.len() == 3);
assert!(darts.contains(&10));
assert!(darts.contains(&11));
assert!(darts.contains(&12));
let darts: Vec<_> = atomically(|t| {
let mut tmp = Vec::with_capacity(3);
for d in map.orbit_tx(t, OrbitPolicy::Face, 16) {
tmp.push(d?);
}
Ok(tmp)
});
assert!(darts.len() == 3);
assert!(darts.contains(&16));
assert!(darts.contains(&17));
assert!(darts.contains(&18));
}
Ok(())
}
#[test]
fn merge_tets_into_pyramid_tx() -> anyhow::Result<()> {
fn rebuild_edge(map: &CMap3<f64>, dart: DartIdType) -> anyhow::Result<()> {
atomically_with_err(|t| {
let b3d = map.beta_tx::<3>(t, dart)?;
let ld = map.beta_tx::<2>(t, dart)?;
let rd = map.beta_tx::<2>(t, b3d)?;
map.unsew_tx::<2>(t, dart)?;
map.unsew_tx::<2>(t, b3d)?;
map.sew_tx::<2>(t, ld, rd)?;
Ok(())
})?;
Ok(())
}
let map = sew_tets_tx().context("Failed to sew first tetrahedra")?;
atomically(|t| {
assert_eq!(
map.write_vertex_tx(t, 3, (0.0, 1.0, 0.0))?,
Some(Vertex3(0.75, 1.25, 0.0))
);
assert_eq!(
map.write_vertex_tx(t, 1, (1.0, 0.0, 0.0))?,
Some(Vertex3(1.75, 0.75, 0.0))
);
assert_eq!(
map.write_vertex_tx(t, 6, (0.5, 0.5, 1.0))?,
Some(Vertex3(1.0, 1.0, 1.0))
);
assert_eq!(
map.write_vertex_tx(t, 15, (1.0, 1.0, 0.0))?,
Some(Vertex3(2.5, 2.0, 0.0))
);
Ok(())
});
rebuild_edge(&map, 10)?;
rebuild_edge(&map, 11)?;
rebuild_edge(&map, 12)?;
atomically_with_err(|t| {
map.unlink_tx::<1>(t, 10)?;
map.unlink_tx::<1>(t, 11)?;
map.unlink_tx::<1>(t, 12)?;
map.unlink_tx::<3>(t, 10)?;
map.unlink_tx::<3>(t, 11)?;
map.unlink_tx::<3>(t, 12)?;
Ok(())
})?;
atomically_with_err(|t| {
map.release_dart_tx(t, 10)?;
map.release_dart_tx(t, 11)?;
map.release_dart_tx(t, 12)?;
map.release_dart_tx(t, 16)?;
map.release_dart_tx(t, 17)?;
map.release_dart_tx(t, 18)?;
Ok(())
})?;
{
let mut volumes = map.iter_volumes();
assert_eq!(volumes.next(), Some(1));
assert_eq!(volumes.next(), None);
let mut faces = map.iter_faces();
assert_eq!(faces.next(), Some(1)); assert_eq!(faces.next(), Some(4)); assert_eq!(faces.next(), Some(7)); assert_eq!(faces.next(), Some(13)); assert_eq!(faces.next(), Some(19)); assert_eq!(faces.next(), Some(22)); assert_eq!(faces.next(), None);
}
Ok(())
}
#[test]
fn reserve_darts() {
let mut map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(1).build().unwrap();
map.allocate_unused_darts(100);
assert!(
map.reserve_darts(10)
.is_ok_and(|s| s.len() == 10 && *s.first().unwrap() == 2 && *s.last().unwrap() == 11)
);
assert!(map.reserve_darts(100).is_err());
assert!(
atomically_with_err(|t| map.reserve_darts_from_tx(t, 10, 40))
.is_ok_and(|s| s.len() == 10 && *s.first().unwrap() == 40 && *s.last().unwrap() == 49)
);
}
#[test]
fn remove_vertex_twice() {
let map: CMap3<f64> = CMap3::new(4);
assert!(map.write_vertex(1, (1.0, 1.0, 1.0)).is_none());
assert_eq!(map.remove_vertex(1), Some(Vertex3(1.0, 1.0, 1.0)));
assert!(map.remove_vertex(1).is_none());
}
#[test]
fn remove_dart_twice() {
let map: CMap3<f64> = CMap3::new(4);
assert!(!map.release_dart(1).unwrap());
assert!(map.release_dart(1).unwrap());
}
mod one_sew {
use super::*;
#[test]
fn topo_no_b3_image() -> anyhow::Result<()> {
let map: CMap3<f64> = CMap3::new(8);
map.link::<1>(2, 3)?;
map.link::<1>(3, 4)?;
map.link::<1>(4, 1)?;
map.write_vertex(1, Vertex3(0.0, 0.0, 0.0));
map.write_vertex(2, Vertex3(1.0, 0.0, 0.0));
map.write_vertex(3, Vertex3(1.0, 1.0, 0.0));
map.write_vertex(4, Vertex3(0.0, 1.0, 0.0));
map.sew::<1>(1, 2)?;
assert_eq!(
&[3, 4, 1, 2],
map.orbit(OrbitPolicy::FaceLinear, 3)
.collect::<Vec<_>>()
.as_slice()
);
assert_eq!(map.beta::<1>(1), 2);
assert_eq!(map.beta::<0>(2), 1);
Ok(())
}
#[test]
fn topo_b3_image() -> anyhow::Result<()> {
let map: CMap3<f64> = CMap3::new(8);
map.link::<1>(2, 3)?;
map.link::<1>(3, 4)?;
map.link::<1>(4, 1)?;
map.write_vertex(1, Vertex3(0.0, 0.0, 0.0));
map.write_vertex(2, Vertex3(1.0, 0.0, 0.0));
map.write_vertex(3, Vertex3(1.0, 1.0, 0.0));
map.write_vertex(4, Vertex3(0.0, 1.0, 0.0));
map.link::<1>(5, 6)?;
map.link::<1>(6, 7)?;
map.link::<1>(7, 8)?;
map.write_vertex(5, Vertex3(0.5, 0.0, 1.0));
map.write_vertex(6, Vertex3(0.0, 0.0, 1.0));
map.write_vertex(7, Vertex3(0.0, 1.0, 1.0));
map.write_vertex(8, Vertex3(1.0, 1.0, 1.0));
map.sew::<3>(1, 5)?;
assert_eq!(map.beta::<3>(1), 5);
assert_eq!(map.beta::<3>(2), 8);
assert_eq!(map.beta::<3>(3), 7);
assert_eq!(map.beta::<3>(4), 6);
map.sew::<1>(1, 2)?;
assert_eq!(map.beta::<1>(1), 2);
assert_eq!(map.beta::<1>(8), 5);
assert_eq!(map.vertex_id(5), 2);
assert_eq!(map.read_vertex(2), Some(Vertex3(0.75, 0.0, 0.5)));
Ok(())
}
#[test]
fn topo_errs() -> anyhow::Result<()> {
{
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(3).build()?;
map.link::<1>(1, 2)?;
assert!(map.sew::<1>(1, 3).is_err_and(|e| matches!(
e,
SewError::FailedLink(LinkError::NonFreeBase(1, 1, 3))
)));
}
{
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(3).build()?;
map.link::<1>(2, 3)?;
assert!(map.sew::<1>(1, 3).is_err_and(|e| matches!(
e,
SewError::FailedLink(LinkError::NonFreeImage(0, 1, 3))
)));
}
{
}
{
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(5).build()?;
map.link::<3>(1, 2)?;
map.link::<3>(3, 4)?;
map.link::<1>(4, 5)?;
map.write_vertex(2, (0.0, 0.0, 0.0));
map.write_vertex(3, (0.0, 1.0, 0.0));
assert!(map.sew::<1>(1, 3).is_err_and(|e| matches!(
e,
SewError::FailedLink(LinkError::NonFreeBase(1, 4, 2))
)));
}
Ok(())
}
#[test]
fn geom_no_orbit() -> anyhow::Result<()> {
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(2).build()?;
map.write_vertex(2, (0.0, 1.0, 0.0));
atomically_with_err(|t| map.sew_tx::<1>(t, 1, 2))?;
atomically(|t| {
assert_eq!(map.vertex_id_tx(t, 1)?, 1);
assert_eq!(map.read_vertex_tx(t, 1)?, None);
assert_eq!(map.vertex_id_tx(t, 2)?, 2);
assert_eq!(map.read_vertex_tx(t, 2)?, Some(Vertex3(0.0, 1.0, 0.0)));
Ok(())
});
Ok(())
}
#[test]
fn geom_no_b2_image() -> anyhow::Result<()> {
{
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(3).build()?;
map.link::<3>(1, 3)?;
map.write_vertex(2, (0.0, 1.0, 0.0));
map.write_vertex(3, (0.0, 0.0, 0.0));
atomically_with_err(|t| map.sew_tx::<1>(t, 1, 2))?;
atomically(|t| {
assert_eq!(map.vertex_id_tx(t, 1)?, 1);
assert_eq!(map.read_vertex_tx(t, 1)?, None);
assert_eq!(map.vertex_id_tx(t, 2)?, 2);
assert_eq!(map.vertex_id_tx(t, 3)?, 2);
assert_eq!(map.read_vertex_tx(t, 2)?, Some(Vertex3(0.0, 0.5, 0.0)));
Ok(())
});
}
{
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(3).build()?;
map.link::<3>(1, 2)?;
map.write_vertex(2, (0.0, 0.0, 0.0));
map.write_vertex(3, (0.0, 1.0, 0.0));
atomically_with_err(|t| map.sew_tx::<1>(t, 1, 3))?;
atomically(|t| {
assert_eq!(map.vertex_id_tx(t, 1)?, 1);
assert_eq!(map.read_vertex_tx(t, 1)?, None);
assert_eq!(map.vertex_id_tx(t, 2)?, 2);
assert_eq!(map.vertex_id_tx(t, 3)?, 2);
assert_eq!(map.read_vertex_tx(t, 2)?, Some(Vertex3(0.0, 0.5, 0.0)));
Ok(())
});
}
Ok(())
}
#[test]
fn geom_no_b3_image() -> anyhow::Result<()> {
{
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(3).build()?;
map.link::<2>(1, 3)?;
map.write_vertex(2, (0.0, 1.0, 0.0));
map.write_vertex(3, (0.0, 0.0, 0.0));
atomically_with_err(|t| map.sew_tx::<1>(t, 1, 2))?;
atomically(|t| {
assert_eq!(map.vertex_id_tx(t, 1)?, 1);
assert_eq!(map.read_vertex_tx(t, 1)?, None);
assert_eq!(map.vertex_id_tx(t, 2)?, 2);
assert_eq!(map.vertex_id_tx(t, 3)?, 2);
assert_eq!(map.read_vertex_tx(t, 2)?, Some(Vertex3(0.0, 0.5, 0.0)));
Ok(())
});
}
{
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(3).build()?;
map.link::<2>(1, 2)?;
map.write_vertex(2, (0.0, 0.0, 0.0));
map.write_vertex(3, (0.0, 1.0, 0.0));
atomically_with_err(|t| map.sew_tx::<1>(t, 1, 3))?;
atomically(|t| {
assert_eq!(map.vertex_id_tx(t, 1)?, 1);
assert_eq!(map.read_vertex_tx(t, 1)?, None);
assert_eq!(map.vertex_id_tx(t, 2)?, 2);
assert_eq!(map.vertex_id_tx(t, 3)?, 2);
assert_eq!(map.read_vertex_tx(t, 2)?, Some(Vertex3(0.0, 0.5, 0.0)));
Ok(())
});
}
Ok(())
}
#[test]
fn geom_full_orbit() -> anyhow::Result<()> {
{
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(4).build()?;
map.link::<2>(1, 3)?;
map.link::<3>(1, 4)?;
assert_eq!(map.vertex_id(3), 3);
assert_eq!(map.vertex_id(4), 3);
map.write_vertex(2, (0.0, 1.0, 0.0));
map.write_vertex(3, (0.0, 0.0, 0.0));
atomically_with_err(|t| map.sew_tx::<1>(t, 1, 2))?;
atomically(|t| {
assert_eq!(map.vertex_id_tx(t, 1)?, 1);
assert_eq!(map.read_vertex_tx(t, 1)?, None);
assert_eq!(map.vertex_id_tx(t, 2)?, 2);
assert_eq!(map.vertex_id_tx(t, 3)?, 2);
assert_eq!(map.vertex_id_tx(t, 4)?, 2);
assert_eq!(map.read_vertex_tx(t, 2)?, Some(Vertex3(0.0, 0.5, 0.0)));
Ok(())
});
}
{
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(4).build()?;
map.link::<2>(1, 2)?;
map.link::<3>(1, 3)?;
assert_eq!(map.vertex_id(2), 2);
assert_eq!(map.vertex_id(3), 2);
map.write_vertex(2, (0.0, 0.0, 0.0));
map.write_vertex(4, (0.0, 1.0, 0.0));
atomically_with_err(|t| map.sew_tx::<1>(t, 1, 4))?;
atomically(|t| {
assert_eq!(map.vertex_id_tx(t, 1)?, 1);
assert_eq!(map.read_vertex_tx(t, 1)?, None);
assert_eq!(map.vertex_id_tx(t, 2)?, 2);
assert_eq!(map.vertex_id_tx(t, 3)?, 2);
assert_eq!(map.vertex_id_tx(t, 4)?, 2);
assert_eq!(map.read_vertex_tx(t, 2)?, Some(Vertex3(0.0, 0.5, 0.0)));
Ok(())
});
}
{
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(4).build()?;
map.link::<2>(1, 4)?;
map.link::<3>(1, 2)?;
assert_eq!(map.vertex_id(2), 2);
assert_eq!(map.vertex_id(4), 2);
map.write_vertex(2, (0.0, 0.0, 0.0));
map.write_vertex(3, (0.0, 1.0, 0.0));
atomically_with_err(|t| map.sew_tx::<1>(t, 1, 3))?;
atomically(|t| {
assert_eq!(map.vertex_id_tx(t, 1)?, 1);
assert_eq!(map.read_vertex_tx(t, 1)?, None);
assert_eq!(map.vertex_id_tx(t, 2)?, 2);
assert_eq!(map.vertex_id_tx(t, 3)?, 2);
assert_eq!(map.vertex_id_tx(t, 4)?, 2);
assert_eq!(map.read_vertex_tx(t, 2)?, Some(Vertex3(0.0, 0.5, 0.0)));
Ok(())
});
}
Ok(())
}
#[test]
fn geom_missing_data() -> anyhow::Result<()> {
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(4).build()?;
map.link::<2>(1, 3)?;
assert!(
atomically_with_err(|t| map.sew_tx::<1>(t, 1, 2)).is_err_and(|e| matches!(
e,
SewError::FailedAttributeOp(AttributeError::InsufficientData(_, _))
))
);
map.unlink::<2>(1)?;
map.link::<3>(1, 4)?;
assert!(
atomically_with_err(|t| map.sew_tx::<1>(t, 1, 2)).is_err_and(|e| matches!(
e,
SewError::FailedAttributeOp(AttributeError::InsufficientData(_, _))
))
);
map.link::<2>(1, 3)?;
assert!(
atomically_with_err(|t| map.sew_tx::<1>(t, 1, 2)).is_err_and(|e| matches!(
e,
SewError::FailedAttributeOp(AttributeError::InsufficientData(_, _))
))
);
Ok(())
}
}
mod two_sew {
use super::*;
#[test]
fn topo_errs() -> anyhow::Result<()> {
{
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(3).build()?;
map.link::<2>(1, 2)?;
assert!(map.sew::<2>(1, 3).is_err_and(|e| matches!(
e,
SewError::FailedLink(LinkError::NonFreeBase(2, 1, 3))
)));
}
{
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(3).build()?;
map.link::<2>(2, 3)?;
assert!(map.sew::<2>(1, 3).is_err_and(|e| matches!(
e,
SewError::FailedLink(LinkError::NonFreeImage(2, 1, 3))
)));
}
Ok(())
}
#[test]
fn geom_no_orbit() -> anyhow::Result<()> {
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(2).build()?;
assert_eq!(map.vertex_id(1), 1);
assert_eq!(map.vertex_id(2), 2);
map.write_vertex(1, (0.0, 0.0, 0.0));
map.write_vertex(2, (1.0, 1.0, 0.0));
atomically_with_err(|t| map.sew_tx::<2>(t, 1, 2))?;
assert_eq!(map.vertex_id(1), 1);
assert_eq!(map.vertex_id(2), 2);
assert_eq!(map.read_vertex(1), Some(Vertex3(0.0, 0.0, 0.0)));
assert_eq!(map.read_vertex(2), Some(Vertex3(1.0, 1.0, 0.0)));
Ok(())
}
#[test]
fn geom_no_b3_image() -> anyhow::Result<()> {
{
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(4).build()?;
map.link::<1>(1, 3)?;
map.link::<1>(2, 4)?;
assert_eq!(map.vertex_id(1), 1);
assert_eq!(map.vertex_id(2), 2);
assert_eq!(map.vertex_id(3), 3);
assert_eq!(map.vertex_id(4), 4);
map.write_vertex(1, (0.0, 0.0, 0.0));
map.write_vertex(2, (1.0, 1.0, 0.0));
map.write_vertex(3, (1.0, 1.0, 0.0));
map.write_vertex(4, (0.0, 0.0, 0.0));
atomically_with_err(|t| map.sew_tx::<2>(t, 1, 2))?;
assert_eq!(map.vertex_id(1), 1);
assert_eq!(map.vertex_id(2), 2);
assert_eq!(map.vertex_id(3), 2);
assert_eq!(map.vertex_id(4), 1);
assert_eq!(map.read_vertex(1), Some(Vertex3(0.0, 0.0, 0.0)));
assert_eq!(map.read_vertex(2), Some(Vertex3(1.0, 1.0, 0.0)));
}
{
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(4).build()?;
map.link::<1>(3, 1)?;
map.link::<1>(4, 2)?;
assert_eq!(map.vertex_id(1), 1);
assert_eq!(map.vertex_id(2), 2);
assert_eq!(map.vertex_id(3), 3);
assert_eq!(map.vertex_id(4), 4);
map.write_vertex(1, (1.0, 1.0, 0.0));
map.write_vertex(2, (0.0, 0.0, 0.0));
map.write_vertex(3, (0.0, 0.0, 0.0));
map.write_vertex(4, (1.0, 1.0, 0.0));
atomically_with_err(|t| map.sew_tx::<2>(t, 3, 4))?;
assert_eq!(map.vertex_id(1), 1);
assert_eq!(map.vertex_id(2), 2);
assert_eq!(map.vertex_id(3), 2);
assert_eq!(map.vertex_id(4), 1);
assert_eq!(map.read_vertex(1), Some(Vertex3(1.0, 1.0, 0.0)));
assert_eq!(map.read_vertex(2), Some(Vertex3(0.0, 0.0, 0.0)));
}
Ok(())
}
#[test]
fn geom_no_b1_image() -> anyhow::Result<()> {
{
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(4).build()?;
map.link::<3>(1, 3)?;
map.link::<3>(2, 4)?;
assert_eq!(map.vertex_id(1), 1);
assert_eq!(map.vertex_id(2), 2);
assert_eq!(map.vertex_id(3), 3);
assert_eq!(map.vertex_id(4), 4);
map.write_vertex(1, (0.0, 0.0, 0.0));
map.write_vertex(2, (1.0, 1.0, 0.0));
map.write_vertex(3, (1.0, 1.0, 0.0));
map.write_vertex(4, (0.0, 0.0, 0.0));
atomically_with_err(|t| map.sew_tx::<2>(t, 1, 2))?;
assert_eq!(map.vertex_id(1), 1);
assert_eq!(map.vertex_id(2), 2);
assert_eq!(map.vertex_id(3), 2);
assert_eq!(map.vertex_id(4), 1);
assert_eq!(map.read_vertex(1), Some(Vertex3(0.0, 0.0, 0.0)));
assert_eq!(map.read_vertex(2), Some(Vertex3(1.0, 1.0, 0.0)));
}
{
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(4).build()?;
map.link::<3>(1, 3)?;
map.link::<3>(2, 4)?;
assert_eq!(map.vertex_id(1), 1);
assert_eq!(map.vertex_id(2), 2);
assert_eq!(map.vertex_id(3), 3);
assert_eq!(map.vertex_id(4), 4);
map.write_vertex(1, (1.0, 1.0, 0.0));
map.write_vertex(2, (0.0, 0.0, 0.0));
map.write_vertex(3, (0.0, 0.0, 0.0));
map.write_vertex(4, (1.0, 1.0, 0.0));
atomically_with_err(|t| map.sew_tx::<2>(t, 3, 4))?;
assert_eq!(map.vertex_id(1), 1);
assert_eq!(map.vertex_id(2), 2);
assert_eq!(map.vertex_id(3), 2);
assert_eq!(map.vertex_id(4), 1);
assert_eq!(map.read_vertex(1), Some(Vertex3(1.0, 1.0, 0.0)));
assert_eq!(map.read_vertex(2), Some(Vertex3(0.0, 0.0, 0.0)));
}
Ok(())
}
#[test]
fn geom_full_orbit() -> anyhow::Result<()> {
{
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(6).build()?;
map.link::<3>(1, 5)?;
map.link::<3>(2, 6)?;
map.link::<1>(1, 3)?;
map.link::<1>(2, 4)?;
assert_eq!(map.vertex_id(1), 1);
assert_eq!(map.vertex_id(2), 2);
assert_eq!(map.vertex_id(3), 3);
assert_eq!(map.vertex_id(4), 4);
assert_eq!(map.vertex_id(5), 3);
assert_eq!(map.vertex_id(6), 4);
map.write_vertex(1, (0.0, 0.0, 0.0));
map.write_vertex(2, (1.0, 1.0, 0.0));
map.write_vertex(3, (1.0, 1.0, 0.0));
map.write_vertex(4, (0.0, 0.0, 0.0));
atomically_with_err(|t| map.sew_tx::<2>(t, 1, 2))?;
assert_eq!(map.vertex_id(1), 1);
assert_eq!(map.vertex_id(2), 2);
assert_eq!(map.vertex_id(3), 2);
assert_eq!(map.vertex_id(4), 1);
assert_eq!(map.vertex_id(5), 2);
assert_eq!(map.vertex_id(6), 1);
assert_eq!(map.read_vertex(1), Some(Vertex3(0.0, 0.0, 0.0)));
assert_eq!(map.read_vertex(2), Some(Vertex3(1.0, 1.0, 0.0)));
}
{
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(6).build()?;
map.link::<3>(5, 3)?;
map.link::<3>(6, 4)?;
map.link::<1>(5, 1)?;
map.link::<1>(6, 2)?;
assert_eq!(map.vertex_id(1), 1);
assert_eq!(map.vertex_id(2), 2);
assert_eq!(map.vertex_id(3), 1);
assert_eq!(map.vertex_id(4), 2);
assert_eq!(map.vertex_id(5), 5);
assert_eq!(map.vertex_id(6), 6);
map.write_vertex(5, (0.0, 0.0, 0.0));
map.write_vertex(6, (1.0, 1.0, 0.0));
map.write_vertex(1, (1.0, 1.0, 0.0));
map.write_vertex(2, (0.0, 0.0, 0.0));
atomically_with_err(|t| map.sew_tx::<2>(t, 5, 6))?;
assert_eq!(map.vertex_id(1), 1);
assert_eq!(map.vertex_id(2), 2);
assert_eq!(map.vertex_id(3), 1);
assert_eq!(map.vertex_id(4), 2);
assert_eq!(map.vertex_id(5), 2);
assert_eq!(map.vertex_id(6), 1);
assert_eq!(map.read_vertex(1), Some(Vertex3(1.0, 1.0, 0.0)));
assert_eq!(map.read_vertex(2), Some(Vertex3(0.0, 0.0, 0.0)));
}
{
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(6).build()?;
map.link::<3>(3, 1)?;
map.link::<3>(4, 2)?;
map.link::<1>(3, 5)?;
map.link::<1>(4, 6)?;
assert_eq!(map.vertex_id(1), 1);
assert_eq!(map.vertex_id(2), 2);
assert_eq!(map.vertex_id(3), 3);
assert_eq!(map.vertex_id(4), 4);
assert_eq!(map.vertex_id(5), 1);
assert_eq!(map.vertex_id(6), 2);
map.write_vertex(1, (0.0, 0.0, 0.0));
map.write_vertex(2, (1.0, 1.0, 0.0));
map.write_vertex(3, (1.0, 1.0, 0.0));
map.write_vertex(4, (0.0, 0.0, 0.0));
atomically_with_err(|t| map.sew_tx::<2>(t, 3, 4))?;
assert_eq!(map.vertex_id(1), 1);
assert_eq!(map.vertex_id(2), 2);
assert_eq!(map.vertex_id(3), 2);
assert_eq!(map.vertex_id(4), 1);
assert_eq!(map.vertex_id(5), 1);
assert_eq!(map.vertex_id(6), 2);
assert_eq!(map.read_vertex(1), Some(Vertex3(0.0, 0.0, 0.0)));
assert_eq!(map.read_vertex(2), Some(Vertex3(1.0, 1.0, 0.0)));
}
Ok(())
}
#[test]
fn geom_err_missing_data() -> anyhow::Result<()> {
{
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(4).build()?;
map.link::<1>(1, 3)?;
map.link::<1>(2, 4)?;
assert_eq!(map.vertex_id(1), 1);
assert_eq!(map.vertex_id(2), 2);
assert_eq!(map.vertex_id(3), 3);
assert_eq!(map.vertex_id(4), 4);
map.write_vertex(2, (0.0, 0.0, 0.0));
map.write_vertex(3, (1.0, 0.0, 0.0));
assert!(
atomically_with_err(|t| map.sew_tx::<2>(t, 1, 2)).is_err_and(|e| matches!(
e,
SewError::FailedAttributeOp(AttributeError::InsufficientData(_, _))
))
);
}
{
let map: CMap3<f64> = CMapBuilder::<3>::from_n_darts(4).build()?;
map.link::<1>(1, 3)?;
map.link::<1>(2, 4)?;
assert_eq!(map.vertex_id(1), 1);
assert_eq!(map.vertex_id(2), 2);
assert_eq!(map.vertex_id(3), 3);
assert_eq!(map.vertex_id(4), 4);
map.write_vertex(1, (0.0, 0.0, 0.0));
map.write_vertex(4, (1.0, 0.0, 0.0));
assert!(
atomically_with_err(|t| map.sew_tx::<2>(t, 1, 2)).is_err_and(|e| matches!(
e,
SewError::FailedAttributeOp(AttributeError::InsufficientData(_, _))
))
);
}
Ok(())
}
#[test]
fn geom_err_bad_orientation() -> anyhow::Result<()> {
let map: CMap3<f64> = CMap3::new(8);
atomically_with_err(|t| {
map.link_tx::<1>(t, 1, 2)?;
map.link_tx::<1>(t, 2, 3)?;
map.link_tx::<1>(t, 3, 4)?;
map.link_tx::<1>(t, 4, 1)?;
map.link_tx::<1>(t, 5, 6)?;
map.link_tx::<1>(t, 6, 7)?;
map.link_tx::<1>(t, 7, 8)?;
map.link_tx::<1>(t, 8, 5)?;
map.write_vertex_tx(t, 1, Vertex3(0.0, 0.0, 0.0))?;
map.write_vertex_tx(t, 2, Vertex3(1.0, 0.0, 0.0))?;
map.write_vertex_tx(t, 3, Vertex3(1.0, 1.0, 0.0))?;
map.write_vertex_tx(t, 4, Vertex3(0.0, 1.0, 0.0))?;
map.write_vertex_tx(t, 5, Vertex3(0.0, 0.0, 1.0))?;
map.write_vertex_tx(t, 6, Vertex3(1.0, 0.0, 1.0))?;
map.write_vertex_tx(t, 7, Vertex3(1.0, 1.0, 1.0))?;
map.write_vertex_tx(t, 8, Vertex3(0.0, 1.0, 1.0))?;
Ok(())
})?;
assert!(
map.sew::<2>(1, 5)
.is_err_and(|e| e == SewError::BadGeometry(2, 1, 5))
);
Ok(())
}
}
mod three_sew {
use super::*;
#[allow(clippy::unnecessary_wraps)]
#[test]
fn topo_errs() -> anyhow::Result<()> {
Ok(())
}
#[test]
fn geom_open_face_no_b2_image() -> anyhow::Result<()> {
{
let map: CMap3<f64> = CMap3::new(8);
atomically_with_err(|t| {
map.link_tx::<1>(t, 2, 3)?;
map.link_tx::<1>(t, 3, 4)?;
map.link_tx::<1>(t, 4, 1)?;
map.write_vertex_tx(t, 1, Vertex3(0.0, 0.0, 0.0))?;
map.write_vertex_tx(t, 2, Vertex3(1.0, 0.0, 0.0))?;
map.write_vertex_tx(t, 3, Vertex3(1.0, 1.0, 0.0))?;
map.write_vertex_tx(t, 4, Vertex3(0.0, 1.0, 0.0))?;
map.link_tx::<1>(t, 5, 6)?;
map.link_tx::<1>(t, 6, 7)?;
map.link_tx::<1>(t, 8, 5)?;
map.write_vertex_tx(t, 5, Vertex3(0.0, 0.0, 1.0))?;
map.write_vertex_tx(t, 6, Vertex3(0.0, 1.0, 1.0))?;
map.write_vertex_tx(t, 7, Vertex3(1.0, 1.0, 1.0))?;
map.write_vertex_tx(t, 8, Vertex3(1.0, 0.0, 1.0))?;
Ok(())
})?;
atomically_with_err(|t| map.sew_tx::<3>(t, 1, 8))?;
assert_eq!(map.read_vertex(1).unwrap(), Vertex3(0.0, 0.0, 0.5));
assert_eq!(map.read_vertex(2).unwrap(), Vertex3(1.0, 0.0, 0.0));
assert_eq!(map.read_vertex(3).unwrap(), Vertex3(1.0, 1.0, 0.5));
assert_eq!(map.read_vertex(4).unwrap(), Vertex3(0.0, 1.0, 0.5));
assert_eq!(map.read_vertex(8).unwrap(), Vertex3(1.0, 0.0, 1.0));
}
{
let map: CMap3<f64> = CMap3::new(8);
atomically_with_err(|t| {
map.link_tx::<1>(t, 2, 3)?;
map.link_tx::<1>(t, 3, 4)?;
map.link_tx::<1>(t, 4, 1)?;
map.write_vertex_tx(t, 1, Vertex3(0.0, 0.0, 0.0))?;
map.write_vertex_tx(t, 2, Vertex3(1.0, 0.0, 0.0))?;
map.write_vertex_tx(t, 3, Vertex3(1.0, 1.0, 0.0))?;
map.write_vertex_tx(t, 4, Vertex3(0.0, 1.0, 0.0))?;
map.link_tx::<1>(t, 5, 6)?;
map.link_tx::<1>(t, 6, 7)?;
map.link_tx::<1>(t, 8, 5)?;
map.write_vertex_tx(t, 5, Vertex3(0.0, 0.0, 1.0))?;
map.write_vertex_tx(t, 6, Vertex3(0.0, 1.0, 1.0))?;
map.write_vertex_tx(t, 7, Vertex3(1.0, 1.0, 1.0))?;
map.write_vertex_tx(t, 8, Vertex3(1.0, 0.0, 1.0))?;
Ok(())
})?;
atomically_with_err(|t| map.sew_tx::<3>(t, 8, 1))?;
assert_eq!(map.read_vertex(1).unwrap(), Vertex3(0.0, 0.0, 0.5));
assert_eq!(map.read_vertex(2).unwrap(), Vertex3(1.0, 0.0, 0.0));
assert_eq!(map.read_vertex(3).unwrap(), Vertex3(1.0, 1.0, 0.5));
assert_eq!(map.read_vertex(4).unwrap(), Vertex3(0.0, 1.0, 0.5));
assert_eq!(map.read_vertex(8).unwrap(), Vertex3(1.0, 0.0, 1.0));
}
Ok(())
}
#[test]
fn geom_closed_face_no_b2_image() -> anyhow::Result<()> {
{
let map: CMap3<f64> = CMap3::new(8);
atomically_with_err(|t| {
map.link_tx::<1>(t, 1, 2)?;
map.link_tx::<1>(t, 2, 3)?;
map.link_tx::<1>(t, 3, 4)?;
map.link_tx::<1>(t, 4, 1)?;
map.write_vertex_tx(t, 1, Vertex3(0.0, 0.0, 0.0))?;
map.write_vertex_tx(t, 2, Vertex3(1.0, 0.0, 0.0))?;
map.write_vertex_tx(t, 3, Vertex3(1.0, 1.0, 0.0))?;
map.write_vertex_tx(t, 4, Vertex3(0.0, 1.0, 0.0))?;
map.link_tx::<1>(t, 5, 6)?;
map.link_tx::<1>(t, 6, 7)?;
map.link_tx::<1>(t, 7, 8)?;
map.link_tx::<1>(t, 8, 5)?;
map.write_vertex_tx(t, 5, Vertex3(0.0, 0.0, 1.0))?;
map.write_vertex_tx(t, 6, Vertex3(0.0, 1.0, 1.0))?;
map.write_vertex_tx(t, 7, Vertex3(1.0, 1.0, 1.0))?;
map.write_vertex_tx(t, 8, Vertex3(1.0, 0.0, 1.0))?;
Ok(())
})?;
atomically_with_err(|t| map.sew_tx::<3>(t, 1, 8))?;
assert_eq!(map.read_vertex(1).unwrap(), Vertex3(0.0, 0.0, 0.5));
assert_eq!(map.read_vertex(2).unwrap(), Vertex3(1.0, 0.0, 0.5));
assert_eq!(map.read_vertex(3).unwrap(), Vertex3(1.0, 1.0, 0.5));
assert_eq!(map.read_vertex(4).unwrap(), Vertex3(0.0, 1.0, 0.5));
}
{
let map: CMap3<f64> = CMap3::new(8);
atomically_with_err(|t| {
map.link_tx::<1>(t, 1, 2)?;
map.link_tx::<1>(t, 2, 3)?;
map.link_tx::<1>(t, 3, 4)?;
map.link_tx::<1>(t, 4, 1)?;
map.write_vertex_tx(t, 1, Vertex3(0.0, 0.0, 0.0))?;
map.write_vertex_tx(t, 2, Vertex3(1.0, 0.0, 0.0))?;
map.write_vertex_tx(t, 3, Vertex3(1.0, 1.0, 0.0))?;
map.write_vertex_tx(t, 4, Vertex3(0.0, 1.0, 0.0))?;
map.link_tx::<1>(t, 5, 6)?;
map.link_tx::<1>(t, 6, 7)?;
map.link_tx::<1>(t, 7, 8)?;
map.link_tx::<1>(t, 8, 5)?;
map.write_vertex_tx(t, 5, Vertex3(0.0, 0.0, 1.0))?;
map.write_vertex_tx(t, 6, Vertex3(0.0, 1.0, 1.0))?;
map.write_vertex_tx(t, 7, Vertex3(1.0, 1.0, 1.0))?;
map.write_vertex_tx(t, 8, Vertex3(1.0, 0.0, 1.0))?;
Ok(())
})?;
atomically_with_err(|t| map.sew_tx::<3>(t, 8, 1))?;
assert_eq!(map.read_vertex(1).unwrap(), Vertex3(0.0, 0.0, 0.5));
assert_eq!(map.read_vertex(2).unwrap(), Vertex3(1.0, 0.0, 0.5));
assert_eq!(map.read_vertex(3).unwrap(), Vertex3(1.0, 1.0, 0.5));
assert_eq!(map.read_vertex(4).unwrap(), Vertex3(0.0, 1.0, 0.5));
}
Ok(())
}
#[test]
fn geom_b2_image() -> anyhow::Result<()> {
{
let map: CMap3<f64> = CMap3::new(12);
atomically_with_err(|t| {
map.link_tx::<1>(t, 1, 2)?;
map.link_tx::<1>(t, 2, 3)?;
map.link_tx::<1>(t, 3, 4)?;
map.link_tx::<1>(t, 4, 1)?;
map.link_tx::<2>(t, 1, 9)?;
map.link_tx::<2>(t, 2, 10)?;
map.link_tx::<2>(t, 3, 11)?;
map.link_tx::<2>(t, 4, 12)?;
map.write_vertex_tx(t, 1, Vertex3(0.0, 0.0, 0.0))?;
map.write_vertex_tx(t, 2, Vertex3(1.0, 0.0, 0.0))?;
map.write_vertex_tx(t, 3, Vertex3(1.0, 1.0, 0.0))?;
map.write_vertex_tx(t, 4, Vertex3(0.0, 1.0, 0.0))?;
map.link_tx::<1>(t, 5, 6)?;
map.link_tx::<1>(t, 6, 7)?;
map.link_tx::<1>(t, 7, 8)?;
map.link_tx::<1>(t, 8, 5)?;
map.write_vertex_tx(t, 5, Vertex3(0.0, 0.0, 1.0))?;
map.write_vertex_tx(t, 6, Vertex3(0.0, 1.0, 1.0))?;
map.write_vertex_tx(t, 7, Vertex3(1.0, 1.0, 1.0))?;
map.write_vertex_tx(t, 8, Vertex3(1.0, 0.0, 1.0))?;
Ok(())
})?;
atomically_with_err(|t| map.sew_tx::<3>(t, 1, 8))?;
assert_eq!(map.read_vertex(1).unwrap(), Vertex3(0.0, 0.0, 0.5));
assert_eq!(map.read_vertex(2).unwrap(), Vertex3(1.0, 0.0, 0.5));
assert_eq!(map.read_vertex(3).unwrap(), Vertex3(1.0, 1.0, 0.5));
assert_eq!(map.read_vertex(4).unwrap(), Vertex3(0.0, 1.0, 0.5));
}
{
let map: CMap3<f64> = CMap3::new(12);
atomically_with_err(|t| {
map.link_tx::<1>(t, 1, 2)?;
map.link_tx::<1>(t, 2, 3)?;
map.link_tx::<1>(t, 3, 4)?;
map.link_tx::<1>(t, 4, 1)?;
map.write_vertex_tx(t, 1, Vertex3(0.0, 0.0, 0.0))?;
map.write_vertex_tx(t, 2, Vertex3(1.0, 0.0, 0.0))?;
map.write_vertex_tx(t, 3, Vertex3(1.0, 1.0, 0.0))?;
map.write_vertex_tx(t, 4, Vertex3(0.0, 1.0, 0.0))?;
map.link_tx::<1>(t, 5, 6)?;
map.link_tx::<1>(t, 6, 7)?;
map.link_tx::<1>(t, 7, 8)?;
map.link_tx::<1>(t, 8, 5)?;
map.link_tx::<2>(t, 5, 9)?;
map.link_tx::<2>(t, 6, 10)?;
map.link_tx::<2>(t, 7, 11)?;
map.link_tx::<2>(t, 8, 12)?;
map.write_vertex_tx(t, 5, Vertex3(0.0, 0.0, 1.0))?;
map.write_vertex_tx(t, 6, Vertex3(0.0, 1.0, 1.0))?;
map.write_vertex_tx(t, 7, Vertex3(1.0, 1.0, 1.0))?;
map.write_vertex_tx(t, 8, Vertex3(1.0, 0.0, 1.0))?;
Ok(())
})?;
atomically_with_err(|t| map.sew_tx::<3>(t, 8, 1))?;
assert_eq!(map.read_vertex(1).unwrap(), Vertex3(0.0, 0.0, 0.5));
assert_eq!(map.read_vertex(2).unwrap(), Vertex3(1.0, 0.0, 0.5));
assert_eq!(map.read_vertex(3).unwrap(), Vertex3(1.0, 1.0, 0.5));
assert_eq!(map.read_vertex(4).unwrap(), Vertex3(0.0, 1.0, 0.5));
}
Ok(())
}
#[test]
fn geom_missing_data() -> anyhow::Result<()> {
let map: CMap3<f64> = CMap3::new(8);
atomically_with_err(|t| {
map.link_tx::<1>(t, 1, 2)?;
map.link_tx::<1>(t, 2, 3)?;
map.link_tx::<1>(t, 3, 4)?;
map.link_tx::<1>(t, 4, 1)?;
map.write_vertex_tx(t, 1, Vertex3(0.0, 0.0, 0.0))?;
map.write_vertex_tx(t, 2, Vertex3(1.0, 0.0, 0.0))?;
map.write_vertex_tx(t, 3, Vertex3(1.0, 1.0, 0.0))?;
map.link_tx::<1>(t, 5, 6)?;
map.link_tx::<1>(t, 6, 7)?;
map.link_tx::<1>(t, 7, 8)?;
map.link_tx::<1>(t, 8, 5)?;
map.write_vertex_tx(t, 5, Vertex3(0.0, 0.0, 1.0))?;
map.write_vertex_tx(t, 7, Vertex3(1.0, 1.0, 1.0))?;
map.write_vertex_tx(t, 8, Vertex3(1.0, 0.0, 1.0))?;
Ok(())
})?;
assert!(
atomically_with_err(|t| map.sew_tx::<3>(t, 1, 8)).is_err_and(|e| matches!(
e,
SewError::FailedAttributeOp(AttributeError::InsufficientData(_, _))
))
);
Ok(())
}
#[test]
fn geom_bad_orientation() -> anyhow::Result<()> {
let map: CMap3<f64> = CMap3::new(8);
atomically_with_err(|t| {
map.link_tx::<1>(t, 1, 2)?;
map.link_tx::<1>(t, 2, 3)?;
map.link_tx::<1>(t, 3, 4)?;
map.link_tx::<1>(t, 4, 1)?;
map.link_tx::<1>(t, 5, 6)?;
map.link_tx::<1>(t, 6, 7)?;
map.link_tx::<1>(t, 7, 8)?;
map.link_tx::<1>(t, 8, 5)?;
map.write_vertex_tx(t, 1, Vertex3(0.0, 0.0, 0.0))?;
map.write_vertex_tx(t, 2, Vertex3(1.0, 0.0, 0.0))?;
map.write_vertex_tx(t, 3, Vertex3(1.0, 1.0, 0.0))?;
map.write_vertex_tx(t, 4, Vertex3(0.0, 1.0, 0.0))?;
map.write_vertex_tx(t, 5, Vertex3(0.0, 0.0, 1.0))?;
map.write_vertex_tx(t, 6, Vertex3(1.0, 0.0, 1.0))?;
map.write_vertex_tx(t, 7, Vertex3(1.0, 1.0, 1.0))?;
map.write_vertex_tx(t, 8, Vertex3(0.0, 1.0, 1.0))?;
Ok(())
})?;
assert!(
map.sew::<3>(1, 5)
.is_err_and(|e| e == SewError::BadGeometry(3, 1, 5))
);
Ok(())
}
}
#[test]
fn sew_ordering() {
loom::model(|| {
let map: CMap3<f64> = CMap3::new(5);
map.link::<2>(1, 2).unwrap();
map.link::<1>(4, 5).unwrap();
map.write_vertex(2, Vertex3(1.0, 1.0, 1.0));
map.write_vertex(3, Vertex3(1.0, 2.0, 1.0));
map.write_vertex(5, Vertex3(2.0, 2.0, 1.0));
let arc = loom::sync::Arc::new(map);
let (m1, m2) = (arc.clone(), arc.clone());
let t1 = loom::thread::spawn(move || while m1.sew::<1>(1, 3).is_err() {});
let t2 = loom::thread::spawn(move || while m2.sew::<2>(3, 4).is_err() {});
t1.join().unwrap();
t2.join().unwrap();
let v2 = arc.remove_vertex(2);
let v3 = arc.remove_vertex(3);
let v5 = arc.remove_vertex(5);
assert!(v2.is_some());
assert!(v3.is_none());
assert!(v5.is_none());
assert_eq!(arc.orbit(OrbitPolicy::Vertex, 2).count(), 3);
assert!(arc.read_vertex(2).is_none());
assert!(arc.read_vertex(3).is_none());
assert!(arc.read_vertex(5).is_none());
});
}
#[test]
fn sew_ordering_with_txtions() {
loom::model(|| {
let map: CMap3<f64> = CMap3::new(5);
map.link::<2>(1, 2).unwrap();
map.link::<2>(3, 4).unwrap();
map.write_vertex(2, Vertex3(1.0, 1.0, 1.0));
let arc = loom::sync::Arc::new(map);
let (m1, m2) = (arc.clone(), arc.clone());
let foo = TVar::new(0);
let f = loom::sync::Arc::new(foo);
let (f1, f2) = (f.clone(), f.clone());
let t1 = loom::thread::spawn(move || {
atomically(|t| {
f1.modify(t, |v| v + 1)?;
if let Err(e) = m1.sew_tx::<1>(t, 1, 3) {
match e {
TransactionError::Stm(e) => Err(e),
TransactionError::Abort(_) => Err(StmError::Retry),
}
} else {
Ok(())
}
});
});
let t2 = loom::thread::spawn(move || {
atomically(|t| {
f2.modify(t, |v| if v != 0 { v + 4 } else { v })?;
if let Err(e) = m2.sew_tx::<1>(t, 4, 5) {
match e {
TransactionError::Stm(e) => Err(e),
TransactionError::Abort(_) => Err(StmError::Retry),
}
} else {
Ok(())
}
});
});
t1.join().unwrap();
t2.join().unwrap();
let (v2, v3, v5) = atomically(|t| {
Ok((
arc.remove_vertex_tx(t, 2)?,
arc.remove_vertex_tx(t, 3)?,
arc.remove_vertex_tx(t, 5)?,
))
});
assert!(v2.is_some());
assert!(v3.is_none());
assert!(v5.is_none());
assert_eq!(arc.orbit(OrbitPolicy::Vertex, 2).count(), 3);
atomically(|t| {
assert!(arc.read_vertex_tx(t, 2)?.is_none());
assert!(arc.read_vertex_tx(t, 3)?.is_none());
assert!(arc.read_vertex_tx(t, 5)?.is_none());
Ok(())
});
assert_eq!(f.read_atomic(), 5);
});
}
#[derive(Debug, Clone, Copy, Default)]
struct Weight(pub u32);
impl AttributeUpdate for Weight {
fn merge(attr1: Self, attr2: Self) -> Result<Self, AttributeError> {
Ok(Self(attr1.0 + attr2.0))
}
fn split(attr: Self) -> Result<(Self, Self), AttributeError> {
Ok((Weight(attr.0 / 2 + attr.0 % 2), Weight(attr.0 / 2)))
}
fn merge_incomplete(attr: Self) -> Result<Self, AttributeError> {
Ok(attr)
}
}
impl AttributeBind for Weight {
type StorageType = AttrSparseVec<Self>;
type IdentifierType = VertexIdType;
const BIND_POLICY: OrbitPolicy = OrbitPolicy::Vertex;
}
#[test]
fn unsew_ordering() {
loom::model(|| {
let mut map: CMap3<f64> = CMap3::new(5);
map.attributes.add_storage::<Weight>(6);
map.link::<2>(1, 2).unwrap();
map.link::<2>(3, 4).unwrap();
map.link::<1>(1, 3).unwrap();
map.link::<1>(4, 5).unwrap();
map.write_vertex(2, Vertex3(0.0, 0.0, 0.0));
map.write_attribute(2, Weight(33));
let arc = loom::sync::Arc::new(map);
let (m1, m2) = (arc.clone(), arc.clone());
let t1 = loom::thread::spawn(move || while m1.unsew::<1>(1).is_err() {});
let t2 = loom::thread::spawn(move || while m2.unsew::<2>(3).is_err() {});
t1.join().unwrap();
t2.join().unwrap();
let w2 = arc.remove_attribute::<Weight>(2);
let w3 = arc.remove_attribute::<Weight>(3);
let w5 = arc.remove_attribute::<Weight>(5);
assert!(w2.is_some());
assert!(w3.is_some());
assert!(w5.is_some());
assert!(arc.read_attribute::<Weight>(2).is_none());
assert!(arc.read_attribute::<Weight>(3).is_none());
assert!(arc.read_attribute::<Weight>(5).is_none());
});
}
#[test]
fn unsew_ordering_with_txtions() {
loom::model(|| {
let mut map: CMap3<f64> = CMap3::new(5);
map.attributes.add_storage::<Weight>(6);
let res = atomically_with_err(|t| {
map.link_tx::<2>(t, 1, 2)?;
map.link_tx::<2>(t, 3, 4)?;
map.link_tx::<1>(t, 1, 3)?;
map.link_tx::<1>(t, 4, 5)?;
map.write_vertex_tx(t, 2, (0.0, 0.0, 0.0))?;
map.write_attribute_tx(t, 2, Weight(33))?;
Ok(())
});
assert!(res.is_ok());
let arc = loom::sync::Arc::new(map);
let (m1, m2) = (arc.clone(), arc.clone());
let t1 = loom::thread::spawn(move || {
atomically(|t| {
if let Err(e) = m1.unsew_tx::<1>(t, 1) {
match e {
TransactionError::Stm(e) => Err(e),
TransactionError::Abort(_) => Err(StmError::Retry),
}
} else {
Ok(())
}
});
});
let t2 = loom::thread::spawn(move || {
atomically(|t| {
if let Err(e) = m2.unsew_tx::<2>(t, 3) {
match e {
TransactionError::Stm(e) => Err(e),
TransactionError::Abort(_) => Err(StmError::Retry),
}
} else {
Ok(())
}
});
});
t1.join().unwrap();
t2.join().unwrap();
let (w2, w3, w5) = atomically(|t| {
Ok((
arc.remove_attribute_tx::<Weight>(t, 2)?,
arc.remove_attribute_tx::<Weight>(t, 3)?,
arc.remove_attribute_tx::<Weight>(t, 5)?,
))
});
assert!(w2.is_some());
assert!(w3.is_some());
assert!(w5.is_some());
atomically(|t| {
assert!(arc.read_attribute_tx::<Weight>(t, 2)?.is_none());
assert!(arc.read_attribute_tx::<Weight>(t, 3)?.is_none());
assert!(arc.read_attribute_tx::<Weight>(t, 5)?.is_none());
Ok(())
});
});
}