conspire 0.7.1

The Rust interface to conspire.
Documentation
use crate::{
    geometry::mesh::{Connectivity, Mesh, Output},
    io::Write,
};
use std::fs::read_to_string;

fn mixed() -> Mesh<3> {
    let connectivities = vec![
        Connectivity::Hexahedral(vec![[0, 1, 2, 3, 4, 5, 6, 7]].into()),
        Connectivity::Wedge(vec![[4, 5, 8, 7, 6, 9]].into()),
        Connectivity::Pyramidal(vec![[1, 2, 6, 5, 10]].into()),
        Connectivity::Tetrahedral(vec![[1, 2, 10, 11]].into()),
    ];
    let coordinates = vec![
        [0.0, 0.0, 0.0],
        [1.0, 0.0, 0.0],
        [1.0, 1.0, 0.0],
        [0.0, 1.0, 0.0],
        [0.0, 0.0, 1.0],
        [1.0, 0.0, 1.0],
        [1.0, 1.0, 1.0],
        [0.0, 1.0, 1.0],
        [0.5, 0.0, 2.0],
        [0.5, 1.0, 2.0],
        [2.0, 0.5, 0.5],
        [1.5, 0.5, -1.0],
    ]
    .into();
    Mesh::from((connectivities, coordinates))
}

fn payload<'a>(contents: &'a str, name: &str) -> &'a str {
    let marker = format!("Name=\"{name}\" format=\"binary\">");
    let start = contents.find(&marker).unwrap() + marker.len();
    let end = contents[start..].find("</DataArray>").unwrap() + start;
    &contents[start..end]
}

fn unbase64(text: &str) -> Vec<u8> {
    let value = |c: u8| match c {
        b'A'..=b'Z' => (c - b'A') as u32,
        b'a'..=b'z' => (c - b'a' + 26) as u32,
        b'0'..=b'9' => (c - b'0' + 52) as u32,
        b'+' => 62,
        b'/' => 63,
        _ => 0,
    };
    let chars: Vec<u8> = text.bytes().filter(|&b| b != b'=').collect();
    let mut out = Vec::new();
    for chunk in chars.chunks(4) {
        let mut block = 0u32;
        for &c in chunk {
            block = (block << 6) | value(c);
        }
        block <<= 6 * (4 - chunk.len());
        for shift in (0..chunk.len() - 1).map(|i| 16 - 8 * i) {
            out.push((block >> shift) as u8);
        }
    }
    out
}

#[test]
fn mixed_unstructured_grid() {
    let path = "target/mixed.vtu";
    mixed().write(Output::Vtu(path)).unwrap();
    let contents = read_to_string(path).unwrap();
    assert!(contents.contains("type=\"UnstructuredGrid\""));
    assert!(contents.contains("byte_order=\"LittleEndian\""));
    assert!(contents.contains("NumberOfPoints=\"12\" NumberOfCells=\"4\""));
    let types = unbase64(payload(&contents, "types"));
    assert_eq!(u64::from_le_bytes(types[0..8].try_into().unwrap()), 4);
    assert_eq!(&types[8..], &[12, 13, 14, 10]);
    let offsets = unbase64(payload(&contents, "offsets"));
    let offsets: Vec<i64> = offsets[8..]
        .chunks(8)
        .map(|b| i64::from_le_bytes(b.try_into().unwrap()))
        .collect();
    assert_eq!(offsets, [8, 14, 19, 23]);
    let connectivity = unbase64(payload(&contents, "connectivity"));
    let first8: Vec<i64> = connectivity[8..]
        .chunks(8)
        .take(8)
        .map(|b| i64::from_le_bytes(b.try_into().unwrap()))
        .collect();
    assert_eq!(first8, [0, 1, 2, 3, 4, 5, 6, 7]);
}