[
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: \"cargo\"\n    directory: \"/\"\n    schedule:\n      interval: \"monthly\"\n"
  },
  {
    "path": ".github/workflows/continuous-integration.yml",
    "content": "name: CI\non: [pull_request, push]\njobs:\n  rustfmt:\n    name: Format\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - uses: actions-rs/toolchain@v1\n        with:\n          profile: minimal\n          toolchain: nightly\n          override: true\n          components: rustfmt\n      - uses: actions-rs/cargo@v1\n        with:\n          command: fmt\n          args: --all -- --check\n  clippy:\n    name: Lint\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - uses: actions-rs/toolchain@v1\n        with:\n          profile: minimal\n          toolchain: stable\n          override: true\n          components: clippy\n      - uses: actions-rs/cargo@v1\n        with:\n          command: clippy\n          args: --all-features --all-targets -- -D clippy::all\n  test:\n    name: Test\n    needs: [clippy, rustfmt]\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [macOS-latest, ubuntu-latest, windows-latest]\n        toolchain:\n          - 1.81.0 # Minimum.\n          - stable\n          - beta\n          - nightly\n    steps:\n      - uses: actions/checkout@v2\n      - uses: actions-rs/toolchain@v1\n        with:\n          profile: minimal\n          toolchain: ${{ matrix.toolchain }}\n          override: true\n      - uses: actions-rs/cargo@v1\n        with:\n          command: test\n          args: --manifest-path=plexus/Cargo.toml --features geometry-nalgebra --no-default-features --verbose\n      - uses: actions-rs/cargo@v1\n        with:\n          command: test\n          args: --manifest-path=plexus/Cargo.toml --all-features --verbose\n"
  },
  {
    "path": ".gitignore",
    "content": ".idea/\ntarget/\n**/*.rs.bk\n*.iml\nCargo.lock\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[workspace]\nmembers = [\n    \"examples/sphere\",\n    \"examples/subdivide\",\n    \"examples/teapot\",\n    \"pictor\",\n    \"plexus\",\n]\nresolver = \"2\"\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n    <img alt=\"Plexus\" src=\"https://raw.githubusercontent.com/olson-sean-k/plexus/master/doc/plexus.svg?sanitize=true\" width=\"320\"/>\n</div>\n<br/>\n\n**Plexus** is a highly composable Rust library for polygonal mesh processing.\nSee [the website][website] for the most recent [API documentation][rustdoc] and\nthe [user guide][guide].\n\n[![GitHub](https://img.shields.io/badge/GitHub-olson--sean--k/plexus-8da0cb?logo=github&style=for-the-badge)](https://github.com/olson-sean-k/plexus)\n[![docs.rs](https://img.shields.io/badge/docs.rs-plexus-66c2a5?logo=rust&style=for-the-badge)](https://docs.rs/plexus)\n[![crates.io](https://img.shields.io/crates/v/plexus.svg?logo=rust&style=for-the-badge)](https://crates.io/crates/plexus)\n[![Gitter](https://img.shields.io/badge/Gitter-plexus--rs-c266a5?logo=gitter&style=for-the-badge)](https://gitter.im/plexus-rs/community)\n\n## Primitives\n\nPlexus provides primitive topological structures that can be composed using\ngenerators and iterator expressions. Iterator expressions operate over a\nsequence of polygons with arbitrary vertex data. These polygons can be\ndecomposed, tessellated, indexed, and collected into mesh data structures.\n\n```rust\nuse decorum::R64; // See \"Integrations\".\nuse nalgebra::Point3;\nuse plexus::buffer::MeshBuffer;\nuse plexus::index::Flat3;\nuse plexus::prelude::*;\nuse plexus::primitive::generate::Position;\nuse plexus::primitive::sphere::UvSphere;\n\nuse crate::render::pipeline::{Color4, Vertex};\n\ntype E3 = Point3<R64>;\n\n// Create a buffer of index and vertex data from a uv-sphere.\nlet buffer: MeshBuffer<Flat3, Vertex> = UvSphere::new(16, 8)\n    .polygons::<Position<E3>>()\n    .map_vertices(|position| Vertex::new(position, Color4::white()))\n    .triangulate()\n    .collect();\n```\n\nThe above example uses a generator and iterator expression to transform the\npositional data of a sphere into a linear buffer for indexed drawing. See [the\nsphere example][example-sphere] for a rendered demonstration.\n\n## Half-Edge Graphs\n\nThe `MeshGraph` type represents polygonal meshes as an ergonomic [half-edge\ngraph][dcel] that supports arbitrary data in vertices, arcs (half-edges), edges,\nand faces. Graphs can be traversed and manipulated in many ways that iterator\nexpressions and linear buffers cannot.\n\n```rust\nuse plexus::graph::MeshGraph;\nuse plexus::prelude::*;\nuse plexus::primitive::Tetragon;\nuse ultraviolet::vec::Vec3;\n\ntype E3 = Vec3;\n\n// Create a graph of a tetragon.\nlet mut graph = MeshGraph::<E3>::from(Tetragon::from([\n    (1.0, 1.0, 0.0),\n    (-1.0, 1.0, 0.0),\n    (-1.0, -1.0, 0.0),\n    (1.0, -1.0, 0.0),\n]));\n// Extrude the face of the tetragon.\nlet key = graph.faces().next().unwrap().key();\nlet face = graph.face_mut(key).unwrap().extrude_with_offset(1.0).unwrap();\n```\n\nPlexus avoids exposing very basic topological operations like inserting\nindividual vertices into a graph, because they can easily be done incorrectly.\nInstead, graphs are typically manipulated with more abstract operations like\nmerging and splitting.\n\nSee [the user guide][guide-graphs] for more details about graphs.\n\n## Geometric Traits\n\nPlexus provides optional traits to support spatial operations by exposing\npositional data in vertices. If the data exposed by the `AsPosition` trait\nsupports these geometric traits, then geometric operations become available in\nprimitive and mesh data structure APIs.\n\n```rust\nuse glam::Vec3A;\nuse plexus::geometry::{AsPosition, Vector};\nuse plexus::graph::GraphData;\nuse plexus::prelude::*;\n\ntype E3 = Vec3A;\n\n#[derive(Clone, Copy, PartialEq)]\npub struct Vertex {\n    pub position: E3,\n    pub normal: Vector<E3>,\n}\n\nimpl GraphData for Vertex {\n    type Vertex = Self;\n    type Arc = ();\n    type Edge = ();\n    type Face = ();\n}\n\nimpl AsPosition for Vertex {\n    type Position = E3;\n\n    fn as_position(&self) -> &Self::Position {\n        &self.position\n    }\n}\n```\n\nData structures like `MeshGraph` also provide functions that allow user code to\ncompute geometry without requiring any of these traits; the data in these\nstructures may be arbitrary, including no data at all.\n\n## Integrations\n\nPlexus integrates with the [`theon`] crate to provide geometric traits and\nsupport various mathematics crates in the Rust ecosystem. Any mathematics crate\ncan be used and, if it is supported by Theon, Plexus provides geometric APIs by\nenabling Cargo features.\n\n| Feature                | Default | Crate           |\n|------------------------|---------|-----------------|\n| `geometry-cgmath`      | No      | [`cgmath`]      |\n| `geometry-glam`        | No      | [`glam`]        |\n| `geometry-mint`        | No      | [`mint`]        |\n| `geometry-nalgebra`    | No      | [`nalgebra`]    |\n| `geometry-ultraviolet` | No      | [`ultraviolet`] |\n\nEnabling the corresponding feature is recommended if using one of these\nsupported crates.\n\nPlexus also integrates with the [`decorum`] crate for floating-point\nrepresentations that can be hashed for fast indexing. The `R64` type is a\n(totally ordered) real number with an `f64` representation that cannot be `NaN`\nnor infinity, for example. Geometric conversion traits are implemented for\nsupported types to allow for implicit conversions of scalar types.\n\n## Encodings\n\nPlexus provides support for polygonal mesh encodings. This allows mesh data\nstructures like `MeshGraph` and `MeshBuffer` to be serialized and deserialized\nto and from various formats.\n\n```rust\nuse nalgebra::Point3;\nuse plexus::encoding::ply::{FromPly, PositionEncoding};\nuse plexus::graph::MeshGraph;\nuse plexus::prelude::*;\nuse std::fs::File;\n\ntype E3 = Point3<f64>;\n\nlet ply = File::open(\"cube.ply\").unwrap();\nlet encoding = PositionEncoding::<E3>::default();\nlet (graph, _) = MeshGraph::<E3>::from_ply(encoding, ply).unwrap();\n```\n\nEncoding support is optional and enabled via Cargo features.\n\n| Feature        | Default | Encoding | Read | Write |\n|----------------|---------|----------|------|-------|\n| `encoding-ply` | No      | PLY      | Yes  | No    |\n\nSee [the teapot example][example-teapot] for a rendered demonstration of reading\na mesh from the file system.\n\n[dcel]: https://en.wikipedia.org/wiki/doubly_connected_edge_list\n\n[guide]: https://plexus.rs/user-guide/getting-started\n[guide-graphs]: https://plexus.rs/user-guide/graphs\n[rustdoc]: https://plexus.rs/rustdoc/plexus\n[website]: https://plexus.rs\n\n[example-sphere]: https://github.com/olson-sean-k/plexus/tree/master/examples/sphere/src/main.rs\n[example-teapot]: https://github.com/olson-sean-k/plexus/tree/master/examples/teapot/src/main.rs\n\n[`cgmath`]: https://crates.io/crates/cgmath\n[`decorum`]: https://crates.io/crates/decorum\n[`glam`]: https://crates.io/crates/glam\n[`mint`]: https://crates.io/crates/mint\n[`nalgebra`]: https://crates.io/crates/nalgebra\n[`theon`]: https://crates.io/crates/theon\n[`ultraviolet`]: https://crates.io/crates/ultraviolet\n"
  },
  {
    "path": "benches/subdivide.rs",
    "content": "use criterion::{criterion_group, criterion_main, BatchSize, Criterion};\nuse nalgebra::Point3;\nuse plexus::geometry::AsPositionMut;\nuse plexus::graph::{EdgeMidpoint, FaceView, GraphData, MeshGraph};\nuse plexus::prelude::*;\nuse plexus::primitive::Tetragon;\nuse smallvec::SmallVec;\n\nconst DEPTH: usize = 8;\n\ntype E3 = Point3<f64>;\n\npub trait Ambo<G> {\n    #[must_use]\n    fn ambo(self) -> Self;\n}\n\nimpl<G> Ambo<G> for FaceView<&'_ mut MeshGraph<G>>\nwhere\n    G: EdgeMidpoint + GraphData,\n    G::Vertex: AsPositionMut,\n{\n    // Subdivide the face with a polygon formed from vertices at the midpoints\n    // of the edges of the face.\n    fn ambo(self) -> Self {\n        // Split each edge, stashing the vertex key and moving to the next arc.\n        let arity = self.arity();\n        let mut arc = self.into_arc();\n        let mut splits = SmallVec::<[_; 4]>::with_capacity(arity);\n        for _ in 0..arity {\n            let vertex = arc.split_at_midpoint();\n            splits.push(vertex.key());\n            arc = vertex.into_outgoing_arc().into_next_arc();\n        }\n        // Split faces along the vertices from each arc split.\n        let mut face = arc.into_face().unwrap();\n        for (a, b) in splits.into_iter().perimeter() {\n            face = face.split(a, b).unwrap().into_face().unwrap();\n        }\n        // Return the face forming the similar polygon.\n        face\n    }\n}\n\nfn tetragon() -> MeshGraph<E3> {\n    // Create a graph from a tetragon.\n    MeshGraph::from(Tetragon::from([\n        (1.0, 0.0, -1.0),\n        (-1.0, 0.0, -1.0),\n        (-1.0, 0.0, 1.0),\n        (1.0, 0.0, 1.0),\n    ]))\n}\n\nfn subdivide(mut graph: MeshGraph<E3>) {\n    // Get the face of the tetragon.\n    let key = graph.faces().next().unwrap().key();\n    let mut face = graph.face_mut(key).unwrap();\n\n    // Subdivide and extrude the face repeatedly.\n    for _ in 0..DEPTH {\n        face = face.ambo().extrude_with_offset(0.5).unwrap();\n    }\n}\n\nfn benchmark(criterion: &mut Criterion) {\n    criterion.bench_function(\"subdivide\", move |bencher| {\n        bencher.iter_batched(tetragon, subdivide, BatchSize::SmallInput)\n    });\n}\n\ncriterion_group!(benches, benchmark);\ncriterion_main!(benches);\n"
  },
  {
    "path": "data/cube.ply",
    "content": "ply\nformat ascii 1.0\nelement vertex 8\nproperty float x\nproperty float y\nproperty float z\nelement face 6\nproperty list uint8 uint32 vertex_index\nend_header\n0 0 0\n0 0 1\n0 1 1\n0 1 0\n1 0 0\n1 0 1\n1 1 1\n1 1 0\n4 0 1 2 3\n4 7 6 5 4\n4 0 4 5 1\n4 1 5 6 2\n4 2 6 7 3\n4 3 7 4 0\n"
  },
  {
    "path": "data/plexus.ply",
    "content": "ply\nformat ascii 1.0\ncomment 0 1 3 4 5 10 12 14 20 21 27 28 35 36 43 44 53 54\nelement vertex 55\nproperty float x\nproperty float y\nproperty float z\nelement face 56\nproperty list uint8 uint32 vertex_index\nend_header\n0 1 0\n-2 0 0\n0 0 0\n2 0 0\n2 -1 0\n0 -2 0\n-2 -1 0\n-2 -3 0\n0 -4 0\n-2 -5 0\n0 -6 0\n-2 -7 0\n0 -8 0\n-2 -9 0\n0 -10 0\n2 -7 0\n4 -6 0\n2 -5 0\n6 -5 0\n4 -4 0\n8 -4 0\n6 -3 0\n8 -2 0\n6 -1 0\n8 0 0\n6 1 0\n8 2 0\n6 2 0\n8 3 0\n6 3 0\n6 4 0\n4 3 0\n4 5 0\n2 4 0\n2 6 0\n0 7 0\n0 5 0\n-2 6 0\n-2 4 0\n-4 5 0\n-4 3 0\n-6 4 0\n-6 3 0\n-6 2 0\n-8 3 0\n-6 1 0\n-8 2 0\n-6 -1 0\n-8 0 0\n-6 -3 0\n-8 -2 0\n-6 -5 0\n-8 -4 0\n-6 -7 0\n-8 -6 0\n3 4 2 5\n3 3 2 4\n3 3 0 2\n3 0 1 2\n3 2 1 6\n3 2 6 5\n3 5 6 7\n3 5 7 8\n3 8 7 9\n3 8 9 10\n3 10 9 11\n3 10 11 12\n3 12 11 13\n3 12 13 14\n3 15 10 12\n3 17 10 15\n3 16 17 15\n3 19 17 16\n3 18 19 16\n3 21 19 18\n3 20 21 18\n3 22 21 20\n3 22 23 21\n3 24 23 22\n3 24 25 23\n3 26 25 24\n3 26 27 25\n3 26 29 27\n3 28 29 26\n3 28 30 29\n3 29 31 27\n3 30 31 29\n3 30 32 31\n3 32 33 31\n3 32 34 33\n3 34 36 33\n3 34 35 36\n3 35 37 36\n3 36 37 38\n3 37 39 38\n3 38 39 40\n3 39 41 40\n3 40 41 42\n3 40 42 43\n3 41 44 42\n3 42 44 46\n3 42 46 43\n3 43 46 45\n3 45 46 48\n3 45 48 47\n3 47 48 50\n3 47 50 49\n3 49 50 52\n3 49 52 51\n3 51 52 54\n3 51 54 53\n"
  },
  {
    "path": "data/teapot.ply",
    "content": "ply\nformat ascii 1.0\nelement vertex 1177\nproperty float32 x\nproperty float32 y\nproperty float32 z\nelement face 2256\nproperty list uint8 uint32 vertex_index\nend_header\n1.38137 0 2.45469\n1.4 0 2.4\n1.35074 -0.375926 2.4\n1.33276 -0.370922 2.45469\n1.38426 0 2.4875\n1.33555 -0.371699 2.4875\n1.40312 0 2.49844\n1.35376 -0.376765 2.49844\n1.43241 0 2.4875\n1.38201 -0.384628 2.4875\n1.46655 0 2.45469\n1.41495 -0.393796 2.45469\n1.5 0 2.4\n1.44722 -0.402778 2.4\n1.21126 -0.711407 2.4\n1.19514 -0.701938 2.45469\n1.19764 -0.703409 2.4875\n1.21396 -0.712995 2.49844\n1.2393 -0.727875 2.4875\n1.26884 -0.745225 2.45469\n1.29778 -0.762222 2.4\n0.994 -0.994 2.4\n0.98077 -0.98077 2.45469\n0.982824 -0.982824 2.4875\n0.996219 -0.996219 2.49844\n1.01701 -1.01701 2.4875\n1.04125 -1.04125 2.45469\n1.065 -1.065 2.4\n0.711407 -1.21126 2.4\n0.701938 -1.19514 2.45469\n0.703409 -1.19764 2.4875\n0.712995 -1.21396 2.49844\n0.727875 -1.2393 2.4875\n0.745225 -1.26884 2.45469\n0.762222 -1.29778 2.4\n0.375926 -1.35074 2.4\n0.370922 -1.33276 2.45469\n0.371699 -1.33555 2.4875\n0.376765 -1.35376 2.49844\n0.384628 -1.38201 2.4875\n0.393796 -1.41495 2.45469\n0.402778 -1.44722 2.4\n0 -1.4 2.4\n0 -1.38137 2.45469\n0 -1.38426 2.4875\n0 -1.40312 2.49844\n0 -1.43241 2.4875\n0 -1.46655 2.45469\n0 -1.5 2.4\n-0.375926 -1.35074 2.4\n-0.370922 -1.33276 2.45469\n-0.371699 -1.33555 2.4875\n-0.376765 -1.35376 2.49844\n-0.384628 -1.38201 2.4875\n-0.393796 -1.41495 2.45469\n-0.402778 -1.44722 2.4\n-0.711407 -1.21126 2.4\n-0.701938 -1.19514 2.45469\n-0.703409 -1.19764 2.4875\n-0.712995 -1.21396 2.49844\n-0.727875 -1.2393 2.4875\n-0.745225 -1.26884 2.45469\n-0.762222 -1.29778 2.4\n-0.994 -0.994 2.4\n-0.98077 -0.98077 2.45469\n-0.982824 -0.982824 2.4875\n-0.996219 -0.996219 2.49844\n-1.01701 -1.01701 2.4875\n-1.04125 -1.04125 2.45469\n-1.065 -1.065 2.4\n-1.21126 -0.711407 2.4\n-1.19514 -0.701938 2.45469\n-1.19764 -0.703409 2.4875\n-1.21396 -0.712995 2.49844\n-1.2393 -0.727875 2.4875\n-1.26884 -0.745225 2.45469\n-1.29778 -0.762222 2.4\n-1.35074 -0.375926 2.4\n-1.33276 -0.370922 2.45469\n-1.33555 -0.371699 2.4875\n-1.35376 -0.376765 2.49844\n-1.38201 -0.384628 2.4875\n-1.41495 -0.393796 2.45469\n-1.44722 -0.402778 2.4\n-1.4 0 2.4\n-1.38137 0 2.45469\n-1.38426 0 2.4875\n-1.40312 0 2.49844\n-1.43241 0 2.4875\n-1.46655 0 2.45469\n-1.5 0 2.4\n-1.35074 0.375926 2.4\n-1.33276 0.370922 2.45469\n-1.33555 0.371699 2.4875\n-1.35376 0.376765 2.49844\n-1.38201 0.384628 2.4875\n-1.41495 0.393796 2.45469\n-1.44722 0.402778 2.4\n-1.21126 0.711407 2.4\n-1.19514 0.701938 2.45469\n-1.19764 0.703409 2.4875\n-1.21396 0.712995 2.49844\n-1.2393 0.727875 2.4875\n-1.26884 0.745225 2.45469\n-1.29778 0.762222 2.4\n-0.994 0.994 2.4\n-0.98077 0.98077 2.45469\n-0.982824 0.982824 2.4875\n-0.996219 0.996219 2.49844\n-1.01701 1.01701 2.4875\n-1.04125 1.04125 2.45469\n-1.065 1.065 2.4\n-0.711407 1.21126 2.4\n-0.701938 1.19514 2.45469\n-0.703409 1.19764 2.4875\n-0.712995 1.21396 2.49844\n-0.727875 1.2393 2.4875\n-0.745225 1.26884 2.45469\n-0.762222 1.29778 2.4\n-0.375926 1.35074 2.4\n-0.370922 1.33276 2.45469\n-0.371699 1.33555 2.4875\n-0.376765 1.35376 2.49844\n-0.384628 1.38201 2.4875\n-0.393796 1.41495 2.45469\n-0.402778 1.44722 2.4\n0 1.4 2.4\n0 1.38137 2.45469\n0 1.38426 2.4875\n0 1.40312 2.49844\n0 1.43241 2.4875\n0 1.46655 2.45469\n0 1.5 2.4\n0.375926 1.35074 2.4\n0.370922 1.33276 2.45469\n0.371699 1.33555 2.4875\n0.376765 1.35376 2.49844\n0.384628 1.38201 2.4875\n0.393796 1.41495 2.45469\n0.402778 1.44722 2.4\n0.711407 1.21126 2.4\n0.701938 1.19514 2.45469\n0.703409 1.19764 2.4875\n0.712995 1.21396 2.49844\n0.727875 1.2393 2.4875\n0.745225 1.26884 2.45469\n0.762222 1.29778 2.4\n0.994 0.994 2.4\n0.98077 0.98077 2.45469\n0.982824 0.982824 2.4875\n0.996219 0.996219 2.49844\n1.01701 1.01701 2.4875\n1.04125 1.04125 2.45469\n1.065 1.065 2.4\n1.21126 0.711407 2.4\n1.19514 0.701938 2.45469\n1.19764 0.703409 2.4875\n1.21396 0.712995 2.49844\n1.2393 0.727875 2.4875\n1.26884 0.745225 2.45469\n1.29778 0.762222 2.4\n1.35074 0.375926 2.4\n1.33276 0.370922 2.45469\n1.33555 0.371699 2.4875\n1.35376 0.376765 2.49844\n1.38201 0.384628 2.4875\n1.41495 0.393796 2.45469\n1.44722 0.402778 2.4\n1.62384 0 2.13785\n1.56671 -0.436032 2.13785\n1.74074 0 1.87778\n1.67949 -0.467421 1.87778\n1.84375 0 1.62187\n1.77888 -0.495081 1.62188\n1.92593 0 1.37222\n1.85816 -0.517147 1.37222\n1.98032 0 1.1309\n1.91065 -0.531754 1.1309\n2 0 0.9\n1.92963 -0.537037 0.9\n1.40492 -0.825153 2.13785\n1.50606 -0.884554 1.87778\n1.59519 -0.936898 1.62188\n1.66628 -0.978656 1.37222\n1.71335 -1.0063 1.1309\n1.73037 -1.0163 0.9\n1.15293 -1.15293 2.13785\n1.23593 -1.23593 1.87778\n1.30906 -1.30906 1.62187\n1.36741 -1.36741 1.37222\n1.40603 -1.40603 1.1309\n1.42 -1.42 0.9\n0.825153 -1.40492 2.13785\n0.884554 -1.50606 1.87778\n0.936898 -1.59519 1.62188\n0.978656 -1.66628 1.37222\n1.0063 -1.71335 1.1309\n1.0163 -1.73037 0.9\n0.436032 -1.56671 2.13785\n0.467421 -1.67949 1.87778\n0.495081 -1.77888 1.62187\n0.517147 -1.85816 1.37222\n0.531754 -1.91065 1.1309\n0.537037 -1.92963 0.9\n0 -1.62384 2.13785\n0 -1.74074 1.87778\n0 -1.84375 1.62187\n0 -1.92593 1.37222\n0 -1.98032 1.1309\n0 -2 0.9\n-0.436032 -1.56671 2.13785\n-0.467421 -1.67949 1.87778\n-0.495081 -1.77888 1.62188\n-0.517147 -1.85816 1.37222\n-0.531754 -1.91065 1.1309\n-0.537037 -1.92963 0.9\n-0.825153 -1.40492 2.13785\n-0.884554 -1.50606 1.87778\n-0.936898 -1.59519 1.62188\n-0.978656 -1.66628 1.37222\n-1.0063 -1.71335 1.1309\n-1.0163 -1.73037 0.9\n-1.15293 -1.15293 2.13785\n-1.23593 -1.23593 1.87778\n-1.30906 -1.30906 1.62187\n-1.36741 -1.36741 1.37222\n-1.40603 -1.40603 1.1309\n-1.42 -1.42 0.9\n-1.40492 -0.825153 2.13785\n-1.50606 -0.884554 1.87778\n-1.59519 -0.936898 1.62188\n-1.66628 -0.978656 1.37222\n-1.71335 -1.0063 1.1309\n-1.73037 -1.0163 0.9\n-1.56671 -0.436032 2.13785\n-1.67949 -0.467421 1.87778\n-1.77888 -0.495081 1.62187\n-1.85816 -0.517147 1.37222\n-1.91065 -0.531754 1.1309\n-1.92963 -0.537037 0.9\n-1.62384 0 2.13785\n-1.74074 0 1.87778\n-1.84375 0 1.62187\n-1.92593 0 1.37222\n-1.98032 0 1.1309\n-2 0 0.9\n-1.56671 0.436032 2.13785\n-1.67949 0.467421 1.87778\n-1.77888 0.495081 1.62188\n-1.85816 0.517147 1.37222\n-1.91065 0.531754 1.1309\n-1.92963 0.537037 0.9\n-1.40492 0.825153 2.13785\n-1.50606 0.884554 1.87778\n-1.59519 0.936898 1.62188\n-1.66628 0.978656 1.37222\n-1.71335 1.0063 1.1309\n-1.73037 1.0163 0.9\n-1.15293 1.15293 2.13785\n-1.23593 1.23593 1.87778\n-1.30906 1.30906 1.62187\n-1.36741 1.36741 1.37222\n-1.40603 1.40603 1.1309\n-1.42 1.42 0.9\n-0.825153 1.40492 2.13785\n-0.884554 1.50606 1.87778\n-0.936898 1.59519 1.62188\n-0.978656 1.66628 1.37222\n-1.0063 1.71335 1.1309\n-1.0163 1.73037 0.9\n-0.436032 1.56671 2.13785\n-0.467421 1.67949 1.87778\n-0.495081 1.77888 1.62187\n-0.517147 1.85816 1.37222\n-0.531754 1.91065 1.1309\n-0.537037 1.92963 0.9\n0 1.62384 2.13785\n0 1.74074 1.87778\n0 1.84375 1.62187\n0 1.92593 1.37222\n0 1.98032 1.1309\n0 2 0.9\n0.436032 1.56671 2.13785\n0.467421 1.67949 1.87778\n0.495081 1.77888 1.62188\n0.517147 1.85816 1.37222\n0.531754 1.91065 1.1309\n0.537037 1.92963 0.9\n0.825153 1.40492 2.13785\n0.884554 1.50606 1.87778\n0.936898 1.59519 1.62188\n0.978656 1.66628 1.37222\n1.0063 1.71335 1.1309\n1.0163 1.73037 0.9\n1.15293 1.15293 2.13785\n1.23593 1.23593 1.87778\n1.30906 1.30906 1.62187\n1.36741 1.36741 1.37222\n1.40603 1.40603 1.1309\n1.42 1.42 0.9\n1.40492 0.825153 2.13785\n1.50606 0.884554 1.87778\n1.59519 0.936898 1.62188\n1.66628 0.978656 1.37222\n1.71335 1.0063 1.1309\n1.73037 1.0163 0.9\n1.56671 0.436032 2.13785\n1.67949 0.467421 1.87778\n1.77888 0.495081 1.62187\n1.85816 0.517147 1.37222\n1.91065 0.531754 1.1309\n1.92963 0.537037 0.9\n1.96296 0 0.693403\n1.8939 -0.527092 0.693403\n1.87037 0 0.522222\n1.80456 -0.502229 0.522222\n1.75 0 0.384375\n1.68843 -0.469907 0.384375\n1.62963 0 0.277778\n1.57229 -0.437586 0.277778\n1.53704 0 0.200347\n1.48296 -0.412723 0.200347\n1.5 0 0.15\n1.44722 -0.402778 0.15\n1.69833 -0.997476 0.693403\n1.61822 -0.950425 0.522222\n1.51407 -0.889259 0.384375\n1.40993 -0.828093 0.277778\n1.32982 -0.781043 0.200347\n1.29778 -0.762222 0.15\n1.3937 -1.3937 0.693403\n1.32796 -1.32796 0.522222\n1.2425 -1.2425 0.384375\n1.15704 -1.15704 0.277778\n1.0913 -1.0913 0.200347\n1.065 -1.065 0.15\n0.997476 -1.69833 0.693403\n0.950425 -1.61822 0.522222\n0.889259 -1.51407 0.384375\n0.828093 -1.40993 0.277778\n0.781043 -1.32982 0.200347\n0.762222 -1.29778 0.15\n0.527092 -1.8939 0.693403\n0.502229 -1.80456 0.522222\n0.469907 -1.68843 0.384375\n0.437586 -1.57229 0.277778\n0.412723 -1.48296 0.200347\n0.402778 -1.44722 0.15\n0 -1.96296 0.693403\n0 -1.87037 0.522222\n0 -1.75 0.384375\n0 -1.62963 0.277778\n0 -1.53704 0.200347\n0 -1.5 0.15\n-0.527092 -1.8939 0.693403\n-0.502229 -1.80456 0.522222\n-0.469907 -1.68843 0.384375\n-0.437586 -1.57229 0.277778\n-0.412723 -1.48296 0.200347\n-0.402778 -1.44722 0.15\n-0.997476 -1.69833 0.693403\n-0.950425 -1.61822 0.522222\n-0.889259 -1.51407 0.384375\n-0.828093 -1.40993 0.277778\n-0.781043 -1.32982 0.200347\n-0.762222 -1.29778 0.15\n-1.3937 -1.3937 0.693403\n-1.32796 -1.32796 0.522222\n-1.2425 -1.2425 0.384375\n-1.15704 -1.15704 0.277778\n-1.0913 -1.0913 0.200347\n-1.065 -1.065 0.15\n-1.69833 -0.997476 0.693403\n-1.61822 -0.950425 0.522222\n-1.51407 -0.889259 0.384375\n-1.40993 -0.828093 0.277778\n-1.32982 -0.781043 0.200347\n-1.29778 -0.762222 0.15\n-1.8939 -0.527092 0.693403\n-1.80456 -0.502229 0.522222\n-1.68843 -0.469907 0.384375\n-1.57229 -0.437586 0.277778\n-1.48296 -0.412723 0.200347\n-1.44722 -0.402778 0.15\n-1.96296 0 0.693403\n-1.87037 0 0.522222\n-1.75 0 0.384375\n-1.62963 0 0.277778\n-1.53704 0 0.200347\n-1.5 0 0.15\n-1.8939 0.527092 0.693403\n-1.80456 0.502229 0.522222\n-1.68843 0.469907 0.384375\n-1.57229 0.437586 0.277778\n-1.48296 0.412723 0.200347\n-1.44722 0.402778 0.15\n-1.69833 0.997476 0.693403\n-1.61822 0.950425 0.522222\n-1.51407 0.889259 0.384375\n-1.40993 0.828093 0.277778\n-1.32982 0.781043 0.200347\n-1.29778 0.762222 0.15\n-1.3937 1.3937 0.693403\n-1.32796 1.32796 0.522222\n-1.2425 1.2425 0.384375\n-1.15704 1.15704 0.277778\n-1.0913 1.0913 0.200347\n-1.065 1.065 0.15\n-0.997476 1.69833 0.693403\n-0.950425 1.61822 0.522222\n-0.889259 1.51407 0.384375\n-0.828093 1.40993 0.277778\n-0.781043 1.32982 0.200347\n-0.762222 1.29778 0.15\n-0.527092 1.8939 0.693403\n-0.502229 1.80456 0.522222\n-0.469907 1.68843 0.384375\n-0.437586 1.57229 0.277778\n-0.412723 1.48296 0.200347\n-0.402778 1.44722 0.15\n0 1.96296 0.693403\n0 1.87037 0.522222\n0 1.75 0.384375\n0 1.62963 0.277778\n0 1.53704 0.200347\n0 1.5 0.15\n0.527092 1.8939 0.693403\n0.502229 1.80456 0.522222\n0.469907 1.68843 0.384375\n0.437586 1.57229 0.277778\n0.412723 1.48296 0.200347\n0.402778 1.44722 0.15\n0.997476 1.69833 0.693403\n0.950425 1.61822 0.522222\n0.889259 1.51407 0.384375\n0.828093 1.40993 0.277778\n0.781043 1.32982 0.200347\n0.762222 1.29778 0.15\n1.3937 1.3937 0.693403\n1.32796 1.32796 0.522222\n1.2425 1.2425 0.384375\n1.15704 1.15704 0.277778\n1.0913 1.0913 0.200347\n1.065 1.065 0.15\n1.69833 0.997476 0.693403\n1.61822 0.950425 0.522222\n1.51407 0.889259 0.384375\n1.40993 0.828093 0.277778\n1.32982 0.781043 0.200347\n1.29778 0.762222 0.15\n1.8939 0.527092 0.693403\n1.80456 0.502229 0.522222\n1.68843 0.469907 0.384375\n1.57229 0.437586 0.277778\n1.48296 0.412723 0.200347\n1.44722 0.402778 0.15\n0.605903 0 0.005903\n0 0 0\n0.584584 0.162696 0.005903\n1.02222 0 0.022222\n0.986255 0.274486 0.022222\n1.28437 0 0.046875\n1.23918 0.344878 0.046875\n1.42778 0 0.077778\n1.37754 0.383385 0.077778\n1.48785 0 0.112847\n1.4355 0.399515 0.112847\n0.524218 0.307888 0.005903\n0.884412 0.51944 0.022222\n1.11122 0.652653 0.046875\n1.23529 0.725523 0.077778\n1.28726 0.756047 0.112847\n0.430191 0.430191 0.005903\n0.725778 0.725778 0.022222\n0.911906 0.911906 0.046875\n1.01372 1.01372 0.077778\n1.05637 1.05637 0.112847\n0.307888 0.524218 0.005903\n0.51944 0.884412 0.022222\n0.652653 1.11122 0.046875\n0.725523 1.23529 0.077778\n0.756047 1.28726 0.112847\n0.162696 0.584584 0.005903\n0.274486 0.986255 0.022222\n0.344878 1.23918 0.046875\n0.383385 1.37754 0.077778\n0.399515 1.4355 0.112847\n0 0.605903 0.005903\n0 1.02222 0.022222\n0 1.28437 0.046875\n0 1.42778 0.077778\n0 1.48785 0.112847\n-0.162696 0.584584 0.005903\n-0.274486 0.986255 0.022222\n-0.344878 1.23918 0.046875\n-0.383385 1.37754 0.077778\n-0.399515 1.4355 0.112847\n-0.307888 0.524218 0.005903\n-0.51944 0.884412 0.022222\n-0.652653 1.11122 0.046875\n-0.725523 1.23529 0.077778\n-0.756047 1.28726 0.112847\n-0.430191 0.430191 0.005903\n-0.725778 0.725778 0.022222\n-0.911906 0.911906 0.046875\n-1.01372 1.01372 0.077778\n-1.05637 1.05637 0.112847\n-0.524218 0.307888 0.005903\n-0.884412 0.51944 0.022222\n-1.11122 0.652653 0.046875\n-1.23529 0.725523 0.077778\n-1.28726 0.756047 0.112847\n-0.584584 0.162696 0.005903\n-0.986255 0.274486 0.022222\n-1.23918 0.344878 0.046875\n-1.37754 0.383385 0.077778\n-1.4355 0.399515 0.112847\n-0.605903 0 0.005903\n-1.02222 0 0.022222\n-1.28437 0 0.046875\n-1.42778 0 0.077778\n-1.48785 0 0.112847\n-0.584584 -0.162696 0.005903\n-0.986255 -0.274486 0.022222\n-1.23918 -0.344878 0.046875\n-1.37754 -0.383385 0.077778\n-1.4355 -0.399515 0.112847\n-0.524218 -0.307888 0.005903\n-0.884412 -0.51944 0.022222\n-1.11122 -0.652653 0.046875\n-1.23529 -0.725523 0.077778\n-1.28726 -0.756047 0.112847\n-0.430191 -0.430191 0.005903\n-0.725778 -0.725778 0.022222\n-0.911906 -0.911906 0.046875\n-1.01372 -1.01372 0.077778\n-1.05637 -1.05637 0.112847\n-0.307888 -0.524218 0.005903\n-0.51944 -0.884412 0.022222\n-0.652653 -1.11122 0.046875\n-0.725523 -1.23529 0.077778\n-0.756047 -1.28726 0.112847\n-0.162696 -0.584584 0.005903\n-0.274486 -0.986255 0.022222\n-0.344878 -1.23918 0.046875\n-0.383385 -1.37754 0.077778\n-0.399515 -1.4355 0.112847\n0 -0.605903 0.005903\n0 -1.02222 0.022222\n0 -1.28437 0.046875\n0 -1.42778 0.077778\n0 -1.48785 0.112847\n0.162696 -0.584584 0.005903\n0.274486 -0.986255 0.022222\n0.344878 -1.23918 0.046875\n0.383385 -1.37754 0.077778\n0.399515 -1.4355 0.112847\n0.307888 -0.524218 0.005903\n0.51944 -0.884412 0.022222\n0.652653 -1.11122 0.046875\n0.725523 -1.23529 0.077778\n0.756047 -1.28726 0.112847\n0.430191 -0.430191 0.005903\n0.725778 -0.725778 0.022222\n0.911906 -0.911906 0.046875\n1.01372 -1.01372 0.077778\n1.05637 -1.05637 0.112847\n0.524218 -0.307888 0.005903\n0.884412 -0.51944 0.022222\n1.11122 -0.652653 0.046875\n1.23529 -0.725523 0.077778\n1.28726 -0.756047 0.112847\n0.584584 -0.162696 0.005903\n0.986255 -0.274486 0.022222\n1.23918 -0.344878 0.046875\n1.37754 -0.383385 0.077778\n1.4355 -0.399515 0.112847\n0.2 0 2.7\n0.171296 0 2.78542\n0.165279 -0.046045 2.78542\n0.192963 -0.053704 2.7\n0.148234 -0.087106 2.78542\n0.173037 -0.10163 2.7\n0.121672 -0.121672 2.78542\n0.142 -0.142 2.7\n0.087106 -0.148234 2.78542\n0.10163 -0.173037 2.7\n0.046045 -0.165279 2.78542\n0.053704 -0.192963 2.7\n0 -0.171296 2.78542\n0 -0.2 2.7\n-0.046045 -0.165279 2.78542\n-0.053704 -0.192963 2.7\n-0.087106 -0.148234 2.78542\n-0.10163 -0.173037 2.7\n-0.121672 -0.121672 2.78542\n-0.142 -0.142 2.7\n-0.148234 -0.087106 2.78542\n-0.173037 -0.10163 2.7\n-0.165279 -0.046045 2.78542\n-0.192963 -0.053704 2.7\n-0.171296 0 2.78542\n-0.2 0 2.7\n-0.165279 0.046045 2.78542\n-0.192963 0.053704 2.7\n-0.148234 0.087106 2.78542\n-0.173037 0.10163 2.7\n-0.121672 0.121672 2.78542\n-0.142 0.142 2.7\n-0.087106 0.148234 2.78542\n-0.10163 0.173037 2.7\n-0.046045 0.165279 2.78542\n-0.053704 0.192963 2.7\n0 0.171296 2.78542\n0 0.2 2.7\n0.046045 0.165279 2.78542\n0.053704 0.192963 2.7\n0.087106 0.148234 2.78542\n0.10163 0.173037 2.7\n0.121672 0.121672 2.78542\n0.142 0.142 2.7\n0.148234 0.087106 2.78542\n0.173037 0.10163 2.7\n0.165279 0.046045 2.78542\n0.192963 0.053704 2.7\n0.350926 0 2.63611\n0.338579 -0.09423 2.63611\n0.574074 0 2.58889\n0.553875 -0.15415 2.58889\n0.825 0 2.55\n0.795972 -0.221528 2.55\n1.05926 0 2.51111\n1.02199 -0.284431 2.51111\n1.23241 0 2.46389\n1.18904 -0.330924 2.46389\n1.3 0 2.4\n1.25426 -0.349074 2.4\n0.303616 -0.178322 2.63611\n0.49668 -0.291715 2.58889\n0.713778 -0.419222 2.55\n0.916455 -0.538261 2.51111\n1.06626 -0.626246 2.46389\n1.12474 -0.660593 2.4\n0.249157 -0.249157 2.63611\n0.407593 -0.407593 2.58889\n0.58575 -0.58575 2.55\n0.752074 -0.752074 2.51111\n0.875009 -0.875009 2.46389\n0.923 -0.923 2.4\n0.178322 -0.303616 2.63611\n0.291715 -0.49668 2.58889\n0.419222 -0.713778 2.55\n0.538261 -0.916455 2.51111\n0.626246 -1.06626 2.46389\n0.660593 -1.12474 2.4\n0.09423 -0.338579 2.63611\n0.15415 -0.553875 2.58889\n0.221528 -0.795972 2.55\n0.284431 -1.02199 2.51111\n0.330924 -1.18904 2.46389\n0.349074 -1.25426 2.4\n0 -0.350926 2.63611\n0 -0.574074 2.58889\n0 -0.825 2.55\n0 -1.05926 2.51111\n0 -1.23241 2.46389\n0 -1.3 2.4\n-0.09423 -0.338579 2.63611\n-0.15415 -0.553875 2.58889\n-0.221528 -0.795972 2.55\n-0.284431 -1.02199 2.51111\n-0.330924 -1.18904 2.46389\n-0.349074 -1.25426 2.4\n-0.178322 -0.303616 2.63611\n-0.291715 -0.49668 2.58889\n-0.419222 -0.713778 2.55\n-0.538261 -0.916455 2.51111\n-0.626246 -1.06626 2.46389\n-0.660593 -1.12474 2.4\n-0.249157 -0.249157 2.63611\n-0.407593 -0.407593 2.58889\n-0.58575 -0.58575 2.55\n-0.752074 -0.752074 2.51111\n-0.875009 -0.875009 2.46389\n-0.923 -0.923 2.4\n-0.303616 -0.178322 2.63611\n-0.49668 -0.291715 2.58889\n-0.713778 -0.419222 2.55\n-0.916455 -0.538261 2.51111\n-1.06626 -0.626246 2.46389\n-1.12474 -0.660593 2.4\n-0.338579 -0.09423 2.63611\n-0.553875 -0.15415 2.58889\n-0.795972 -0.221528 2.55\n-1.02199 -0.284431 2.51111\n-1.18904 -0.330924 2.46389\n-1.25426 -0.349074 2.4\n-0.350926 0 2.63611\n-0.574074 0 2.58889\n-0.825 0 2.55\n-1.05926 0 2.51111\n-1.23241 0 2.46389\n-1.3 0 2.4\n-0.338579 0.09423 2.63611\n-0.553875 0.15415 2.58889\n-0.795972 0.221528 2.55\n-1.02199 0.284431 2.51111\n-1.18904 0.330924 2.46389\n-1.25426 0.349074 2.4\n-0.303616 0.178322 2.63611\n-0.49668 0.291715 2.58889\n-0.713778 0.419222 2.55\n-0.916455 0.538261 2.51111\n-1.06626 0.626246 2.46389\n-1.12474 0.660593 2.4\n-0.249157 0.249157 2.63611\n-0.407593 0.407593 2.58889\n-0.58575 0.58575 2.55\n-0.752074 0.752074 2.51111\n-0.875009 0.875009 2.46389\n-0.923 0.923 2.4\n-0.178322 0.303616 2.63611\n-0.291715 0.49668 2.58889\n-0.419222 0.713778 2.55\n-0.538261 0.916455 2.51111\n-0.626246 1.06626 2.46389\n-0.660593 1.12474 2.4\n-0.09423 0.338579 2.63611\n-0.15415 0.553875 2.58889\n-0.221528 0.795972 2.55\n-0.284431 1.02199 2.51111\n-0.330924 1.18904 2.46389\n-0.349074 1.25426 2.4\n0 0.350926 2.63611\n0 0.574074 2.58889\n0 0.825 2.55\n0 1.05926 2.51111\n0 1.23241 2.46389\n0 1.3 2.4\n0.09423 0.338579 2.63611\n0.15415 0.553875 2.58889\n0.221528 0.795972 2.55\n0.284431 1.02199 2.51111\n0.330924 1.18904 2.46389\n0.349074 1.25426 2.4\n0.178322 0.303616 2.63611\n0.291715 0.49668 2.58889\n0.419222 0.713778 2.55\n0.538261 0.916455 2.51111\n0.626246 1.06626 2.46389\n0.660593 1.12474 2.4\n0.249157 0.249157 2.63611\n0.407593 0.407593 2.58889\n0.58575 0.58575 2.55\n0.752074 0.752074 2.51111\n0.875009 0.875009 2.46389\n0.923 0.923 2.4\n0.303616 0.178322 2.63611\n0.49668 0.291715 2.58889\n0.713778 0.419222 2.55\n0.916455 0.538261 2.51111\n1.06626 0.626246 2.46389\n1.12474 0.660593 2.4\n0.338579 0.09423 2.63611\n0.553875 0.15415 2.58889\n0.795972 0.221528 2.55\n1.02199 0.284431 2.51111\n1.18904 0.330924 2.46389\n1.25426 0.349074 2.4\n-1.92454 0 2.02396\n-1.6 0 2.025\n-1.59259 -0.125 2.04167\n-1.92704 -0.125 2.04055\n-2.1963 0 2.01667\n-2.20645 -0.125 2.03272\n-2.4125 0 1.99687\n-2.42824 -0.125 2.01146\n-2.57037 0 1.95833\n-2.58985 -0.125 1.97006\n-2.66713 0 1.89479\n-2.6887 -0.125 1.90181\n-2.7 0 1.8\n-2.72222 -0.125 1.8\n-1.57407 -0.2 2.08333\n-1.9333 -0.2 2.08202\n-2.23182 -0.2 2.07284\n-2.46759 -0.2 2.04792\n-2.63855 -0.2 1.99938\n-2.74263 -0.2 1.91937\n-2.77778 -0.2 1.8\n-1.55 -0.225 2.1375\n-1.94144 -0.225 2.13594\n-2.26481 -0.225 2.125\n-2.51875 -0.225 2.09531\n-2.70185 -0.225 2.0375\n-2.81273 -0.225 1.94219\n-2.85 -0.225 1.8\n-1.52593 -0.2 2.19167\n-1.94957 -0.2 2.18985\n-2.29781 -0.2 2.17716\n-2.56991 -0.2 2.14271\n-2.76516 -0.2 2.07562\n-2.88284 -0.2 1.96501\n-2.92222 -0.2 1.8\n-1.50741 -0.125 2.23333\n-1.95583 -0.125 2.23133\n-2.32318 -0.125 2.21728\n-2.60926 -0.125 2.17917\n-2.81385 -0.125 2.10494\n-2.93676 -0.125 1.98256\n-2.97778 -0.125 1.8\n-1.5 0 2.25\n-1.95833 0 2.24792\n-2.33333 0 2.23333\n-2.625 0 2.19375\n-2.83333 0 2.11667\n-2.95833 0 1.98958\n-3 0 1.8\n-1.50741 0.125 2.23333\n-1.95583 0.125 2.23133\n-2.32318 0.125 2.21728\n-2.60926 0.125 2.17917\n-2.81385 0.125 2.10494\n-2.93676 0.125 1.98256\n-2.97778 0.125 1.8\n-1.52593 0.2 2.19167\n-1.94957 0.2 2.18985\n-2.29781 0.2 2.17716\n-2.56991 0.2 2.14271\n-2.76516 0.2 2.07562\n-2.88284 0.2 1.96501\n-2.92222 0.2 1.8\n-1.55 0.225 2.1375\n-1.94144 0.225 2.13594\n-2.26481 0.225 2.125\n-2.51875 0.225 2.09531\n-2.70185 0.225 2.0375\n-2.81273 0.225 1.94219\n-2.85 0.225 1.8\n-1.57407 0.2 2.08333\n-1.9333 0.2 2.08202\n-2.23182 0.2 2.07284\n-2.46759 0.2 2.04792\n-2.63855 0.2 1.99938\n-2.74263 0.2 1.91937\n-2.77778 0.2 1.8\n-1.59259 0.125 2.04167\n-1.92704 0.125 2.04055\n-2.20645 0.125 2.03272\n-2.42824 0.125 2.01146\n-2.58985 0.125 1.97006\n-2.6887 0.125 1.90181\n-2.72222 0.125 1.8\n-2.68287 0 1.67083\n-2.70418 -0.125 1.66398\n-2.62963 0 1.51667\n-2.64829 -0.125 1.50535\n-2.5375 0 1.35\n-2.55185 -0.125 1.33576\n-2.4037 0 1.18333\n-2.41221 -0.125 1.16687\n-2.22546 0 1.02917\n-2.22668 -0.125 1.01033\n-1.99259 -0.125 0.877778\n-2.75747 -0.2 1.64684\n-2.69492 -0.2 1.47706\n-2.58773 -0.2 1.30017\n-2.43347 -0.2 1.12572\n-2.22972 -0.2 0.963227\n-1.97407 -0.2 0.822222\n-2.82674 -0.225 1.62457\n-2.75556 -0.225 1.44028\n-2.63437 -0.225 1.25391\n-2.46111 -0.225 1.07222\n-2.23368 -0.225 0.901997\n-1.95 -0.225 0.75\n-2.896 -0.2 1.60229\n-2.81619 -0.2 1.4035\n-2.68102 -0.2 1.20764\n-2.48875 -0.2 1.01872\n-2.23764 -0.2 0.840766\n-1.92593 -0.2 0.677778\n-2.94929 -0.125 1.58515\n-2.86283 -0.125 1.37521\n-2.7169 -0.125 1.17205\n-2.51001 -0.125 0.977572\n-2.24068 -0.125 0.793666\n-1.90741 -0.125 0.622222\n-2.9706 0 1.5783\n-2.88148 0 1.36389\n-2.73125 0 1.15781\n-2.51852 0 0.961111\n-2.2419 0 0.774826\n-1.9 0 0.6\n-2.94929 0.125 1.58515\n-2.86283 0.125 1.37521\n-2.7169 0.125 1.17205\n-2.51001 0.125 0.977572\n-2.24068 0.125 0.793666\n-1.90741 0.125 0.622222\n-2.896 0.2 1.60229\n-2.81619 0.2 1.4035\n-2.68102 0.2 1.20764\n-2.48875 0.2 1.01872\n-2.23764 0.2 0.840766\n-1.92593 0.2 0.677778\n-2.82674 0.225 1.62457\n-2.75556 0.225 1.44028\n-2.63437 0.225 1.25391\n-2.46111 0.225 1.07222\n-2.23368 0.225 0.901997\n-1.95 0.225 0.75\n-2.75747 0.2 1.64684\n-2.69492 0.2 1.47706\n-2.58773 0.2 1.30017\n-2.43347 0.2 1.12572\n-2.22972 0.2 0.963227\n-1.97407 0.2 0.822222\n-2.70418 0.125 1.66398\n-2.64829 0.125 1.50535\n-2.55185 0.125 1.33576\n-2.41221 0.125 1.16687\n-2.22668 0.125 1.01033\n-1.99259 0.125 0.877778\n2.0588 0 1.47639\n1.7 0 1.425\n1.7 -0.275 1.36389\n2.07238 -0.262346 1.42521\n2.27037 0 1.61111\n2.29012 -0.23071 1.57202\n2.3875 0 1.8\n2.40972 -0.189583 1.77361\n2.46296 0 2.01389\n2.48765 -0.148457 1.99928\n2.54954 0 2.22361\n2.5804 -0.116821 2.21831\n2.7 0 2.4\n2.74444 -0.104167 2.4\n1.7 -0.44 1.21111\n2.10633 -0.419753 1.29725\n2.33951 -0.369136 1.47428\n2.46528 -0.303333 1.70764\n2.54938 -0.237531 1.96276\n2.65756 -0.186914 2.20507\n2.85556 -0.166667 2.4\n1.7 -0.495 1.0125\n2.15046 -0.472222 1.1309\n2.4037 -0.415278 1.34722\n2.5375 -0.34125 1.62187\n2.62963 -0.267222 1.91528\n2.75787 -0.210278 2.18785\n3 -0.1875 2.4\n1.7 -0.44 0.813889\n2.1946 -0.419753 0.964558\n2.4679 -0.369136 1.22016\n2.60972 -0.303333 1.53611\n2.70988 -0.237531 1.8678\n2.85818 -0.186914 2.17063\n3.14444 -0.166667 2.4\n1.7 -0.275 0.661111\n2.22855 -0.262346 0.8366\n2.51728 -0.23071 1.12243\n2.66528 -0.189583 1.47014\n2.7716 -0.148457 1.83128\n2.93534 -0.116821 2.15738\n3.25556 -0.104167 2.4\n1.7 0 0.6\n2.24213 0 0.785417\n2.53704 0 1.08333\n2.6875 0 1.44375\n2.7963 0 1.81667\n2.9662 0 2.15208\n3.3 0 2.4\n1.7 0.275 0.661111\n2.22855 0.262346 0.8366\n2.51728 0.23071 1.12243\n2.66528 0.189583 1.47014\n2.7716 0.148457 1.83128\n2.93534 0.116821 2.15738\n3.25556 0.104167 2.4\n1.7 0.44 0.813889\n2.1946 0.419753 0.964558\n2.4679 0.369136 1.22016\n2.60972 0.303333 1.53611\n2.70988 0.237531 1.8678\n2.85818 0.186914 2.17063\n3.14444 0.166667 2.4\n1.7 0.495 1.0125\n2.15046 0.472222 1.1309\n2.4037 0.415278 1.34722\n2.5375 0.34125 1.62187\n2.62963 0.267222 1.91528\n2.75787 0.210278 2.18785\n3 0.1875 2.4\n1.7 0.44 1.21111\n2.10633 0.419753 1.29725\n2.33951 0.369136 1.47428\n2.46528 0.303333 1.70764\n2.54938 0.237531 1.96276\n2.65756 0.186914 2.20507\n2.85556 0.166667 2.4\n1.7 0.275 1.36389\n2.07238 0.262346 1.42521\n2.29012 0.23071 1.57202\n2.40972 0.189583 1.77361\n2.48765 0.148457 1.99928\n2.5804 0.116821 2.21831\n2.74444 0.104167 2.4\n2.74907 0 2.43125\n2.79641 -0.101032 2.43193\n2.79259 0 2.45\n2.83978 -0.092978 2.45123\n2.825 0 2.45625\n2.86968 -0.082031 2.45781\n2.84074 0 2.45\n2.88121 -0.070216 2.45154\n2.83426 0 2.43125\n2.86949 -0.059558 2.43231\n2.8 0 2.4\n2.82963 -0.052083 2.4\n2.91474 -0.161574 2.43361\n2.95775 -0.148148 2.45432\n2.98137 -0.129167 2.46172\n2.98237 -0.107407 2.4554\n2.95756 -0.085648 2.43496\n2.9037 -0.066667 2.4\n3.06858 -0.181684 2.43581\n3.11111 -0.165972 2.45833\n3.12656 -0.142969 2.4668\n3.11389 -0.115278 2.46042\n3.07205 -0.085504 2.43841\n3 -0.05625 2.4\n3.22241 -0.16142 2.438\n3.26447 -0.146914 2.46235\n3.27176 -0.125 2.47187\n3.2454 -0.097531 2.46543\n3.18654 -0.066358 2.44186\n3.0963 -0.033333 2.4\n3.34075 -0.100839 2.43969\n3.38244 -0.091435 2.46543\n3.38345 -0.076823 2.47578\n3.34657 -0.05787 2.46929\n3.27461 -0.035446 2.44451\n3.17037 -0.010417 2.4\n3.38808 0 2.44036\n3.42963 0 2.46667\n3.42813 0 2.47734\n3.38704 0 2.47083\n3.30984 0 2.44557\n3.2 0 2.4\n3.34075 0.10108 2.43969\n3.38244 0.093364 2.46543\n3.38345 0.083333 2.47578\n3.34657 0.073303 2.46929\n3.27461 0.065586 2.44451\n3.17037 0.0625 2.4\n3.22241 0.161728 2.438\n3.26447 0.149383 2.46235\n3.27176 0.133333 2.47187\n3.2454 0.117284 2.46543\n3.18654 0.104938 2.44186\n3.0963 0.1 2.4\n3.06858 0.181944 2.43581\n3.11111 0.168056 2.45833\n3.12656 0.15 2.4668\n3.11389 0.131944 2.46042\n3.07205 0.118056 2.43841\n3 0.1125 2.4\n2.91474 0.161728 2.43361\n2.95775 0.149383 2.45432\n2.98137 0.133333 2.46172\n2.98237 0.117284 2.4554\n2.95756 0.104938 2.43496\n2.9037 0.1 2.4\n2.79641 0.10108 2.43193\n2.83978 0.093364 2.45123\n2.86968 0.083333 2.45781\n2.88121 0.073303 2.45154\n2.86949 0.065586 2.43231\n2.82963 0.0625 2.4\n0.278704 0 3.12708\n0 0 3.15\n0.268946 -0.075078 3.12708\n0.362963 0 3.06667\n0.350254 -0.097771 3.06667\n0.325 0 2.98125\n0.313617 -0.087529 2.98125\n0.237037 0 2.88333\n0.228728 -0.063803 2.88333\n0.241285 -0.141931 3.12708\n0.314228 -0.184834 3.06667\n0.281352 -0.165481 2.98125\n0.20518 -0.120647 2.88333\n0.19814 -0.19814 3.12708\n0.258037 -0.258037 3.06667\n0.231031 -0.231031 2.98125\n0.168463 -0.168463 2.88333\n0.141931 -0.241285 3.12708\n0.184834 -0.314228 3.06667\n0.165481 -0.281352 2.98125\n0.120647 -0.20518 2.88333\n0.075078 -0.268946 3.12708\n0.097771 -0.350254 3.06667\n0.087529 -0.313617 2.98125\n0.063803 -0.228728 2.88333\n0 -0.278704 3.12708\n0 -0.362963 3.06667\n0 -0.325 2.98125\n0 -0.237037 2.88333\n-0.075078 -0.268946 3.12708\n-0.097771 -0.350254 3.06667\n-0.087529 -0.313617 2.98125\n-0.063803 -0.228728 2.88333\n-0.141931 -0.241285 3.12708\n-0.184834 -0.314228 3.06667\n-0.165481 -0.281352 2.98125\n-0.120647 -0.20518 2.88333\n-0.19814 -0.19814 3.12708\n-0.258037 -0.258037 3.06667\n-0.231031 -0.231031 2.98125\n-0.168463 -0.168463 2.88333\n-0.241285 -0.141931 3.12708\n-0.314228 -0.184834 3.06667\n-0.281352 -0.165481 2.98125\n-0.20518 -0.120647 2.88333\n-0.268946 -0.075078 3.12708\n-0.350254 -0.097771 3.06667\n-0.313617 -0.087529 2.98125\n-0.228728 -0.063803 2.88333\n-0.278704 0 3.12708\n-0.362963 0 3.06667\n-0.325 0 2.98125\n-0.237037 0 2.88333\n-0.268946 0.075078 3.12708\n-0.350254 0.097771 3.06667\n-0.313617 0.087529 2.98125\n-0.228728 0.063803 2.88333\n-0.241285 0.141931 3.12708\n-0.314228 0.184834 3.06667\n-0.281352 0.165481 2.98125\n-0.20518 0.120647 2.88333\n-0.19814 0.19814 3.12708\n-0.258037 0.258037 3.06667\n-0.231031 0.231031 2.98125\n-0.168463 0.168463 2.88333\n-0.141931 0.241285 3.12708\n-0.184834 0.314228 3.06667\n-0.165481 0.281352 2.98125\n-0.120647 0.20518 2.88333\n-0.075078 0.268946 3.12708\n-0.097771 0.350254 3.06667\n-0.087529 0.313617 2.98125\n-0.063803 0.228728 2.88333\n0 0.278704 3.12708\n0 0.362963 3.06667\n0 0.325 2.98125\n0 0.237037 2.88333\n0.075078 0.268946 3.12708\n0.097771 0.350254 3.06667\n0.087529 0.313617 2.98125\n0.063803 0.228728 2.88333\n0.141931 0.241285 3.12708\n0.184834 0.314228 3.06667\n0.165481 0.281352 2.98125\n0.120647 0.20518 2.88333\n0.19814 0.19814 3.12708\n0.258037 0.258037 3.06667\n0.231031 0.231031 2.98125\n0.168463 0.168463 2.88333\n0.241285 0.141931 3.12708\n0.314228 0.184834 3.06667\n0.281352 0.165481 2.98125\n0.20518 0.120647 2.88333\n0.268946 0.075078 3.12708\n0.350254 0.097771 3.06667\n0.313617 0.087529 2.98125\n0.228728 0.063803 2.88333\n3 0 1 2\n3 0 2 3\n3 4 0 3\n3 4 3 5\n3 6 4 5\n3 6 5 7\n3 8 6 7\n3 8 7 9\n3 10 8 9\n3 10 9 11\n3 12 10 11\n3 12 11 13\n3 3 2 14\n3 3 14 15\n3 5 3 15\n3 5 15 16\n3 7 5 16\n3 7 16 17\n3 9 7 17\n3 9 17 18\n3 11 9 18\n3 11 18 19\n3 13 11 19\n3 13 19 20\n3 15 14 21\n3 15 21 22\n3 16 15 22\n3 16 22 23\n3 17 16 23\n3 17 23 24\n3 18 17 24\n3 18 24 25\n3 19 18 25\n3 19 25 26\n3 20 19 26\n3 20 26 27\n3 22 21 28\n3 22 28 29\n3 23 22 29\n3 23 29 30\n3 24 23 30\n3 24 30 31\n3 25 24 31\n3 25 31 32\n3 26 25 32\n3 26 32 33\n3 27 26 33\n3 27 33 34\n3 29 28 35\n3 29 35 36\n3 30 29 36\n3 30 36 37\n3 31 30 37\n3 31 37 38\n3 32 31 38\n3 32 38 39\n3 33 32 39\n3 33 39 40\n3 34 33 40\n3 34 40 41\n3 36 35 42\n3 36 42 43\n3 37 36 43\n3 37 43 44\n3 38 37 44\n3 38 44 45\n3 39 38 45\n3 39 45 46\n3 40 39 46\n3 40 46 47\n3 41 40 47\n3 41 47 48\n3 43 42 49\n3 43 49 50\n3 44 43 50\n3 44 50 51\n3 45 44 51\n3 45 51 52\n3 46 45 52\n3 46 52 53\n3 47 46 53\n3 47 53 54\n3 48 47 54\n3 48 54 55\n3 50 49 56\n3 50 56 57\n3 51 50 57\n3 51 57 58\n3 52 51 58\n3 52 58 59\n3 53 52 59\n3 53 59 60\n3 54 53 60\n3 54 60 61\n3 55 54 61\n3 55 61 62\n3 57 56 63\n3 57 63 64\n3 58 57 64\n3 58 64 65\n3 59 58 65\n3 59 65 66\n3 60 59 66\n3 60 66 67\n3 61 60 67\n3 61 67 68\n3 62 61 68\n3 62 68 69\n3 64 63 70\n3 64 70 71\n3 65 64 71\n3 65 71 72\n3 66 65 72\n3 66 72 73\n3 67 66 73\n3 67 73 74\n3 68 67 74\n3 68 74 75\n3 69 68 75\n3 69 75 76\n3 71 70 77\n3 71 77 78\n3 72 71 78\n3 72 78 79\n3 73 72 79\n3 73 79 80\n3 74 73 80\n3 74 80 81\n3 75 74 81\n3 75 81 82\n3 76 75 82\n3 76 82 83\n3 78 77 84\n3 78 84 85\n3 79 78 85\n3 79 85 86\n3 80 79 86\n3 80 86 87\n3 81 80 87\n3 81 87 88\n3 82 81 88\n3 82 88 89\n3 83 82 89\n3 83 89 90\n3 85 84 91\n3 85 91 92\n3 86 85 92\n3 86 92 93\n3 87 86 93\n3 87 93 94\n3 88 87 94\n3 88 94 95\n3 89 88 95\n3 89 95 96\n3 90 89 96\n3 90 96 97\n3 92 91 98\n3 92 98 99\n3 93 92 99\n3 93 99 100\n3 94 93 100\n3 94 100 101\n3 95 94 101\n3 95 101 102\n3 96 95 102\n3 96 102 103\n3 97 96 103\n3 97 103 104\n3 99 98 105\n3 99 105 106\n3 100 99 106\n3 100 106 107\n3 101 100 107\n3 101 107 108\n3 102 101 108\n3 102 108 109\n3 103 102 109\n3 103 109 110\n3 104 103 110\n3 104 110 111\n3 106 105 112\n3 106 112 113\n3 107 106 113\n3 107 113 114\n3 108 107 114\n3 108 114 115\n3 109 108 115\n3 109 115 116\n3 110 109 116\n3 110 116 117\n3 111 110 117\n3 111 117 118\n3 113 112 119\n3 113 119 120\n3 114 113 120\n3 114 120 121\n3 115 114 121\n3 115 121 122\n3 116 115 122\n3 116 122 123\n3 117 116 123\n3 117 123 124\n3 118 117 124\n3 118 124 125\n3 120 119 126\n3 120 126 127\n3 121 120 127\n3 121 127 128\n3 122 121 128\n3 122 128 129\n3 123 122 129\n3 123 129 130\n3 124 123 130\n3 124 130 131\n3 125 124 131\n3 125 131 132\n3 127 126 133\n3 127 133 134\n3 128 127 134\n3 128 134 135\n3 129 128 135\n3 129 135 136\n3 130 129 136\n3 130 136 137\n3 131 130 137\n3 131 137 138\n3 132 131 138\n3 132 138 139\n3 134 133 140\n3 134 140 141\n3 135 134 141\n3 135 141 142\n3 136 135 142\n3 136 142 143\n3 137 136 143\n3 137 143 144\n3 138 137 144\n3 138 144 145\n3 139 138 145\n3 139 145 146\n3 141 140 147\n3 141 147 148\n3 142 141 148\n3 142 148 149\n3 143 142 149\n3 143 149 150\n3 144 143 150\n3 144 150 151\n3 145 144 151\n3 145 151 152\n3 146 145 152\n3 146 152 153\n3 148 147 154\n3 148 154 155\n3 149 148 155\n3 149 155 156\n3 150 149 156\n3 150 156 157\n3 151 150 157\n3 151 157 158\n3 152 151 158\n3 152 158 159\n3 153 152 159\n3 153 159 160\n3 155 154 161\n3 155 161 162\n3 156 155 162\n3 156 162 163\n3 157 156 163\n3 157 163 164\n3 158 157 164\n3 158 164 165\n3 159 158 165\n3 159 165 166\n3 160 159 166\n3 160 166 167\n3 162 161 1\n3 162 1 0\n3 163 162 0\n3 163 0 4\n3 164 163 4\n3 164 4 6\n3 165 164 6\n3 165 6 8\n3 166 165 8\n3 166 8 10\n3 167 166 10\n3 167 10 12\n3 168 12 13\n3 168 13 169\n3 170 168 169\n3 170 169 171\n3 172 170 171\n3 172 171 173\n3 174 172 173\n3 174 173 175\n3 176 174 175\n3 176 175 177\n3 178 176 177\n3 178 177 179\n3 169 13 20\n3 169 20 180\n3 171 169 180\n3 171 180 181\n3 173 171 181\n3 173 181 182\n3 175 173 182\n3 175 182 183\n3 177 175 183\n3 177 183 184\n3 179 177 184\n3 179 184 185\n3 180 20 27\n3 180 27 186\n3 181 180 186\n3 181 186 187\n3 182 181 187\n3 182 187 188\n3 183 182 188\n3 183 188 189\n3 184 183 189\n3 184 189 190\n3 185 184 190\n3 185 190 191\n3 186 27 34\n3 186 34 192\n3 187 186 192\n3 187 192 193\n3 188 187 193\n3 188 193 194\n3 189 188 194\n3 189 194 195\n3 190 189 195\n3 190 195 196\n3 191 190 196\n3 191 196 197\n3 192 34 41\n3 192 41 198\n3 193 192 198\n3 193 198 199\n3 194 193 199\n3 194 199 200\n3 195 194 200\n3 195 200 201\n3 196 195 201\n3 196 201 202\n3 197 196 202\n3 197 202 203\n3 198 41 48\n3 198 48 204\n3 199 198 204\n3 199 204 205\n3 200 199 205\n3 200 205 206\n3 201 200 206\n3 201 206 207\n3 202 201 207\n3 202 207 208\n3 203 202 208\n3 203 208 209\n3 204 48 55\n3 204 55 210\n3 205 204 210\n3 205 210 211\n3 206 205 211\n3 206 211 212\n3 207 206 212\n3 207 212 213\n3 208 207 213\n3 208 213 214\n3 209 208 214\n3 209 214 215\n3 210 55 62\n3 210 62 216\n3 211 210 216\n3 211 216 217\n3 212 211 217\n3 212 217 218\n3 213 212 218\n3 213 218 219\n3 214 213 219\n3 214 219 220\n3 215 214 220\n3 215 220 221\n3 216 62 69\n3 216 69 222\n3 217 216 222\n3 217 222 223\n3 218 217 223\n3 218 223 224\n3 219 218 224\n3 219 224 225\n3 220 219 225\n3 220 225 226\n3 221 220 226\n3 221 226 227\n3 222 69 76\n3 222 76 228\n3 223 222 228\n3 223 228 229\n3 224 223 229\n3 224 229 230\n3 225 224 230\n3 225 230 231\n3 226 225 231\n3 226 231 232\n3 227 226 232\n3 227 232 233\n3 228 76 83\n3 228 83 234\n3 229 228 234\n3 229 234 235\n3 230 229 235\n3 230 235 236\n3 231 230 236\n3 231 236 237\n3 232 231 237\n3 232 237 238\n3 233 232 238\n3 233 238 239\n3 234 83 90\n3 234 90 240\n3 235 234 240\n3 235 240 241\n3 236 235 241\n3 236 241 242\n3 237 236 242\n3 237 242 243\n3 238 237 243\n3 238 243 244\n3 239 238 244\n3 239 244 245\n3 240 90 97\n3 240 97 246\n3 241 240 246\n3 241 246 247\n3 242 241 247\n3 242 247 248\n3 243 242 248\n3 243 248 249\n3 244 243 249\n3 244 249 250\n3 245 244 250\n3 245 250 251\n3 246 97 104\n3 246 104 252\n3 247 246 252\n3 247 252 253\n3 248 247 253\n3 248 253 254\n3 249 248 254\n3 249 254 255\n3 250 249 255\n3 250 255 256\n3 251 250 256\n3 251 256 257\n3 252 104 111\n3 252 111 258\n3 253 252 258\n3 253 258 259\n3 254 253 259\n3 254 259 260\n3 255 254 260\n3 255 260 261\n3 256 255 261\n3 256 261 262\n3 257 256 262\n3 257 262 263\n3 258 111 118\n3 258 118 264\n3 259 258 264\n3 259 264 265\n3 260 259 265\n3 260 265 266\n3 261 260 266\n3 261 266 267\n3 262 261 267\n3 262 267 268\n3 263 262 268\n3 263 268 269\n3 264 118 125\n3 264 125 270\n3 265 264 270\n3 265 270 271\n3 266 265 271\n3 266 271 272\n3 267 266 272\n3 267 272 273\n3 268 267 273\n3 268 273 274\n3 269 268 274\n3 269 274 275\n3 270 125 132\n3 270 132 276\n3 271 270 276\n3 271 276 277\n3 272 271 277\n3 272 277 278\n3 273 272 278\n3 273 278 279\n3 274 273 279\n3 274 279 280\n3 275 274 280\n3 275 280 281\n3 276 132 139\n3 276 139 282\n3 277 276 282\n3 277 282 283\n3 278 277 283\n3 278 283 284\n3 279 278 284\n3 279 284 285\n3 280 279 285\n3 280 285 286\n3 281 280 286\n3 281 286 287\n3 282 139 146\n3 282 146 288\n3 283 282 288\n3 283 288 289\n3 284 283 289\n3 284 289 290\n3 285 284 290\n3 285 290 291\n3 286 285 291\n3 286 291 292\n3 287 286 292\n3 287 292 293\n3 288 146 153\n3 288 153 294\n3 289 288 294\n3 289 294 295\n3 290 289 295\n3 290 295 296\n3 291 290 296\n3 291 296 297\n3 292 291 297\n3 292 297 298\n3 293 292 298\n3 293 298 299\n3 294 153 160\n3 294 160 300\n3 295 294 300\n3 295 300 301\n3 296 295 301\n3 296 301 302\n3 297 296 302\n3 297 302 303\n3 298 297 303\n3 298 303 304\n3 299 298 304\n3 299 304 305\n3 300 160 167\n3 300 167 306\n3 301 300 306\n3 301 306 307\n3 302 301 307\n3 302 307 308\n3 303 302 308\n3 303 308 309\n3 304 303 309\n3 304 309 310\n3 305 304 310\n3 305 310 311\n3 306 167 12\n3 306 12 168\n3 307 306 168\n3 307 168 170\n3 308 307 170\n3 308 170 172\n3 309 308 172\n3 309 172 174\n3 310 309 174\n3 310 174 176\n3 311 310 176\n3 311 176 178\n3 312 178 179\n3 312 179 313\n3 314 312 313\n3 314 313 315\n3 316 314 315\n3 316 315 317\n3 318 316 317\n3 318 317 319\n3 320 318 319\n3 320 319 321\n3 322 320 321\n3 322 321 323\n3 313 179 185\n3 313 185 324\n3 315 313 324\n3 315 324 325\n3 317 315 325\n3 317 325 326\n3 319 317 326\n3 319 326 327\n3 321 319 327\n3 321 327 328\n3 323 321 328\n3 323 328 329\n3 324 185 191\n3 324 191 330\n3 325 324 330\n3 325 330 331\n3 326 325 331\n3 326 331 332\n3 327 326 332\n3 327 332 333\n3 328 327 333\n3 328 333 334\n3 329 328 334\n3 329 334 335\n3 330 191 197\n3 330 197 336\n3 331 330 336\n3 331 336 337\n3 332 331 337\n3 332 337 338\n3 333 332 338\n3 333 338 339\n3 334 333 339\n3 334 339 340\n3 335 334 340\n3 335 340 341\n3 336 197 203\n3 336 203 342\n3 337 336 342\n3 337 342 343\n3 338 337 343\n3 338 343 344\n3 339 338 344\n3 339 344 345\n3 340 339 345\n3 340 345 346\n3 341 340 346\n3 341 346 347\n3 342 203 209\n3 342 209 348\n3 343 342 348\n3 343 348 349\n3 344 343 349\n3 344 349 350\n3 345 344 350\n3 345 350 351\n3 346 345 351\n3 346 351 352\n3 347 346 352\n3 347 352 353\n3 348 209 215\n3 348 215 354\n3 349 348 354\n3 349 354 355\n3 350 349 355\n3 350 355 356\n3 351 350 356\n3 351 356 357\n3 352 351 357\n3 352 357 358\n3 353 352 358\n3 353 358 359\n3 354 215 221\n3 354 221 360\n3 355 354 360\n3 355 360 361\n3 356 355 361\n3 356 361 362\n3 357 356 362\n3 357 362 363\n3 358 357 363\n3 358 363 364\n3 359 358 364\n3 359 364 365\n3 360 221 227\n3 360 227 366\n3 361 360 366\n3 361 366 367\n3 362 361 367\n3 362 367 368\n3 363 362 368\n3 363 368 369\n3 364 363 369\n3 364 369 370\n3 365 364 370\n3 365 370 371\n3 366 227 233\n3 366 233 372\n3 367 366 372\n3 367 372 373\n3 368 367 373\n3 368 373 374\n3 369 368 374\n3 369 374 375\n3 370 369 375\n3 370 375 376\n3 371 370 376\n3 371 376 377\n3 372 233 239\n3 372 239 378\n3 373 372 378\n3 373 378 379\n3 374 373 379\n3 374 379 380\n3 375 374 380\n3 375 380 381\n3 376 375 381\n3 376 381 382\n3 377 376 382\n3 377 382 383\n3 378 239 245\n3 378 245 384\n3 379 378 384\n3 379 384 385\n3 380 379 385\n3 380 385 386\n3 381 380 386\n3 381 386 387\n3 382 381 387\n3 382 387 388\n3 383 382 388\n3 383 388 389\n3 384 245 251\n3 384 251 390\n3 385 384 390\n3 385 390 391\n3 386 385 391\n3 386 391 392\n3 387 386 392\n3 387 392 393\n3 388 387 393\n3 388 393 394\n3 389 388 394\n3 389 394 395\n3 390 251 257\n3 390 257 396\n3 391 390 396\n3 391 396 397\n3 392 391 397\n3 392 397 398\n3 393 392 398\n3 393 398 399\n3 394 393 399\n3 394 399 400\n3 395 394 400\n3 395 400 401\n3 396 257 263\n3 396 263 402\n3 397 396 402\n3 397 402 403\n3 398 397 403\n3 398 403 404\n3 399 398 404\n3 399 404 405\n3 400 399 405\n3 400 405 406\n3 401 400 406\n3 401 406 407\n3 402 263 269\n3 402 269 408\n3 403 402 408\n3 403 408 409\n3 404 403 409\n3 404 409 410\n3 405 404 410\n3 405 410 411\n3 406 405 411\n3 406 411 412\n3 407 406 412\n3 407 412 413\n3 408 269 275\n3 408 275 414\n3 409 408 414\n3 409 414 415\n3 410 409 415\n3 410 415 416\n3 411 410 416\n3 411 416 417\n3 412 411 417\n3 412 417 418\n3 413 412 418\n3 413 418 419\n3 414 275 281\n3 414 281 420\n3 415 414 420\n3 415 420 421\n3 416 415 421\n3 416 421 422\n3 417 416 422\n3 417 422 423\n3 418 417 423\n3 418 423 424\n3 419 418 424\n3 419 424 425\n3 420 281 287\n3 420 287 426\n3 421 420 426\n3 421 426 427\n3 422 421 427\n3 422 427 428\n3 423 422 428\n3 423 428 429\n3 424 423 429\n3 424 429 430\n3 425 424 430\n3 425 430 431\n3 426 287 293\n3 426 293 432\n3 427 426 432\n3 427 432 433\n3 428 427 433\n3 428 433 434\n3 429 428 434\n3 429 434 435\n3 430 429 435\n3 430 435 436\n3 431 430 436\n3 431 436 437\n3 432 293 299\n3 432 299 438\n3 433 432 438\n3 433 438 439\n3 434 433 439\n3 434 439 440\n3 435 434 440\n3 435 440 441\n3 436 435 441\n3 436 441 442\n3 437 436 442\n3 437 442 443\n3 438 299 305\n3 438 305 444\n3 439 438 444\n3 439 444 445\n3 440 439 445\n3 440 445 446\n3 441 440 446\n3 441 446 447\n3 442 441 447\n3 442 447 448\n3 443 442 448\n3 443 448 449\n3 444 305 311\n3 444 311 450\n3 445 444 450\n3 445 450 451\n3 446 445 451\n3 446 451 452\n3 447 446 452\n3 447 452 453\n3 448 447 453\n3 448 453 454\n3 449 448 454\n3 449 454 455\n3 450 311 178\n3 450 178 312\n3 451 450 312\n3 451 312 314\n3 452 451 314\n3 452 314 316\n3 453 452 316\n3 453 316 318\n3 454 453 318\n3 454 318 320\n3 455 454 320\n3 455 320 322\n3 456 457 458\n3 459 456 458\n3 459 458 460\n3 461 459 460\n3 461 460 462\n3 463 461 462\n3 463 462 464\n3 465 463 464\n3 465 464 466\n3 322 465 466\n3 322 466 455\n3 458 457 467\n3 460 458 467\n3 460 467 468\n3 462 460 468\n3 462 468 469\n3 464 462 469\n3 464 469 470\n3 466 464 470\n3 466 470 471\n3 455 466 471\n3 455 471 449\n3 467 457 472\n3 468 467 472\n3 468 472 473\n3 469 468 473\n3 469 473 474\n3 470 469 474\n3 470 474 475\n3 471 470 475\n3 471 475 476\n3 449 471 476\n3 449 476 443\n3 472 457 477\n3 473 472 477\n3 473 477 478\n3 474 473 478\n3 474 478 479\n3 475 474 479\n3 475 479 480\n3 476 475 480\n3 476 480 481\n3 443 476 481\n3 443 481 437\n3 477 457 482\n3 478 477 482\n3 478 482 483\n3 479 478 483\n3 479 483 484\n3 480 479 484\n3 480 484 485\n3 481 480 485\n3 481 485 486\n3 437 481 486\n3 437 486 431\n3 482 457 487\n3 483 482 487\n3 483 487 488\n3 484 483 488\n3 484 488 489\n3 485 484 489\n3 485 489 490\n3 486 485 490\n3 486 490 491\n3 431 486 491\n3 431 491 425\n3 487 457 492\n3 488 487 492\n3 488 492 493\n3 489 488 493\n3 489 493 494\n3 490 489 494\n3 490 494 495\n3 491 490 495\n3 491 495 496\n3 425 491 496\n3 425 496 419\n3 492 457 497\n3 493 492 497\n3 493 497 498\n3 494 493 498\n3 494 498 499\n3 495 494 499\n3 495 499 500\n3 496 495 500\n3 496 500 501\n3 419 496 501\n3 419 501 413\n3 497 457 502\n3 498 497 502\n3 498 502 503\n3 499 498 503\n3 499 503 504\n3 500 499 504\n3 500 504 505\n3 501 500 505\n3 501 505 506\n3 413 501 506\n3 413 506 407\n3 502 457 507\n3 503 502 507\n3 503 507 508\n3 504 503 508\n3 504 508 509\n3 505 504 509\n3 505 509 510\n3 506 505 510\n3 506 510 511\n3 407 506 511\n3 407 511 401\n3 507 457 512\n3 508 507 512\n3 508 512 513\n3 509 508 513\n3 509 513 514\n3 510 509 514\n3 510 514 515\n3 511 510 515\n3 511 515 516\n3 401 511 516\n3 401 516 395\n3 512 457 517\n3 513 512 517\n3 513 517 518\n3 514 513 518\n3 514 518 519\n3 515 514 519\n3 515 519 520\n3 516 515 520\n3 516 520 521\n3 395 516 521\n3 395 521 389\n3 517 457 522\n3 518 517 522\n3 518 522 523\n3 519 518 523\n3 519 523 524\n3 520 519 524\n3 520 524 525\n3 521 520 525\n3 521 525 526\n3 389 521 526\n3 389 526 383\n3 522 457 527\n3 523 522 527\n3 523 527 528\n3 524 523 528\n3 524 528 529\n3 525 524 529\n3 525 529 530\n3 526 525 530\n3 526 530 531\n3 383 526 531\n3 383 531 377\n3 527 457 532\n3 528 527 532\n3 528 532 533\n3 529 528 533\n3 529 533 534\n3 530 529 534\n3 530 534 535\n3 531 530 535\n3 531 535 536\n3 377 531 536\n3 377 536 371\n3 532 457 537\n3 533 532 537\n3 533 537 538\n3 534 533 538\n3 534 538 539\n3 535 534 539\n3 535 539 540\n3 536 535 540\n3 536 540 541\n3 371 536 541\n3 371 541 365\n3 537 457 542\n3 538 537 542\n3 538 542 543\n3 539 538 543\n3 539 543 544\n3 540 539 544\n3 540 544 545\n3 541 540 545\n3 541 545 546\n3 365 541 546\n3 365 546 359\n3 542 457 547\n3 543 542 547\n3 543 547 548\n3 544 543 548\n3 544 548 549\n3 545 544 549\n3 545 549 550\n3 546 545 550\n3 546 550 551\n3 359 546 551\n3 359 551 353\n3 547 457 552\n3 548 547 552\n3 548 552 553\n3 549 548 553\n3 549 553 554\n3 550 549 554\n3 550 554 555\n3 551 550 555\n3 551 555 556\n3 353 551 556\n3 353 556 347\n3 552 457 557\n3 553 552 557\n3 553 557 558\n3 554 553 558\n3 554 558 559\n3 555 554 559\n3 555 559 560\n3 556 555 560\n3 556 560 561\n3 347 556 561\n3 347 561 341\n3 557 457 562\n3 558 557 562\n3 558 562 563\n3 559 558 563\n3 559 563 564\n3 560 559 564\n3 560 564 565\n3 561 560 565\n3 561 565 566\n3 341 561 566\n3 341 566 335\n3 562 457 567\n3 563 562 567\n3 563 567 568\n3 564 563 568\n3 564 568 569\n3 565 564 569\n3 565 569 570\n3 566 565 570\n3 566 570 571\n3 335 566 571\n3 335 571 329\n3 567 457 572\n3 568 567 572\n3 568 572 573\n3 569 568 573\n3 569 573 574\n3 570 569 574\n3 570 574 575\n3 571 570 575\n3 571 575 576\n3 329 571 576\n3 329 576 323\n3 572 457 456\n3 573 572 456\n3 573 456 459\n3 574 573 459\n3 574 459 461\n3 575 574 461\n3 575 461 463\n3 576 575 463\n3 576 463 465\n3 323 576 465\n3 323 465 322\n3 577 578 579\n3 577 579 580\n3 580 579 581\n3 580 581 582\n3 582 581 583\n3 582 583 584\n3 584 583 585\n3 584 585 586\n3 586 585 587\n3 586 587 588\n3 588 587 589\n3 588 589 590\n3 590 589 591\n3 590 591 592\n3 592 591 593\n3 592 593 594\n3 594 593 595\n3 594 595 596\n3 596 595 597\n3 596 597 598\n3 598 597 599\n3 598 599 600\n3 600 599 601\n3 600 601 602\n3 602 601 603\n3 602 603 604\n3 604 603 605\n3 604 605 606\n3 606 605 607\n3 606 607 608\n3 608 607 609\n3 608 609 610\n3 610 609 611\n3 610 611 612\n3 612 611 613\n3 612 613 614\n3 614 613 615\n3 614 615 616\n3 616 615 617\n3 616 617 618\n3 618 617 619\n3 618 619 620\n3 620 619 621\n3 620 621 622\n3 622 621 623\n3 622 623 624\n3 624 623 578\n3 624 578 577\n3 625 577 580\n3 625 580 626\n3 627 625 626\n3 627 626 628\n3 629 627 628\n3 629 628 630\n3 631 629 630\n3 631 630 632\n3 633 631 632\n3 633 632 634\n3 635 633 634\n3 635 634 636\n3 626 580 582\n3 626 582 637\n3 628 626 637\n3 628 637 638\n3 630 628 638\n3 630 638 639\n3 632 630 639\n3 632 639 640\n3 634 632 640\n3 634 640 641\n3 636 634 641\n3 636 641 642\n3 637 582 584\n3 637 584 643\n3 638 637 643\n3 638 643 644\n3 639 638 644\n3 639 644 645\n3 640 639 645\n3 640 645 646\n3 641 640 646\n3 641 646 647\n3 642 641 647\n3 642 647 648\n3 643 584 586\n3 643 586 649\n3 644 643 649\n3 644 649 650\n3 645 644 650\n3 645 650 651\n3 646 645 651\n3 646 651 652\n3 647 646 652\n3 647 652 653\n3 648 647 653\n3 648 653 654\n3 649 586 588\n3 649 588 655\n3 650 649 655\n3 650 655 656\n3 651 650 656\n3 651 656 657\n3 652 651 657\n3 652 657 658\n3 653 652 658\n3 653 658 659\n3 654 653 659\n3 654 659 660\n3 655 588 590\n3 655 590 661\n3 656 655 661\n3 656 661 662\n3 657 656 662\n3 657 662 663\n3 658 657 663\n3 658 663 664\n3 659 658 664\n3 659 664 665\n3 660 659 665\n3 660 665 666\n3 661 590 592\n3 661 592 667\n3 662 661 667\n3 662 667 668\n3 663 662 668\n3 663 668 669\n3 664 663 669\n3 664 669 670\n3 665 664 670\n3 665 670 671\n3 666 665 671\n3 666 671 672\n3 667 592 594\n3 667 594 673\n3 668 667 673\n3 668 673 674\n3 669 668 674\n3 669 674 675\n3 670 669 675\n3 670 675 676\n3 671 670 676\n3 671 676 677\n3 672 671 677\n3 672 677 678\n3 673 594 596\n3 673 596 679\n3 674 673 679\n3 674 679 680\n3 675 674 680\n3 675 680 681\n3 676 675 681\n3 676 681 682\n3 677 676 682\n3 677 682 683\n3 678 677 683\n3 678 683 684\n3 679 596 598\n3 679 598 685\n3 680 679 685\n3 680 685 686\n3 681 680 686\n3 681 686 687\n3 682 681 687\n3 682 687 688\n3 683 682 688\n3 683 688 689\n3 684 683 689\n3 684 689 690\n3 685 598 600\n3 685 600 691\n3 686 685 691\n3 686 691 692\n3 687 686 692\n3 687 692 693\n3 688 687 693\n3 688 693 694\n3 689 688 694\n3 689 694 695\n3 690 689 695\n3 690 695 696\n3 691 600 602\n3 691 602 697\n3 692 691 697\n3 692 697 698\n3 693 692 698\n3 693 698 699\n3 694 693 699\n3 694 699 700\n3 695 694 700\n3 695 700 701\n3 696 695 701\n3 696 701 702\n3 697 602 604\n3 697 604 703\n3 698 697 703\n3 698 703 704\n3 699 698 704\n3 699 704 705\n3 700 699 705\n3 700 705 706\n3 701 700 706\n3 701 706 707\n3 702 701 707\n3 702 707 708\n3 703 604 606\n3 703 606 709\n3 704 703 709\n3 704 709 710\n3 705 704 710\n3 705 710 711\n3 706 705 711\n3 706 711 712\n3 707 706 712\n3 707 712 713\n3 708 707 713\n3 708 713 714\n3 709 606 608\n3 709 608 715\n3 710 709 715\n3 710 715 716\n3 711 710 716\n3 711 716 717\n3 712 711 717\n3 712 717 718\n3 713 712 718\n3 713 718 719\n3 714 713 719\n3 714 719 720\n3 715 608 610\n3 715 610 721\n3 716 715 721\n3 716 721 722\n3 717 716 722\n3 717 722 723\n3 718 717 723\n3 718 723 724\n3 719 718 724\n3 719 724 725\n3 720 719 725\n3 720 725 726\n3 721 610 612\n3 721 612 727\n3 722 721 727\n3 722 727 728\n3 723 722 728\n3 723 728 729\n3 724 723 729\n3 724 729 730\n3 725 724 730\n3 725 730 731\n3 726 725 731\n3 726 731 732\n3 727 612 614\n3 727 614 733\n3 728 727 733\n3 728 733 734\n3 729 728 734\n3 729 734 735\n3 730 729 735\n3 730 735 736\n3 731 730 736\n3 731 736 737\n3 732 731 737\n3 732 737 738\n3 733 614 616\n3 733 616 739\n3 734 733 739\n3 734 739 740\n3 735 734 740\n3 735 740 741\n3 736 735 741\n3 736 741 742\n3 737 736 742\n3 737 742 743\n3 738 737 743\n3 738 743 744\n3 739 616 618\n3 739 618 745\n3 740 739 745\n3 740 745 746\n3 741 740 746\n3 741 746 747\n3 742 741 747\n3 742 747 748\n3 743 742 748\n3 743 748 749\n3 744 743 749\n3 744 749 750\n3 745 618 620\n3 745 620 751\n3 746 745 751\n3 746 751 752\n3 747 746 752\n3 747 752 753\n3 748 747 753\n3 748 753 754\n3 749 748 754\n3 749 754 755\n3 750 749 755\n3 750 755 756\n3 751 620 622\n3 751 622 757\n3 752 751 757\n3 752 757 758\n3 753 752 758\n3 753 758 759\n3 754 753 759\n3 754 759 760\n3 755 754 760\n3 755 760 761\n3 756 755 761\n3 756 761 762\n3 757 622 624\n3 757 624 763\n3 758 757 763\n3 758 763 764\n3 759 758 764\n3 759 764 765\n3 760 759 765\n3 760 765 766\n3 761 760 766\n3 761 766 767\n3 762 761 767\n3 762 767 768\n3 763 624 577\n3 763 577 625\n3 764 763 625\n3 764 625 627\n3 765 764 627\n3 765 627 629\n3 766 765 629\n3 766 629 631\n3 767 766 631\n3 767 631 633\n3 768 767 633\n3 768 633 635\n3 769 770 771\n3 769 771 772\n3 773 769 772\n3 773 772 774\n3 775 773 774\n3 775 774 776\n3 777 775 776\n3 777 776 778\n3 779 777 778\n3 779 778 780\n3 781 779 780\n3 781 780 782\n3 772 771 783\n3 772 783 784\n3 774 772 784\n3 774 784 785\n3 776 774 785\n3 776 785 786\n3 778 776 786\n3 778 786 787\n3 780 778 787\n3 780 787 788\n3 782 780 788\n3 782 788 789\n3 784 783 790\n3 784 790 791\n3 785 784 791\n3 785 791 792\n3 786 785 792\n3 786 792 793\n3 787 786 793\n3 787 793 794\n3 788 787 794\n3 788 794 795\n3 789 788 795\n3 789 795 796\n3 791 790 797\n3 791 797 798\n3 792 791 798\n3 792 798 799\n3 793 792 799\n3 793 799 800\n3 794 793 800\n3 794 800 801\n3 795 794 801\n3 795 801 802\n3 796 795 802\n3 796 802 803\n3 798 797 804\n3 798 804 805\n3 799 798 805\n3 799 805 806\n3 800 799 806\n3 800 806 807\n3 801 800 807\n3 801 807 808\n3 802 801 808\n3 802 808 809\n3 803 802 809\n3 803 809 810\n3 805 804 811\n3 805 811 812\n3 806 805 812\n3 806 812 813\n3 807 806 813\n3 807 813 814\n3 808 807 814\n3 808 814 815\n3 809 808 815\n3 809 815 816\n3 810 809 816\n3 810 816 817\n3 812 811 818\n3 812 818 819\n3 813 812 819\n3 813 819 820\n3 814 813 820\n3 814 820 821\n3 815 814 821\n3 815 821 822\n3 816 815 822\n3 816 822 823\n3 817 816 823\n3 817 823 824\n3 819 818 825\n3 819 825 826\n3 820 819 826\n3 820 826 827\n3 821 820 827\n3 821 827 828\n3 822 821 828\n3 822 828 829\n3 823 822 829\n3 823 829 830\n3 824 823 830\n3 824 830 831\n3 826 825 832\n3 826 832 833\n3 827 826 833\n3 827 833 834\n3 828 827 834\n3 828 834 835\n3 829 828 835\n3 829 835 836\n3 830 829 836\n3 830 836 837\n3 831 830 837\n3 831 837 838\n3 833 832 839\n3 833 839 840\n3 834 833 840\n3 834 840 841\n3 835 834 841\n3 835 841 842\n3 836 835 842\n3 836 842 843\n3 837 836 843\n3 837 843 844\n3 838 837 844\n3 838 844 845\n3 840 839 846\n3 840 846 847\n3 841 840 847\n3 841 847 848\n3 842 841 848\n3 842 848 849\n3 843 842 849\n3 843 849 850\n3 844 843 850\n3 844 850 851\n3 845 844 851\n3 845 851 852\n3 847 846 770\n3 847 770 769\n3 848 847 769\n3 848 769 773\n3 849 848 773\n3 849 773 775\n3 850 849 775\n3 850 775 777\n3 851 850 777\n3 851 777 779\n3 852 851 779\n3 852 779 781\n3 853 781 782\n3 853 782 854\n3 855 853 854\n3 855 854 856\n3 857 855 856\n3 857 856 858\n3 859 857 858\n3 859 858 860\n3 861 859 860\n3 861 860 862\n3 245 861 862\n3 245 862 863\n3 854 782 789\n3 854 789 864\n3 856 854 864\n3 856 864 865\n3 858 856 865\n3 858 865 866\n3 860 858 866\n3 860 866 867\n3 862 860 867\n3 862 867 868\n3 863 862 868\n3 863 868 869\n3 864 789 796\n3 864 796 870\n3 865 864 870\n3 865 870 871\n3 866 865 871\n3 866 871 872\n3 867 866 872\n3 867 872 873\n3 868 867 873\n3 868 873 874\n3 869 868 874\n3 869 874 875\n3 870 796 803\n3 870 803 876\n3 871 870 876\n3 871 876 877\n3 872 871 877\n3 872 877 878\n3 873 872 878\n3 873 878 879\n3 874 873 879\n3 874 879 880\n3 875 874 880\n3 875 880 881\n3 876 803 810\n3 876 810 882\n3 877 876 882\n3 877 882 883\n3 878 877 883\n3 878 883 884\n3 879 878 884\n3 879 884 885\n3 880 879 885\n3 880 885 886\n3 881 880 886\n3 881 886 887\n3 882 810 817\n3 882 817 888\n3 883 882 888\n3 883 888 889\n3 884 883 889\n3 884 889 890\n3 885 884 890\n3 885 890 891\n3 886 885 891\n3 886 891 892\n3 887 886 892\n3 887 892 893\n3 888 817 824\n3 888 824 894\n3 889 888 894\n3 889 894 895\n3 890 889 895\n3 890 895 896\n3 891 890 896\n3 891 896 897\n3 892 891 897\n3 892 897 898\n3 893 892 898\n3 893 898 899\n3 894 824 831\n3 894 831 900\n3 895 894 900\n3 895 900 901\n3 896 895 901\n3 896 901 902\n3 897 896 902\n3 897 902 903\n3 898 897 903\n3 898 903 904\n3 899 898 904\n3 899 904 905\n3 900 831 838\n3 900 838 906\n3 901 900 906\n3 901 906 907\n3 902 901 907\n3 902 907 908\n3 903 902 908\n3 903 908 909\n3 904 903 909\n3 904 909 910\n3 905 904 910\n3 905 910 911\n3 906 838 845\n3 906 845 912\n3 907 906 912\n3 907 912 913\n3 908 907 913\n3 908 913 914\n3 909 908 914\n3 909 914 915\n3 910 909 915\n3 910 915 916\n3 911 910 916\n3 911 916 917\n3 912 845 852\n3 912 852 918\n3 913 912 918\n3 913 918 919\n3 914 913 919\n3 914 919 920\n3 915 914 920\n3 915 920 921\n3 916 915 921\n3 916 921 922\n3 917 916 922\n3 917 922 923\n3 918 852 781\n3 918 781 853\n3 919 918 853\n3 919 853 855\n3 920 919 855\n3 920 855 857\n3 921 920 857\n3 921 857 859\n3 922 921 859\n3 922 859 861\n3 923 922 861\n3 923 861 245\n3 924 925 926\n3 924 926 927\n3 928 924 927\n3 928 927 929\n3 930 928 929\n3 930 929 931\n3 932 930 931\n3 932 931 933\n3 934 932 933\n3 934 933 935\n3 936 934 935\n3 936 935 937\n3 927 926 938\n3 927 938 939\n3 929 927 939\n3 929 939 940\n3 931 929 940\n3 931 940 941\n3 933 931 941\n3 933 941 942\n3 935 933 942\n3 935 942 943\n3 937 935 943\n3 937 943 944\n3 939 938 945\n3 939 945 946\n3 940 939 946\n3 940 946 947\n3 941 940 947\n3 941 947 948\n3 942 941 948\n3 942 948 949\n3 943 942 949\n3 943 949 950\n3 944 943 950\n3 944 950 951\n3 946 945 952\n3 946 952 953\n3 947 946 953\n3 947 953 954\n3 948 947 954\n3 948 954 955\n3 949 948 955\n3 949 955 956\n3 950 949 956\n3 950 956 957\n3 951 950 957\n3 951 957 958\n3 953 952 959\n3 953 959 960\n3 954 953 960\n3 954 960 961\n3 955 954 961\n3 955 961 962\n3 956 955 962\n3 956 962 963\n3 957 956 963\n3 957 963 964\n3 958 957 964\n3 958 964 965\n3 960 959 966\n3 960 966 967\n3 961 960 967\n3 961 967 968\n3 962 961 968\n3 962 968 969\n3 963 962 969\n3 963 969 970\n3 964 963 970\n3 964 970 971\n3 965 964 971\n3 965 971 972\n3 967 966 973\n3 967 973 974\n3 968 967 974\n3 968 974 975\n3 969 968 975\n3 969 975 976\n3 970 969 976\n3 970 976 977\n3 971 970 977\n3 971 977 978\n3 972 971 978\n3 972 978 979\n3 974 973 980\n3 974 980 981\n3 975 974 981\n3 975 981 982\n3 976 975 982\n3 976 982 983\n3 977 976 983\n3 977 983 984\n3 978 977 984\n3 978 984 985\n3 979 978 985\n3 979 985 986\n3 981 980 987\n3 981 987 988\n3 982 981 988\n3 982 988 989\n3 983 982 989\n3 983 989 990\n3 984 983 990\n3 984 990 991\n3 985 984 991\n3 985 991 992\n3 986 985 992\n3 986 992 993\n3 988 987 994\n3 988 994 995\n3 989 988 995\n3 989 995 996\n3 990 989 996\n3 990 996 997\n3 991 990 997\n3 991 997 998\n3 992 991 998\n3 992 998 999\n3 993 992 999\n3 993 999 1000\n3 995 994 1001\n3 995 1001 1002\n3 996 995 1002\n3 996 1002 1003\n3 997 996 1003\n3 997 1003 1004\n3 998 997 1004\n3 998 1004 1005\n3 999 998 1005\n3 999 1005 1006\n3 1000 999 1006\n3 1000 1006 1007\n3 1002 1001 925\n3 1002 925 924\n3 1003 1002 924\n3 1003 924 928\n3 1004 1003 928\n3 1004 928 930\n3 1005 1004 930\n3 1005 930 932\n3 1006 1005 932\n3 1006 932 934\n3 1007 1006 934\n3 1007 934 936\n3 1008 936 937\n3 1008 937 1009\n3 1010 1008 1009\n3 1010 1009 1011\n3 1012 1010 1011\n3 1012 1011 1013\n3 1014 1012 1013\n3 1014 1013 1015\n3 1016 1014 1015\n3 1016 1015 1017\n3 1018 1016 1017\n3 1018 1017 1019\n3 1009 937 944\n3 1009 944 1020\n3 1011 1009 1020\n3 1011 1020 1021\n3 1013 1011 1021\n3 1013 1021 1022\n3 1015 1013 1022\n3 1015 1022 1023\n3 1017 1015 1023\n3 1017 1023 1024\n3 1019 1017 1024\n3 1019 1024 1025\n3 1020 944 951\n3 1020 951 1026\n3 1021 1020 1026\n3 1021 1026 1027\n3 1022 1021 1027\n3 1022 1027 1028\n3 1023 1022 1028\n3 1023 1028 1029\n3 1024 1023 1029\n3 1024 1029 1030\n3 1025 1024 1030\n3 1025 1030 1031\n3 1026 951 958\n3 1026 958 1032\n3 1027 1026 1032\n3 1027 1032 1033\n3 1028 1027 1033\n3 1028 1033 1034\n3 1029 1028 1034\n3 1029 1034 1035\n3 1030 1029 1035\n3 1030 1035 1036\n3 1031 1030 1036\n3 1031 1036 1037\n3 1032 958 965\n3 1032 965 1038\n3 1033 1032 1038\n3 1033 1038 1039\n3 1034 1033 1039\n3 1034 1039 1040\n3 1035 1034 1040\n3 1035 1040 1041\n3 1036 1035 1041\n3 1036 1041 1042\n3 1037 1036 1042\n3 1037 1042 1043\n3 1038 965 972\n3 1038 972 1044\n3 1039 1038 1044\n3 1039 1044 1045\n3 1040 1039 1045\n3 1040 1045 1046\n3 1041 1040 1046\n3 1041 1046 1047\n3 1042 1041 1047\n3 1042 1047 1048\n3 1043 1042 1048\n3 1043 1048 1049\n3 1044 972 979\n3 1044 979 1050\n3 1045 1044 1050\n3 1045 1050 1051\n3 1046 1045 1051\n3 1046 1051 1052\n3 1047 1046 1052\n3 1047 1052 1053\n3 1048 1047 1053\n3 1048 1053 1054\n3 1049 1048 1054\n3 1049 1054 1055\n3 1050 979 986\n3 1050 986 1056\n3 1051 1050 1056\n3 1051 1056 1057\n3 1052 1051 1057\n3 1052 1057 1058\n3 1053 1052 1058\n3 1053 1058 1059\n3 1054 1053 1059\n3 1054 1059 1060\n3 1055 1054 1060\n3 1055 1060 1061\n3 1056 986 993\n3 1056 993 1062\n3 1057 1056 1062\n3 1057 1062 1063\n3 1058 1057 1063\n3 1058 1063 1064\n3 1059 1058 1064\n3 1059 1064 1065\n3 1060 1059 1065\n3 1060 1065 1066\n3 1061 1060 1066\n3 1061 1066 1067\n3 1062 993 1000\n3 1062 1000 1068\n3 1063 1062 1068\n3 1063 1068 1069\n3 1064 1063 1069\n3 1064 1069 1070\n3 1065 1064 1070\n3 1065 1070 1071\n3 1066 1065 1071\n3 1066 1071 1072\n3 1067 1066 1072\n3 1067 1072 1073\n3 1068 1000 1007\n3 1068 1007 1074\n3 1069 1068 1074\n3 1069 1074 1075\n3 1070 1069 1075\n3 1070 1075 1076\n3 1071 1070 1076\n3 1071 1076 1077\n3 1072 1071 1077\n3 1072 1077 1078\n3 1073 1072 1078\n3 1073 1078 1079\n3 1074 1007 936\n3 1074 936 1008\n3 1075 1074 1008\n3 1075 1008 1010\n3 1076 1075 1010\n3 1076 1010 1012\n3 1077 1076 1012\n3 1077 1012 1014\n3 1078 1077 1014\n3 1078 1014 1016\n3 1079 1078 1016\n3 1079 1016 1018\n3 1080 1081 1082\n3 1083 1080 1082\n3 1083 1082 1084\n3 1085 1083 1084\n3 1085 1084 1086\n3 1087 1085 1086\n3 1087 1086 1088\n3 578 1087 1088\n3 578 1088 579\n3 1082 1081 1089\n3 1084 1082 1089\n3 1084 1089 1090\n3 1086 1084 1090\n3 1086 1090 1091\n3 1088 1086 1091\n3 1088 1091 1092\n3 579 1088 1092\n3 579 1092 581\n3 1089 1081 1093\n3 1090 1089 1093\n3 1090 1093 1094\n3 1091 1090 1094\n3 1091 1094 1095\n3 1092 1091 1095\n3 1092 1095 1096\n3 581 1092 1096\n3 581 1096 583\n3 1093 1081 1097\n3 1094 1093 1097\n3 1094 1097 1098\n3 1095 1094 1098\n3 1095 1098 1099\n3 1096 1095 1099\n3 1096 1099 1100\n3 583 1096 1100\n3 583 1100 585\n3 1097 1081 1101\n3 1098 1097 1101\n3 1098 1101 1102\n3 1099 1098 1102\n3 1099 1102 1103\n3 1100 1099 1103\n3 1100 1103 1104\n3 585 1100 1104\n3 585 1104 587\n3 1101 1081 1105\n3 1102 1101 1105\n3 1102 1105 1106\n3 1103 1102 1106\n3 1103 1106 1107\n3 1104 1103 1107\n3 1104 1107 1108\n3 587 1104 1108\n3 587 1108 589\n3 1105 1081 1109\n3 1106 1105 1109\n3 1106 1109 1110\n3 1107 1106 1110\n3 1107 1110 1111\n3 1108 1107 1111\n3 1108 1111 1112\n3 589 1108 1112\n3 589 1112 591\n3 1109 1081 1113\n3 1110 1109 1113\n3 1110 1113 1114\n3 1111 1110 1114\n3 1111 1114 1115\n3 1112 1111 1115\n3 1112 1115 1116\n3 591 1112 1116\n3 591 1116 593\n3 1113 1081 1117\n3 1114 1113 1117\n3 1114 1117 1118\n3 1115 1114 1118\n3 1115 1118 1119\n3 1116 1115 1119\n3 1116 1119 1120\n3 593 1116 1120\n3 593 1120 595\n3 1117 1081 1121\n3 1118 1117 1121\n3 1118 1121 1122\n3 1119 1118 1122\n3 1119 1122 1123\n3 1120 1119 1123\n3 1120 1123 1124\n3 595 1120 1124\n3 595 1124 597\n3 1121 1081 1125\n3 1122 1121 1125\n3 1122 1125 1126\n3 1123 1122 1126\n3 1123 1126 1127\n3 1124 1123 1127\n3 1124 1127 1128\n3 597 1124 1128\n3 597 1128 599\n3 1125 1081 1129\n3 1126 1125 1129\n3 1126 1129 1130\n3 1127 1126 1130\n3 1127 1130 1131\n3 1128 1127 1131\n3 1128 1131 1132\n3 599 1128 1132\n3 599 1132 601\n3 1129 1081 1133\n3 1130 1129 1133\n3 1130 1133 1134\n3 1131 1130 1134\n3 1131 1134 1135\n3 1132 1131 1135\n3 1132 1135 1136\n3 601 1132 1136\n3 601 1136 603\n3 1133 1081 1137\n3 1134 1133 1137\n3 1134 1137 1138\n3 1135 1134 1138\n3 1135 1138 1139\n3 1136 1135 1139\n3 1136 1139 1140\n3 603 1136 1140\n3 603 1140 605\n3 1137 1081 1141\n3 1138 1137 1141\n3 1138 1141 1142\n3 1139 1138 1142\n3 1139 1142 1143\n3 1140 1139 1143\n3 1140 1143 1144\n3 605 1140 1144\n3 605 1144 607\n3 1141 1081 1145\n3 1142 1141 1145\n3 1142 1145 1146\n3 1143 1142 1146\n3 1143 1146 1147\n3 1144 1143 1147\n3 1144 1147 1148\n3 607 1144 1148\n3 607 1148 609\n3 1145 1081 1149\n3 1146 1145 1149\n3 1146 1149 1150\n3 1147 1146 1150\n3 1147 1150 1151\n3 1148 1147 1151\n3 1148 1151 1152\n3 609 1148 1152\n3 609 1152 611\n3 1149 1081 1153\n3 1150 1149 1153\n3 1150 1153 1154\n3 1151 1150 1154\n3 1151 1154 1155\n3 1152 1151 1155\n3 1152 1155 1156\n3 611 1152 1156\n3 611 1156 613\n3 1153 1081 1157\n3 1154 1153 1157\n3 1154 1157 1158\n3 1155 1154 1158\n3 1155 1158 1159\n3 1156 1155 1159\n3 1156 1159 1160\n3 613 1156 1160\n3 613 1160 615\n3 1157 1081 1161\n3 1158 1157 1161\n3 1158 1161 1162\n3 1159 1158 1162\n3 1159 1162 1163\n3 1160 1159 1163\n3 1160 1163 1164\n3 615 1160 1164\n3 615 1164 617\n3 1161 1081 1165\n3 1162 1161 1165\n3 1162 1165 1166\n3 1163 1162 1166\n3 1163 1166 1167\n3 1164 1163 1167\n3 1164 1167 1168\n3 617 1164 1168\n3 617 1168 619\n3 1165 1081 1169\n3 1166 1165 1169\n3 1166 1169 1170\n3 1167 1166 1170\n3 1167 1170 1171\n3 1168 1167 1171\n3 1168 1171 1172\n3 619 1168 1172\n3 619 1172 621\n3 1169 1081 1173\n3 1170 1169 1173\n3 1170 1173 1174\n3 1171 1170 1174\n3 1171 1174 1175\n3 1172 1171 1175\n3 1172 1175 1176\n3 621 1172 1176\n3 621 1176 623\n3 1173 1081 1080\n3 1174 1173 1080\n3 1174 1080 1083\n3 1175 1174 1083\n3 1175 1083 1085\n3 1176 1175 1085\n3 1176 1085 1087\n3 623 1176 1087\n3 623 1087 578\n"
  },
  {
    "path": "doc/katex-header.html",
    "content": "<link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.css\" integrity=\"sha384-zB1R0rpPzHqg7Kpt0Aljp8JPLqbXI3bhnPWROx27a9N0Ll6ZP/+DiW/UqRcLbRjq\" crossorigin=\"anonymous\">\n<script defer src=\"https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.js\" integrity=\"sha384-y23I5Q6l+B6vatafAwxRu/0oK/79VlbSz7Q9aiSZUvyWYIYsd+qj+o24G5ZU2zJz\" crossorigin=\"anonymous\"></script>\n<script defer src=\"https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/contrib/auto-render.min.js\" integrity=\"sha384-kWPLUVMOks5AQFrykwIup5lo0m3iMkkHrD0uJ4H5cjeGihAutqP0yW0J6dpFiVkI\" crossorigin=\"anonymous\"></script>\n<script>\n    document.addEventListener(\"DOMContentLoaded\", function() {\n        renderMathInElement(document.body, {\n            delimiters: [\n                { left: \"$$\", right: \"$$\", display: true },\n                { left: \"\\\\(\", right: \"\\\\)\", display: false },\n                { left: \"$\", right: \"$\", display: false },\n                { left: \"\\\\[\", right: \"\\\\]\", display: true }\n            ]\n        });\n    });\n</script>\n"
  },
  {
    "path": "examples/sphere/Cargo.toml",
    "content": "[package]\nname = \"example-sphere\"\nversion = \"0.0.0\"\nedition = \"2021\"\nauthors = [\"Sean Olson <olson.sean.k@gmail.com>\"]\nlicense = \"MIT\"\npublish = false\n\n[dependencies]\nnalgebra = \"^0.33.0\"\ntheon = \"^0.1.0\"\n\n[dependencies.pictor]\npath = \"../../pictor\"\n\n[dependencies.plexus]\npath = \"../../plexus\"\ndefault-features = false\nfeatures = [\n    \"encoding-ply\",\n    \"geometry-nalgebra\",\n]\n"
  },
  {
    "path": "examples/sphere/src/main.rs",
    "content": "use nalgebra::Point3;\nuse pictor::pipeline::{self, Vertex};\nuse plexus::prelude::*;\nuse plexus::primitive;\nuse plexus::primitive::generate::{Normal, Position};\nuse plexus::primitive::sphere::UvSphere;\nuse theon::space::{EuclideanSpace, VectorSpace};\n\ntype E3 = Point3<f32>;\n\nfn main() {\n    let from = Point3::new(0.0, 0.0, 3.0);\n    let to = Point3::origin();\n    pipeline::render_mesh_buffer_with(from, to, move || {\n        let sphere = UvSphere::new(32, 16);\n        primitive::zip_vertices((\n            sphere.polygons::<Position<E3>>().triangulate(),\n            sphere.polygons::<Normal<E3>>().triangulate(),\n        ))\n        .map_vertices(|(position, normal)| Vertex {\n            position: position.into_homogeneous().into(),\n            normal: normal.into_inner().into_homogeneous().into(),\n            color: [1.0, 0.6, 0.2, 1.0],\n        })\n        .collect()\n    });\n}\n"
  },
  {
    "path": "examples/subdivide/Cargo.toml",
    "content": "[package]\nname = \"example-subdivide\"\nversion = \"0.0.0\"\nedition = \"2021\"\nauthors = [\"Sean Olson <olson.sean.k@gmail.com>\"]\nlicense = \"MIT\"\npublish = false\n\n[dependencies]\nnalgebra = \"^0.33.0\"\nsmallvec = \"^1.0.0\"\ntheon = \"^0.1.0\"\n\n[dependencies.pictor]\npath = \"../../pictor\"\n\n[dependencies.plexus]\npath = \"../../plexus\"\ndefault-features = false\nfeatures = [\"geometry-nalgebra\"]\n"
  },
  {
    "path": "examples/subdivide/src/main.rs",
    "content": "use nalgebra::Point3;\nuse pictor::pipeline::{self, Vertex};\nuse plexus::geometry::AsPositionMut;\nuse plexus::graph::{ClosedView, EdgeMidpoint, FaceView, GraphData, MeshGraph};\nuse plexus::prelude::*;\nuse plexus::primitive::Tetragon;\nuse smallvec::SmallVec;\nuse theon::space::{EuclideanSpace, VectorSpace};\n\ntype E3 = Point3<f32>;\n\npub trait Ambo<G>: ClosedView {\n    #[must_use]\n    fn ambo(self) -> Self;\n}\n\nimpl<G> Ambo<G> for FaceView<&'_ mut MeshGraph<G>>\nwhere\n    G: EdgeMidpoint + GraphData,\n    G::Vertex: AsPositionMut,\n{\n    // Subdivide the face with a polygon formed from vertices at the midpoints\n    // of the edges of the face.\n    fn ambo(self) -> Self {\n        // Split each edge, stashing the vertex key and moving to the next arc.\n        let arity = self.arity();\n        let mut arc = self.into_arc();\n        let mut splits = SmallVec::<[_; 4]>::with_capacity(arity);\n        for _ in 0..arity {\n            let vertex = arc.split_at_midpoint();\n            splits.push(vertex.key());\n            arc = vertex.into_outgoing_arc().into_next_arc();\n        }\n        // Split faces along the vertices from each arc split.\n        let mut face = arc.into_face().unwrap();\n        for (a, b) in splits.into_iter().perimeter() {\n            face = face.split(a, b).unwrap().into_face().unwrap();\n        }\n        // Return the face forming the similar polygon.\n        face\n    }\n}\n\nfn main() {\n    let from = Point3::new(-0.9, 3.1, 2.4);\n    let to = Point3::new(0.0, 1.0, 0.0);\n    pipeline::render_mesh_buffer_with(from, to, || {\n        // Create a graph from a tetragon.\n        let mut graph = MeshGraph::<E3>::from(Tetragon::from([\n            (1.0, 0.0, -1.0),\n            (-1.0, 0.0, -1.0),\n            (-1.0, 0.0, 1.0),\n            (1.0, 0.0, 1.0),\n        ]));\n        // Get the face of the tetragon.\n        let key = graph.faces().next().unwrap().key();\n        let mut face = graph.face_mut(key).unwrap();\n\n        // Subdivide and extrude the face repeatedly.\n        for _ in 0..5 {\n            face = face.ambo().extrude_with_offset(0.5).unwrap();\n        }\n\n        // Convert the graph into a buffer.\n        graph.triangulate();\n        graph\n            .to_mesh_by_face_with(|face, vertex| Vertex {\n                position: vertex.position().into_homogeneous().into(),\n                normal: face.normal().unwrap().into_homogeneous().into(),\n                color: [1.0, 0.6, 0.2, 1.0],\n            })\n            .unwrap()\n    });\n}\n"
  },
  {
    "path": "examples/teapot/Cargo.toml",
    "content": "[package]\nname = \"example-teapot\"\nversion = \"0.0.0\"\nedition = \"2021\"\nauthors = [\"Sean Olson <olson.sean.k@gmail.com>\"]\nlicense = \"MIT\"\npublish = false\n\n[dependencies]\nnalgebra = \"^0.33.0\"\ntheon = \"^0.1.0\"\n\n[dependencies.pictor]\npath = \"../../pictor\"\n\n[dependencies.plexus]\npath = \"../../plexus\"\ndefault-features = false\nfeatures = [\n    \"encoding-ply\",\n    \"geometry-nalgebra\",\n]\n"
  },
  {
    "path": "examples/teapot/src/main.rs",
    "content": "use nalgebra::Point3;\nuse pictor::pipeline::{self, Vertex};\nuse plexus::encoding::ply::{FromPly, PositionEncoding};\nuse plexus::graph::MeshGraph;\nuse theon::space::{EuclideanSpace, VectorSpace};\n\ntype E3 = Point3<f32>;\n\nfn main() {\n    let from = Point3::new(0.0, -6.0, 4.0);\n    let to = Point3::new(0.0, 0.0, 1.0);\n    pipeline::render_mesh_buffer_with(from, to, move || {\n        // Read PLY data into a graph.\n        let ply: &[u8] = include_bytes!(\"../../../data/teapot.ply\");\n        let encoding = PositionEncoding::<E3>::default();\n        let (graph, _) = MeshGraph::<E3>::from_ply(encoding, ply).expect(\"teapot\");\n\n        // Convert the graph into a buffer.\n        graph\n            .to_mesh_by_vertex_with(|vertex| Vertex {\n                position: vertex.position().into_homogeneous().into(),\n                normal: vertex.normal().unwrap().into_homogeneous().into(),\n                color: [1.0, 0.6, 0.2, 1.0],\n            })\n            .expect(\"buffer\")\n    });\n}\n"
  },
  {
    "path": "pictor/Cargo.toml",
    "content": "[package]\nname = \"pictor\"\nversion = \"0.0.0\"\nedition = \"2021\"\nrust-version = \"1.81.0\"\nauthors = [\"Sean Olson <olson.sean.k@gmail.com>\"]\nlicense = \"MIT\"\ndescription = \"Renderer and support library for Plexus examples.\"\npublish = false\n\n[dependencies]\nbytemuck = \"^1.13.0\"\ndecorum = \"^0.4.0\"\nnaga = \"^23.0.0\"\nnalgebra = \"^0.33.0\"\nnum = \"^0.4.3\"\nrand = \"^0.8.5\"\ntheon = \"^0.1.0\"\nwinit = \"^0.30.8\"\n\n[dependencies.futures]\nversion = \"^0.3.31\"\ndefault-features = false\nfeatures = [\n    \"std\",\n    \"executor\",\n]\n\n[dependencies.plexus]\npath = \"../plexus\"\ndefault-features = false\nfeatures = [\"geometry-nalgebra\"]\n\n[dependencies.wgpu]\nversion = \"^23.0.1\"\nfeatures = [\"spirv\"]\n"
  },
  {
    "path": "pictor/src/camera.rs",
    "content": "use nalgebra::{Isometry3, Matrix4, Orthographic3, Perspective3, Point3, Vector3};\nuse std::sync::LazyLock;\nuse wgpu::SurfaceConfiguration;\n\n#[rustfmt::skip]\nstatic OPENGL_TO_WGPU_TRANSFORM: LazyLock<Matrix4<f32>> = LazyLock::new(|| {\n    Matrix4::new(\n        1.0, 0.0, 0.0, 0.0,\n        0.0, 1.0, 0.0, 0.0,\n        0.0, 0.0, 0.5, 0.0,\n        0.0, 0.0, 0.5, 1.0,\n    )\n});\n\n#[derive(Clone, Debug)]\npub enum Projection {\n    Perspective(Perspective3<f32>),\n    Orthographic(Orthographic3<f32>),\n}\n\nimpl Projection {\n    pub fn perspective(aspect: f32, fov: f32, near: f32, far: f32) -> Self {\n        Projection::Perspective(Perspective3::new(aspect, fov, near, far))\n    }\n\n    pub fn orthographic(left: f32, right: f32, bottom: f32, top: f32, near: f32, far: f32) -> Self {\n        Projection::Orthographic(Orthographic3::new(left, right, bottom, top, near, far))\n    }\n}\n\nimpl AsRef<Matrix4<f32>> for Projection {\n    fn as_ref(&self) -> &Matrix4<f32> {\n        match *self {\n            Projection::Perspective(ref perspective) => perspective.as_matrix(),\n            Projection::Orthographic(ref orthographic) => orthographic.as_matrix(),\n        }\n    }\n}\n\n#[derive(Clone, Debug)]\npub struct Camera {\n    pub projection: Projection,\n    view: Isometry3<f32>,\n}\n\nimpl Camera {\n    pub fn look_at(&mut self, from: &Point3<f32>, to: &Point3<f32>) {\n        self.view = Isometry3::look_at_rh(from, to, &Vector3::y());\n    }\n\n    pub fn reproject(&mut self, surface: &SurfaceConfiguration) {\n        match self.projection {\n            Projection::Perspective(ref mut perspective) => {\n                perspective.set_aspect(surface.width as f32 / surface.height as f32);\n            }\n            Projection::Orthographic(ref mut orthographic) => {\n                let inverse = surface.height as f32 / surface.width as f32;\n                let radius = (orthographic.right() - orthographic.left()) * inverse * 0.5;\n                orthographic.set_bottom_and_top(-radius, radius);\n            }\n        }\n    }\n\n    pub fn transform(&self) -> Matrix4<f32> {\n        *OPENGL_TO_WGPU_TRANSFORM * self.projection.as_ref() * self.view.to_homogeneous()\n    }\n}\n\nimpl From<Projection> for Camera {\n    fn from(projection: Projection) -> Self {\n        Camera {\n            projection,\n            view: Isometry3::look_at_rh(\n                &Point3::new(0.0, 0.0, 1.0),\n                &Point3::origin(),\n                &Vector3::y(),\n            ),\n        }\n    }\n}\n"
  },
  {
    "path": "pictor/src/harness.rs",
    "content": "use futures::executor::{self, LocalPool, LocalSpawner};\nuse futures::task::LocalSpawn;\nuse std::cmp;\nuse std::fmt::Debug;\nuse std::sync::Arc;\nuse winit::application::ApplicationHandler;\nuse winit::dpi::PhysicalSize;\nuse winit::event::WindowEvent;\nuse winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop};\nuse winit::window::{Window, WindowAttributes, WindowId};\n\nuse crate::renderer::Renderer;\n\n#[derive(Debug)]\nstruct Executor {\n    pool: LocalPool,\n    spawner: LocalSpawner,\n}\n\nimpl Executor {\n    pub fn new() -> Self {\n        let pool = LocalPool::new();\n        let spawner = pool.spawner();\n        Executor { pool, spawner }\n    }\n\n    pub fn flush(&mut self) {\n        self.pool.run_until_stalled()\n    }\n\n    pub fn spawner(&self) -> &impl LocalSpawn {\n        &self.spawner\n    }\n}\n\n#[derive(Debug)]\nstruct Activity<T> {\n    window: Arc<Window>,\n    renderer: Renderer<'static>,\n    application: T,\n}\n\nimpl<T> Activity<T>\nwhere\n    T: Application,\n{\n    pub fn bind_and_configure(window: Window, configuration: T::Configuration) -> Self {\n        let window = Arc::new(window);\n        let renderer = executor::block_on(Renderer::try_from_window(window.clone())).unwrap();\n        let application = T::configure(configuration, &renderer).unwrap();\n        Activity {\n            window,\n            renderer,\n            application,\n        }\n    }\n}\n\n#[derive(Debug)]\nstruct Harness<T, F> {\n    executor: Executor,\n    f: F,\n    activity: Option<Activity<T>>,\n}\n\nimpl<T, F> Harness<T, F>\nwhere\n    T: Application,\n{\n    fn redraw(&mut self) {\n        if let Some(activity) = self.activity.as_mut() {\n            let frame = activity.renderer.surface.get_current_texture().unwrap();\n            let view = frame\n                .texture\n                .create_view(&wgpu::TextureViewDescriptor::default());\n            activity\n                .application\n                .render(&activity.renderer, &view, self.executor.spawner());\n            frame.present();\n        }\n    }\n\n    fn resize(&mut self, dimensions: PhysicalSize<u32>) {\n        if let Some(activity) = self.activity.as_mut() {\n            activity.renderer.surface_configuration.width = cmp::max(1, dimensions.width);\n            activity.renderer.surface_configuration.height = cmp::max(1, dimensions.height);\n            activity.application.resize(&activity.renderer);\n            activity.renderer.surface.configure(\n                &activity.renderer.device,\n                &activity.renderer.surface_configuration,\n            );\n            activity.window.request_redraw();\n        }\n    }\n}\n\nimpl<T, F> ApplicationHandler<()> for Harness<T, F>\nwhere\n    T: Application,\n    F: FnMut() -> (WindowAttributes, T::Configuration),\n{\n    fn resumed(&mut self, reactor: &ActiveEventLoop) {\n        let (window, configuration) = (self.f)();\n        self.activity.replace(Activity::bind_and_configure(\n            reactor.create_window(window).unwrap(),\n            configuration,\n        ));\n    }\n\n    fn suspended(&mut self, _reactor: &ActiveEventLoop) {\n        self.activity.take();\n    }\n\n    fn window_event(&mut self, reactor: &ActiveEventLoop, _: WindowId, event: WindowEvent) {\n        match event {\n            WindowEvent::RedrawRequested => {\n                self.redraw();\n            }\n            WindowEvent::CloseRequested => {\n                reactor.exit();\n            }\n            WindowEvent::Resized(dimensions) => {\n                self.resize(dimensions);\n            }\n            _ => {\n                if let Some(activity) = self.activity.as_mut() {\n                    if let Reaction::Abort = activity.application.react(event) {\n                        reactor.exit();\n                    }\n                }\n            }\n        }\n        self.executor.flush();\n    }\n}\n\n#[derive(Clone, Copy, Debug, Default)]\npub enum Reaction {\n    #[default]\n    Continue,\n    Abort,\n}\n\npub trait ConfigureStage {\n    fn device(&self) -> &wgpu::Device;\n\n    fn queue(&self) -> &wgpu::Queue;\n\n    fn surface_configuration(&self) -> &wgpu::SurfaceConfiguration;\n}\n\npub trait RenderStage {\n    fn device(&self) -> &wgpu::Device;\n\n    fn queue(&self) -> &wgpu::Queue;\n}\n\npub trait Application: 'static + Sized {\n    type Configuration: Sized;\n    type Error: Debug;\n\n    fn configure(\n        configuration: Self::Configuration,\n        stage: &impl ConfigureStage,\n    ) -> Result<Self, Self::Error>;\n\n    fn react(&mut self, event: WindowEvent) -> Reaction {\n        let _ = event;\n        Reaction::Continue\n    }\n\n    fn resize(&mut self, stage: &impl ConfigureStage);\n\n    fn render(\n        &mut self,\n        stage: &impl RenderStage,\n        view: &wgpu::TextureView,\n        spawn: &impl LocalSpawn,\n    );\n}\n\npub fn run<T, F>(f: F)\nwhere\n    T: Application,\n    F: FnMut() -> (WindowAttributes, T::Configuration),\n{\n    let executor = Executor::new();\n    let reactor = EventLoop::new().unwrap();\n    reactor.set_control_flow(ControlFlow::Poll);\n    reactor\n        .run_app(&mut Harness::<T, _> {\n            executor,\n            f,\n            activity: None,\n        })\n        .unwrap();\n}\n"
  },
  {
    "path": "pictor/src/lib.rs",
    "content": "mod camera;\nmod harness;\npub mod pipeline;\nmod renderer;\n\npub use crate::camera::*;\npub use crate::harness::*;\n\n// TODO: Compile shaders from source code rather than statically loading binary SpirV.\n"
  },
  {
    "path": "pictor/src/pipeline.rs",
    "content": "use bytemuck::{self, Pod, Zeroable};\nuse decorum::cmp::CanonicalEq;\nuse decorum::hash::CanonicalHash;\nuse futures::task::LocalSpawn;\nuse nalgebra::{Point3, Scalar, Vector3, Vector4};\nuse num::{self, One};\nuse plexus::buffer::MeshBuffer;\nuse plexus::geometry::UnitGeometry;\nuse plexus::index::Flat3;\nuse rand::distributions::{Distribution, Standard};\nuse rand::{self, Rng};\nuse std::f32::consts::FRAC_PI_4;\nuse std::hash::{Hash, Hasher};\nuse std::mem;\nuse theon::adjunct::Extend;\nuse wgpu::include_spirv_raw;\nuse wgpu::util::DeviceExt as _;\nuse winit::event::{ElementState, KeyEvent, WindowEvent};\nuse winit::keyboard::{Key, NamedKey};\nuse winit::window::Window;\n\nuse crate::camera::{Camera, Projection};\nuse crate::harness::{self, Application, ConfigureStage, Reaction, RenderStage};\n\nuse Reaction::Abort;\nuse Reaction::Continue;\n\n#[derive(Clone, Copy, Debug)]\npub struct Color4<T>(pub Vector4<T>)\nwhere\n    T: Scalar;\n\nimpl<T> Color4<T>\nwhere\n    T: Scalar,\n{\n    pub fn white() -> Self\n    where\n        T: One,\n    {\n        Color4(Vector4::repeat(One::one()))\n    }\n\n    pub fn random() -> Self\n    where\n        T: One,\n        Standard: Distribution<T>,\n        Vector3<T>: Extend<Vector4<T>, Item = T>,\n    {\n        let mut rng = rand::thread_rng();\n        Color4(Vector3::from_fn(|_, _| rng.gen()).extend(One::one()))\n    }\n}\n\nimpl<T> AsRef<Vector4<T>> for Color4<T>\nwhere\n    T: Scalar,\n{\n    fn as_ref(&self) -> &Vector4<T> {\n        &self.0\n    }\n}\n\nimpl<T> Default for Color4<T>\nwhere\n    T: One + Scalar,\n{\n    fn default() -> Self {\n        Color4::white()\n    }\n}\n\nimpl<T> From<Vector4<T>> for Color4<T>\nwhere\n    T: Scalar,\n{\n    fn from(vector: Vector4<T>) -> Self {\n        Color4(vector)\n    }\n}\n\nimpl<T> From<Color4<T>> for Vector4<T>\nwhere\n    T: Scalar,\n{\n    fn from(color: Color4<T>) -> Self {\n        color.0\n    }\n}\n\nimpl<T> UnitGeometry for Color4<T> where T: One + Scalar {}\n\n#[derive(Clone, Copy, Debug)]\n#[repr(C)]\npub struct Vertex {\n    pub position: [f32; 4],\n    pub normal: [f32; 4],\n    pub color: [f32; 4],\n}\n\nimpl Eq for Vertex {}\n\nimpl Hash for Vertex {\n    fn hash<H>(&self, state: &mut H)\n    where\n        H: Hasher,\n    {\n        self.position.hash_canonical(state);\n        self.normal.hash_canonical(state);\n        self.color.hash_canonical(state);\n    }\n}\n\nimpl PartialEq for Vertex {\n    fn eq(&self, other: &Self) -> bool {\n        self.position.eq_canonical(&other.position)\n            && self.normal.eq_canonical(&other.normal)\n            && self.color.eq_canonical(&other.color)\n    }\n}\n\n// SAFETY: This type is inhabited, is `repr(C)`, has no padding, has no illegal bit patterns,\n//         contains no pointers, and has only fields that are also `Pod`.\nunsafe impl Pod for Vertex {}\n\n// SAFETY: This type has a zeroed inhabitant.\nunsafe impl Zeroable for Vertex {}\n\n#[derive(Debug)]\nstruct RenderConfiguration {\n    camera: Camera,\n    from: Point3<f32>,\n    buffer: MeshBuffer<Flat3<u32>, Vertex>,\n}\n\n#[derive(Debug)]\nstruct RenderApplication {\n    camera: Camera,\n    _viewpoint: wgpu::Buffer,\n    transform: wgpu::Buffer,\n    vertices: wgpu::Buffer,\n    indices: wgpu::Buffer,\n    depth: wgpu::TextureView,\n    n: u32,\n    bind_group: wgpu::BindGroup,\n    pipeline: wgpu::RenderPipeline,\n}\n\nimpl RenderApplication {\n    fn configure_depth_buffer(stage: &impl ConfigureStage) -> wgpu::TextureView {\n        stage\n            .device()\n            .create_texture(&wgpu::TextureDescriptor {\n                label: None,\n                view_formats: stage.surface_configuration().view_formats.as_slice(),\n                size: wgpu::Extent3d {\n                    width: stage.surface_configuration().width,\n                    height: stage.surface_configuration().height,\n                    depth_or_array_layers: 1,\n                },\n                mip_level_count: 1,\n                sample_count: 1,\n                dimension: wgpu::TextureDimension::D2,\n                format: wgpu::TextureFormat::Depth32Float,\n                usage: wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::RENDER_ATTACHMENT,\n            })\n            .create_view(&Default::default())\n    }\n}\n\nimpl Application for RenderApplication {\n    type Configuration = RenderConfiguration;\n    type Error = ();\n\n    fn configure(\n        configuration: Self::Configuration,\n        stage: &impl ConfigureStage,\n    ) -> Result<Self, Self::Error> {\n        let RenderConfiguration {\n            mut camera,\n            from,\n            buffer,\n        } = configuration;\n        camera.reproject(stage.surface_configuration());\n        let vertices = stage\n            .device()\n            .create_buffer_init(&wgpu::util::BufferInitDescriptor {\n                label: None,\n                contents: bytemuck::cast_slice(buffer.as_vertex_slice()),\n                usage: wgpu::BufferUsages::VERTEX,\n            });\n        let indices = stage\n            .device()\n            .create_buffer_init(&wgpu::util::BufferInitDescriptor {\n                label: None,\n                contents: bytemuck::cast_slice(buffer.as_index_slice()),\n                usage: wgpu::BufferUsages::INDEX,\n            });\n        let transform = stage\n            .device()\n            .create_buffer_init(&wgpu::util::BufferInitDescriptor {\n                label: None,\n                contents: bytemuck::cast_slice(camera.transform().as_slice()),\n                usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::UNIFORM,\n            });\n        let viewpoint = stage\n            .device()\n            .create_buffer_init(&wgpu::util::BufferInitDescriptor {\n                label: None,\n                contents: bytemuck::cast_slice(from.coords.as_slice()),\n                usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::UNIFORM,\n            });\n        let depth = Self::configure_depth_buffer(stage);\n        let bind_group_layout =\n            stage\n                .device()\n                .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {\n                    label: None,\n                    entries: &[\n                        wgpu::BindGroupLayoutEntry {\n                            binding: 0,\n                            visibility: wgpu::ShaderStages::VERTEX,\n                            ty: wgpu::BindingType::Buffer {\n                                ty: wgpu::BufferBindingType::Uniform,\n                                has_dynamic_offset: false,\n                                min_binding_size: wgpu::BufferSize::new(64),\n                            },\n                            count: None,\n                        },\n                        wgpu::BindGroupLayoutEntry {\n                            binding: 1,\n                            visibility: wgpu::ShaderStages::VERTEX,\n                            ty: wgpu::BindingType::Buffer {\n                                ty: wgpu::BufferBindingType::Uniform,\n                                has_dynamic_offset: false,\n                                min_binding_size: wgpu::BufferSize::new(12),\n                            },\n                            count: None,\n                        },\n                    ],\n                });\n        let bind_group = stage\n            .device()\n            .create_bind_group(&wgpu::BindGroupDescriptor {\n                label: None,\n                layout: &bind_group_layout,\n                entries: &[\n                    wgpu::BindGroupEntry {\n                        binding: 0,\n                        resource: transform.as_entire_binding(),\n                    },\n                    wgpu::BindGroupEntry {\n                        binding: 1,\n                        resource: viewpoint.as_entire_binding(),\n                    },\n                ],\n            });\n        let pipeline = stage\n            .device()\n            .create_render_pipeline(&wgpu::RenderPipelineDescriptor {\n                label: None,\n                layout: Some(&stage.device().create_pipeline_layout(\n                    &wgpu::PipelineLayoutDescriptor {\n                        label: None,\n                        bind_group_layouts: &[&bind_group_layout],\n                        push_constant_ranges: &[],\n                    },\n                )),\n                vertex: wgpu::VertexState {\n                    module: unsafe {\n                        &stage\n                            .device()\n                            .create_shader_module_spirv(&include_spirv_raw!(\"shader.spv.vert\"))\n                    },\n                    entry_point: Some(\"main\"),\n                    compilation_options: Default::default(),\n                    buffers: &[wgpu::VertexBufferLayout {\n                        array_stride: mem::size_of::<Vertex>() as wgpu::BufferAddress,\n                        step_mode: wgpu::VertexStepMode::Vertex,\n                        // LINT: The constants in these trivial expressions illustrate the sizing\n                        //       and layout of the data more clearly than the evaluation alone.\n                        attributes: &[\n                            #[expect(clippy::erasing_op)]\n                            wgpu::VertexAttribute {\n                                format: wgpu::VertexFormat::Float32x4,\n                                offset: 0 * 4 * 4,\n                                shader_location: 0,\n                            },\n                            #[expect(clippy::identity_op)]\n                            wgpu::VertexAttribute {\n                                format: wgpu::VertexFormat::Float32x4,\n                                offset: 1 * 4 * 4,\n                                shader_location: 1,\n                            },\n                            wgpu::VertexAttribute {\n                                format: wgpu::VertexFormat::Float32x4,\n                                offset: 2 * 4 * 4,\n                                shader_location: 2,\n                            },\n                        ],\n                    }],\n                },\n                fragment: Some(wgpu::FragmentState {\n                    module: unsafe {\n                        &stage\n                            .device()\n                            .create_shader_module_spirv(&include_spirv_raw!(\"shader.spv.frag\"))\n                    },\n                    entry_point: Some(\"main\"),\n                    compilation_options: Default::default(),\n                    targets: &[Some(wgpu::ColorTargetState {\n                        format: stage.surface_configuration().format,\n                        blend: Some(wgpu::BlendState {\n                            color: wgpu::BlendComponent::REPLACE,\n                            alpha: wgpu::BlendComponent::REPLACE,\n                        }),\n                        write_mask: wgpu::ColorWrites::ALL,\n                    })],\n                }),\n                depth_stencil: Some(wgpu::DepthStencilState {\n                    format: wgpu::TextureFormat::Depth32Float,\n                    depth_write_enabled: true,\n                    depth_compare: wgpu::CompareFunction::Less,\n                    stencil: Default::default(),\n                    bias: Default::default(),\n                }),\n                primitive: wgpu::PrimitiveState {\n                    topology: wgpu::PrimitiveTopology::TriangleList,\n                    front_face: wgpu::FrontFace::Ccw,\n                    cull_mode: Some(wgpu::Face::Back),\n                    ..Default::default()\n                },\n                multisample: Default::default(),\n                multiview: None,\n                cache: None,\n            });\n        Ok(RenderApplication {\n            camera,\n            _viewpoint: viewpoint,\n            transform,\n            vertices,\n            indices,\n            depth,\n            n: buffer.as_index_slice().len() as u32,\n            bind_group,\n            pipeline,\n        })\n    }\n\n    fn react(&mut self, event: WindowEvent) -> Reaction {\n        match event {\n            WindowEvent::KeyboardInput {\n                event:\n                    KeyEvent {\n                        logical_key: Key::Named(NamedKey::Escape),\n                        state: ElementState::Pressed,\n                        ..\n                    },\n                ..\n            } => Abort,\n            _ => Continue,\n        }\n    }\n\n    fn resize(&mut self, stage: &impl ConfigureStage) {\n        self.camera.reproject(stage.surface_configuration());\n        stage.queue().write_buffer(\n            &self.transform,\n            0,\n            bytemuck::cast_slice(self.camera.transform().as_slice()),\n        );\n        self.depth = Self::configure_depth_buffer(stage);\n    }\n\n    fn render(&mut self, stage: &impl RenderStage, view: &wgpu::TextureView, _: &impl LocalSpawn) {\n        let mut encoder = stage\n            .device()\n            .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });\n        let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {\n            color_attachments: &[Some(wgpu::RenderPassColorAttachment {\n                view,\n                resolve_target: None,\n                ops: wgpu::Operations {\n                    load: wgpu::LoadOp::Clear(wgpu::Color {\n                        r: 0.1,\n                        g: 0.2,\n                        b: 0.3,\n                        a: 1.0,\n                    }),\n                    store: wgpu::StoreOp::Store,\n                },\n            })],\n            depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {\n                view: &self.depth,\n                depth_ops: Some(wgpu::Operations {\n                    load: wgpu::LoadOp::Clear(1.0),\n                    store: wgpu::StoreOp::Store,\n                }),\n                stencil_ops: None,\n            }),\n            ..Default::default()\n        });\n        pass.set_pipeline(&self.pipeline);\n        pass.set_bind_group(0, &self.bind_group, &[]);\n        pass.set_index_buffer(self.indices.slice(..), wgpu::IndexFormat::Uint32);\n        pass.set_vertex_buffer(0, self.vertices.slice(..));\n        pass.draw_indexed(0..self.n, 0, 0..1);\n\n        drop(pass); // Release `encoder`.\n        stage.queue().submit(Some(encoder.finish()));\n    }\n}\n\npub fn render_mesh_buffer_with<F>(from: Point3<f32>, to: Point3<f32>, mut f: F)\nwhere\n    F: FnMut() -> MeshBuffer<Flat3<u32>, Vertex>,\n{\n    let camera = {\n        let mut camera = Camera::from(Projection::perspective(1.0, FRAC_PI_4, 0.1, 8.0));\n        //let mut camera = Camera::from(Projection::orthographic(-4.0, 4.0, -4.0, 4.0, -8.0, 8.0));\n        camera.look_at(&from, &to);\n        camera\n    };\n    harness::run::<RenderApplication, _>(move || {\n        (\n            Window::default_attributes().with_title(\"Plexus\"),\n            RenderConfiguration {\n                camera: camera.clone(),\n                from,\n                buffer: f(),\n            },\n        )\n    })\n}\n"
  },
  {
    "path": "pictor/src/renderer.rs",
    "content": "use std::borrow::Borrow;\nuse winit::window::Window;\n\nuse crate::harness::{ConfigureStage, RenderStage};\n\n#[derive(Debug)]\npub struct Renderer<'window> {\n    _instance: wgpu::Instance,\n    _adapter: wgpu::Adapter,\n    pub surface: wgpu::Surface<'window>,\n    pub surface_configuration: wgpu::SurfaceConfiguration,\n    pub device: wgpu::Device,\n    queue: wgpu::Queue,\n}\n\nimpl<'window> Renderer<'window> {\n    pub async fn try_from_window<T>(window: T) -> Result<Self, ()>\n    where\n        T: Borrow<Window> + Into<wgpu::SurfaceTarget<'window>>,\n    {\n        let dimensions = window.borrow().inner_size();\n        let instance = wgpu::Instance::new(wgpu::InstanceDescriptor::default());\n        let surface = instance.create_surface(window).unwrap();\n        let adapter = instance\n            .request_adapter(&wgpu::RequestAdapterOptions {\n                compatible_surface: Some(&surface),\n                ..Default::default()\n            })\n            .await\n            .ok_or(())?;\n        let (device, queue) = adapter\n            .request_device(\n                &wgpu::DeviceDescriptor {\n                    required_features: wgpu::Features::SPIRV_SHADER_PASSTHROUGH,\n                    required_limits: wgpu::Limits::downlevel_webgl2_defaults()\n                        .using_resolution(adapter.limits()),\n                    memory_hints: wgpu::MemoryHints::MemoryUsage,\n                    ..Default::default()\n                },\n                None,\n            )\n            .await\n            .map_err(|_| ())?;\n        let surface_configuration = surface\n            .get_default_config(&adapter, dimensions.width, dimensions.height)\n            .unwrap();\n        Ok(Renderer {\n            _instance: instance,\n            _adapter: adapter,\n            surface,\n            surface_configuration,\n            device,\n            queue,\n        })\n    }\n}\n\nimpl ConfigureStage for Renderer<'_> {\n    fn device(&self) -> &wgpu::Device {\n        &self.device\n    }\n\n    fn queue(&self) -> &wgpu::Queue {\n        &self.queue\n    }\n\n    fn surface_configuration(&self) -> &wgpu::SurfaceConfiguration {\n        &self.surface_configuration\n    }\n}\n\nimpl RenderStage for Renderer<'_> {\n    fn device(&self) -> &wgpu::Device {\n        &self.device\n    }\n\n    fn queue(&self) -> &wgpu::Queue {\n        &self.queue\n    }\n}\n"
  },
  {
    "path": "pictor/src/shader.glsl.frag",
    "content": "#version 450\n\nlayout(location = 0) in vec4 v_color;\n\nlayout(location = 0) out vec4 f_target0;\n\nvoid main() {\n    f_target0 = v_color;\n}\n"
  },
  {
    "path": "pictor/src/shader.glsl.vert",
    "content": "#version 450\n\nlayout(location = 0) in vec4 a_position;\nlayout(location = 1) in vec4 a_normal;\nlayout(location = 2) in vec4 a_color;\n\nlayout(set = 0, binding = 0) uniform transform {\n    mat4 u_transform;\n};\nlayout(set = 0, binding = 1) uniform viewpoint {\n    vec3 u_viewpoint;\n};\n\nlayout(location = 0) out vec4 v_color;\n\nvoid main() {\n    v_color = a_color * vec4(vec3(max(0.0, dot(vec3(a_normal), normalize(u_viewpoint - vec3(a_position))))), 1.0);\n    gl_Position = u_transform * a_position;\n}\n"
  },
  {
    "path": "plexus/Cargo.toml",
    "content": "[package]\nname = \"plexus\"\nversion = \"0.0.11\"\nedition = \"2021\"\nrust-version = \"1.81.0\"\nauthors = [\"Sean Olson <olson.sean.k@gmail.com>\"]\nlicense = \"MIT\"\nreadme = \"../README.md\"\nhomepage = \"https://plexus.rs\"\nrepository = \"https://github.com/olson-sean-k/plexus\"\ndescription = \"Polygonal mesh processing.\"\nkeywords = [\n    \"polygon\",\n    \"mesh\",\n    \"topology\",\n    \"geometry\",\n    \"half-edge\",\n]\ncategories = [\n    \"algorithms\",\n    \"data-structures\",\n    \"graphics\",\n    \"rendering::data-formats\",\n]\n\n[package.metadata.docs.rs]\n# Enable all features for API documentation.\nall-features = true\n# Enable KaTeX support by injecting a header into the documentation.\nrustdoc-args = [\n    \"--html-in-header\",\n    \"../doc/katex-header.html\",\n]\n\n[[bench]]\nname = \"subdivide\"\nharness = false\npath = \"../benches/subdivide.rs\"\n\n[features]\ndefault = []\nencoding-ply = [\"dep:ply-rs\"]\ngeometry-cgmath = [\n    \"dep:cgmath\",\n    \"theon/cgmath\",\n]\ngeometry-glam = [\n    \"dep:glam\",\n    \"theon/glam\",\n]\ngeometry-mint = [\n    \"dep:mint\",\n    \"theon/mint\",\n]\ngeometry-nalgebra = [\n    \"dep:nalgebra\",\n    \"theon/nalgebra\",\n]\ngeometry-ultraviolet = [\n    \"dep:ultraviolet\",\n    \"theon/ultraviolet\",\n]\n\n[dependencies]\napprox = \"^0.5.0\"\nahash = \"^0.8.11\"\narrayvec = \"^0.7.6\"\nderivative = \"^2.1.1\"\nitertools = \"^0.14.0\"\nnum = \"^0.4.3\"\nsmallvec = \"^1.0.0\"\nthiserror = \"^2.0.10\"\ntypenum = \"^1.17.0\"\n\n[dependencies.cgmath]\nversion = \"^0.18.0\"\noptional = true\n\n[dependencies.decorum]\nversion = \"^0.4.0\"\ndefault-features = false\nfeatures = [\n    \"approx\",\n    \"serde\",\n    \"std\",\n]\n\n[dependencies.glam]\nversion = \"^0.29.0\"\noptional = true\n\n[dependencies.mint]\nversion = \"^0.5.0\"\noptional = true\n\n[dependencies.nalgebra]\nversion = \"^0.33.0\"\noptional = true\n\n[dependencies.ply-rs]\nversion = \"^0.1.2\"\noptional = true\n\n[dependencies.theon]\nversion = \"^0.1.0\"\ndefault-features = false\nfeatures = [\"lapack\"]\n\n[dependencies.ultraviolet]\nversion = \"^0.9.0\"\noptional = true\n\n[build-dependencies]\nrustversion = \"^1.0.3\"\n\n[dev-dependencies]\ncriterion = \"^0.5.1\"\n# For brevity and simplicity, tests and API documentation use a direct\n# dependency on `nalgebra`. This approach requires that the version\n# specification is compatible with `theon`.\nnalgebra = \"^0.33.0\"\n\n[dev-dependencies.theon]\nversion = \"^0.1.0\"\ndefault-features = false\nfeatures = [\n    \"lapack\",\n    \"nalgebra\",\n]\n"
  },
  {
    "path": "plexus/src/buffer/builder.rs",
    "content": "use num::{Integer, NumCast, Unsigned};\nuse std::hash::Hash;\nuse typenum::NonZero;\n\nuse crate::buffer::{BufferError, MeshBuffer};\nuse crate::builder::{FacetBuilder, MeshBuilder, SurfaceBuilder};\nuse crate::constant::{Constant, ToType, TypeOf};\nuse crate::geometry::{FromGeometry, IntoGeometry};\nuse crate::index::{Flat, Grouping, IndexBuffer};\nuse crate::primitive::Topological;\nuse crate::transact::{ClosedInput, Transact};\nuse crate::Arity;\n\n// TODO: It should not be possible to manufacture keys without placing\n//       additional constraints on the type bounds of `FacetBuilder` (for\n//       example, `FacetBuilder<Key = usize>`). Is it important to check for\n//       out-of-bounds indices in `insert_facet`?\n\npub type VertexKey<R> = <Vec<<R as Grouping>::Group> as IndexBuffer<R>>::Index;\n\npub struct BufferBuilder<R, G>\nwhere\n    R: Grouping,\n{\n    indices: Vec<R::Group>,\n    vertices: Vec<G>,\n}\n\nimpl<R, G> Default for BufferBuilder<R, G>\nwhere\n    R: Grouping,\n    Vec<R::Group>: IndexBuffer<R>,\n{\n    fn default() -> Self {\n        BufferBuilder {\n            indices: Default::default(),\n            vertices: Default::default(),\n        }\n    }\n}\n\nimpl<R, G> ClosedInput for BufferBuilder<R, G>\nwhere\n    R: Grouping,\n    Vec<R::Group>: IndexBuffer<R>,\n{\n    type Input = ();\n}\n\nimpl<K, G, const N: usize> FacetBuilder<K> for BufferBuilder<Flat<K, N>, G>\nwhere\n    Constant<N>: ToType,\n    TypeOf<N>: NonZero,\n    K: Copy + Hash + Integer + Unsigned,\n    Vec<K>: IndexBuffer<Flat<K, N>>,\n{\n    type Facet = ();\n    type Key = ();\n\n    fn insert_facet<T, U>(&mut self, keys: T, _: U) -> Result<Self::Key, Self::Error>\n    where\n        Self::Facet: FromGeometry<U>,\n        T: AsRef<[K]>,\n    {\n        let keys = keys.as_ref();\n        if keys.len() == N {\n            self.indices.extend(keys.iter());\n            Ok(())\n        }\n        else {\n            // TODO: These numbers do not necessarily represent arity (i.e., the\n            //       number of edges of each topological structure). Use a\n            //       different error variant to express this.\n            Err(BufferError::ArityConflict {\n                expected: N,\n                actual: keys.len(),\n            })\n        }\n    }\n}\n\nimpl<P, G> FacetBuilder<P::Vertex> for BufferBuilder<P, G>\nwhere\n    P: Grouping<Group = P> + Topological,\n    P::Vertex: Copy + Hash + Integer + Unsigned,\n    Vec<P>: IndexBuffer<P>,\n{\n    type Facet = ();\n    type Key = ();\n\n    fn insert_facet<T, U>(&mut self, keys: T, _: U) -> Result<Self::Key, Self::Error>\n    where\n        Self::Facet: FromGeometry<U>,\n        T: AsRef<[P::Vertex]>,\n    {\n        let arity = keys.as_ref().len();\n        P::try_from_slice(keys)\n            .ok_or(BufferError::ArityConflict {\n                expected: P::ARITY.into_interval().0,\n                actual: arity,\n            })\n            .map(|polygon| self.indices.push(polygon))\n    }\n}\n\nimpl<R, G> MeshBuilder for BufferBuilder<R, G>\nwhere\n    Self: SurfaceBuilder<Vertex = G, Facet = ()>,\n    R: Grouping,\n    VertexKey<R>: Hash,\n    Vec<R::Group>: IndexBuffer<R>,\n{\n    type Builder = Self;\n\n    type Vertex = G;\n    type Facet = ();\n\n    fn surface_with<F, T, E>(&mut self, f: F) -> Result<T, Self::Error>\n    where\n        Self::Error: From<E>,\n        F: FnOnce(&mut Self::Builder) -> Result<T, E>,\n    {\n        f(self).map_err(|error| error.into())\n    }\n}\n\nimpl<R, G> SurfaceBuilder for BufferBuilder<R, G>\nwhere\n    Self: FacetBuilder<VertexKey<R>, Facet = ()>,\n    Self::Error: From<BufferError>, // TODO: Why is this necessary?\n    R: Grouping,\n    VertexKey<R>: Hash + NumCast,\n    Vec<R::Group>: IndexBuffer<R>,\n{\n    type Builder = Self;\n    type Key = VertexKey<R>;\n\n    type Vertex = G;\n    type Facet = ();\n\n    fn facets_with<F, T, E>(&mut self, f: F) -> Result<T, Self::Error>\n    where\n        Self::Error: From<E>,\n        F: FnOnce(&mut Self::Builder) -> Result<T, E>,\n    {\n        f(self).map_err(|error| error.into())\n    }\n\n    fn insert_vertex<T>(&mut self, data: T) -> Result<Self::Key, Self::Error>\n    where\n        Self::Vertex: FromGeometry<T>,\n    {\n        let key = <VertexKey<R> as NumCast>::from(self.vertices.len())\n            .ok_or(BufferError::IndexOverflow)?;\n        self.vertices.push(data.into_geometry());\n        Ok(key)\n    }\n}\n\nimpl<R, G> Transact<<Self as ClosedInput>::Input> for BufferBuilder<R, G>\nwhere\n    R: Grouping,\n    Vec<R::Group>: IndexBuffer<R>,\n{\n    type Commit = MeshBuffer<R, G>;\n    type Abort = ();\n    type Error = BufferError;\n\n    fn commit(self) -> Result<Self::Commit, (Self::Abort, Self::Error)> {\n        let BufferBuilder { indices, vertices } = self;\n        Ok(MeshBuffer::from_raw_buffers_unchecked(indices, vertices))\n    }\n\n    fn abort(self) -> Self::Abort {}\n}\n"
  },
  {
    "path": "plexus/src/buffer/mod.rs",
    "content": "//! Linear representations of polygonal meshes.\n//!\n//! This module provides types and traits that describe polygonal meshes as\n//! buffers of vertex data and buffers of indices into that vertex data. These\n//! buffers are called the _vertex buffer_ and _index buffer_, respectively, and\n//! are typically used for indexed drawing. The [`MeshBuffer`] type unifies\n//! vertex and index buffers and maintains their consistency.\n//!\n//! Note that only _composite_ vertex buffers are supported, in which each\n//! element of a vertex buffer completely describes all attributes of a vertex.\n//! Plexus does not support _component_ buffers, in which each attribute of a\n//! vertex is stored in a dedicated buffer.\n//!\n//! Plexus refers to independent vertex and index buffers as _raw buffers_. For\n//! example, a [`Vec`] of index data is a raw buffer and can be modified without\n//! regard to consistency with any particular vertex buffer. The\n//! [`FromRawBuffers`] trait provides a way to construct mesh data structures\n//! from such raw buffers.\n//!\n//! Index buffers may contain either _flat_ or _structured_ data. See the\n//! [`index`] module for more about these buffers and how they are defined.\n//!\n//! # Examples\n//!\n//! Generating a flat [`MeshBuffer`] from a [$uv$-sphere][`UvSphere`]:\n//!\n//! ```rust\n//! # extern crate decorum;\n//! # extern crate nalgebra;\n//! # extern crate plexus;\n//! #\n//! use decorum::R32;\n//! use nalgebra::Point3;\n//! use plexus::buffer::MeshBuffer3;\n//! use plexus::prelude::*;\n//! use plexus::primitive::generate::Position;\n//! use plexus::primitive::sphere::UvSphere;\n//!\n//! let buffer: MeshBuffer3<u32, Point3<f32>> = UvSphere::new(16, 16)\n//!     .polygons::<Position<Point3<R32>>>()\n//!     .triangulate()\n//!     .collect();\n//! let indices = buffer.as_index_slice();\n//! let positions = buffer.as_vertex_slice();\n//! ```\n//!\n//! Converting a [`MeshGraph`] to a structured [`MeshBuffer`]:\n//!\n//! ```rust\n//! # extern crate decorum;\n//! # extern crate nalgebra;\n//! # extern crate plexus;\n//! #\n//! use decorum::R64;\n//! use nalgebra::Point3;\n//! use plexus::buffer::MeshBufferN;\n//! use plexus::graph::MeshGraph;\n//! use plexus::prelude::*;\n//! use plexus::primitive::cube::Cube;\n//! use plexus::primitive::generate::Position;\n//!\n//! type E3 = Point3<R64>;\n//!\n//! let graph: MeshGraph<E3> = Cube::new().polygons::<Position<E3>>().collect();\n//! let buffer: MeshBufferN<usize, E3> = graph.to_mesh_by_vertex().unwrap();\n//! ```\n//!\n//! [`Vec`]: std::vec::Vec\n//! [`FromRawBuffers`]: crate::buffer::FromRawBuffers\n//! [`MeshBuffer`]: crate::buffer::MeshBuffer\n//! [`MeshGraph`]: crate::graph::MeshGraph\n//! [`index`]: crate::index\n//! [`UvSphere`]: crate::primitive::sphere::UvSphere\n\n// `MeshBuffer`s must convert and sum indices into their vertex data. Some of\n// these conversions may fail, but others are never expected to fail, because of\n// invariants enforced by `MeshBuffer`.\n//\n// Index types require `Unsigned` and `Vec` capacity is limited by word size\n// (the width of `usize`). An overflow cannot occur in some contexts, because a\n// consistent `MeshBuffer` cannot index into a `Vec` with an index larger than\n// its maximum addressable capacity (the maximum value that `usize` can\n// represent).\n\n// TODO: More consistently `expect` or `ok_or` index conversions and sums.\n\nmod builder;\n\nuse itertools::Itertools;\nuse num::{Integer, NumCast, Unsigned};\nuse std::fmt::Debug;\nuse std::hash::Hash;\nuse std::iter::FromIterator;\nuse std::vec;\nuse theon::adjunct::Map;\nuse thiserror::Error;\nuse typenum::{self, NonZero, Unsigned as _, U3, U4};\n\nuse crate::buffer::builder::BufferBuilder;\nuse crate::builder::{Buildable, MeshBuilder};\nuse crate::constant::{Constant, ToType, TypeOf};\nuse crate::encoding::{FaceDecoder, FromEncoding, VertexDecoder};\nuse crate::geometry::{FromGeometry, IntoGeometry};\nuse crate::index::{\n    BufferOf, Flat, Flat3, Flat4, FromIndexer, Grouping, HashIndexer, IndexBuffer, IndexOf,\n    IndexVertices, Indexer, Push,\n};\nuse crate::primitive::decompose::IntoVertices;\nuse crate::primitive::{\n    BoundedPolygon, IntoIndexed, IntoPolygons, Polygonal, Tetragon, Topological, Trigon,\n    UnboundedPolygon,\n};\nuse crate::{Arity, DynamicArity, MeshArity, Monomorphic, StaticArity, TryFromIterator};\n\n/// Errors concerning raw buffers and [`MeshBuffer`]s.\n///\n/// [`MeshBuffer`]: crate::buffer::MeshBuffer\n#[derive(Debug, Eq, Error, PartialEq)]\npub enum BufferError {\n    /// An index into vertex data is out of bounds.\n    ///\n    /// This error occurs when an index read from an index buffer is out of\n    /// bounds of the vertex buffer it indexes.\n    #[error(\"index into vertex data out of bounds\")]\n    IndexOutOfBounds,\n    /// The computation of an index causes an overflow.\n    ///\n    /// This error occurs if the result of computing an index overflows the type\n    /// used to represent indices. For example, if the elements of an index\n    /// buffer are `u8`s and an operation results in indices greater than\n    /// [`u8::MAX`], then this error will occur.\n    ///\n    /// [`u8::MAX`]: std::u8::MAX\n    #[error(\"index overflow\")]\n    IndexOverflow,\n    #[error(\"index buffer conflicts with arity\")]\n    /// The number of indices in a flat index buffer is incompatible with the\n    /// arity of the buffer.\n    ///\n    /// This error may occur if a flat index buffer contains a number of indices\n    /// that is indivisible by the arity of the topology it represents. For\n    /// example, this may error occur if a triangular index buffer contains a\n    /// number of indices that is not divisible by three.\n    IndexUnaligned,\n    /// The arity of a buffer or other data structure is not compatible with an\n    /// operation.\n    #[error(\"conflicting arity; expected {expected}, but got {actual}\")]\n    ArityConflict {\n        /// The expected arity.\n        expected: usize,\n        /// The incompatible arity that was encountered.\n        actual: usize,\n    },\n}\n\n/// Triangular [`MeshBuffer`].\n///\n/// The index buffer for this type contains [`Trigon`]s. For applications where\n/// a flat index buffer is necessary, consider [`IntoFlatIndex`] or the\n/// [`Flat3`] meta-grouping.\n///\n/// [`IntoFlatIndex`]: crate::buffer::IntoFlatIndex\n/// [`MeshBuffer`]: crate::buffer::MeshBuffer\n/// [`Flat3`]: crate::index::Flat3\n/// [`Trigon`]: crate::primitive::Trigon\npub type MeshBuffer3<N, G> = MeshBuffer<Trigon<N>, G>;\n\n/// Quadrilateral [`MeshBuffer`].\n///\n/// The index buffer for this type contains [`Tetragon`]s. For applications\n/// where a flat index buffer is necessary, consider [`IntoFlatIndex`] or the\n/// [`Flat4`] meta-grouping.\n///\n/// [`IntoFlatIndex`]: crate::buffer::IntoFlatIndex\n/// [`MeshBuffer`]: crate::buffer::MeshBuffer\n/// [`Flat4`]: crate::index::Flat4\n/// [`Tetragon`]: crate::primitive::Tetragon\npub type MeshBuffer4<N, G> = MeshBuffer<Tetragon<N>, G>;\n\n/// [`MeshBuffer`] that supports polygons with arbitrary [arity][`Arity`].\n///\n/// [`MeshBuffer`]: crate::buffer::MeshBuffer\n/// [`Arity`]: crate::Arity\npub type MeshBufferN<N, G> = MeshBuffer<UnboundedPolygon<N>, G>;\n\n/// Conversion from raw buffers.\npub trait FromRawBuffers<N, G>: Sized {\n    type Error: Debug;\n\n    /// Creates a type from raw buffers.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the raw buffers are inconsistent or the implementor\n    /// cannot be constructed from the buffers. The latter typically occurs if\n    /// the given topology is unsupported.\n    fn from_raw_buffers<I, J>(indices: I, vertices: J) -> Result<Self, Self::Error>\n    where\n        I: IntoIterator<Item = N>,\n        J: IntoIterator<Item = G>;\n}\n\n/// Conversion from raw buffers that do not encode their arity.\npub trait FromRawBuffersWithArity<N, G>: Sized {\n    type Error: Debug;\n\n    /// Creates a type from raw buffers with the given arity.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the raw buffers are inconsistent, the raw buffers\n    /// are incompatible with the given arity, or the implementor cannot be\n    /// constructed from the buffers. The latter typically occurs if the given\n    /// topology is unsupported.\n    fn from_raw_buffers_with_arity<I, J>(\n        indices: I,\n        vertices: J,\n        arity: usize,\n    ) -> Result<Self, Self::Error>\n    where\n        I: IntoIterator<Item = N>,\n        J: IntoIterator<Item = G>;\n}\n\n// TODO: Provide a similar trait for index buffers instead. `MeshBuffer` could\n//       use such a trait to provide this API.\npub trait IntoFlatIndex<G, const N: usize>\nwhere\n    Constant<N>: ToType,\n    TypeOf<N>: NonZero,\n{\n    type Item: Copy + Integer + Unsigned;\n\n    fn into_flat_index(self) -> MeshBuffer<Flat<Self::Item, N>, G>;\n}\n\n// TODO: Provide a similar trait for index buffers instead. `MeshBuffer` could\n//       use such a trait to provide this API.\npub trait IntoStructuredIndex<G>\nwhere\n    <Self::Item as Topological>::Vertex: Copy + Integer + Unsigned,\n{\n    type Item: Polygonal;\n\n    fn into_structured_index(self) -> MeshBuffer<Self::Item, G>;\n}\n\n/// Polygonal mesh composed of vertex and index buffers.\n///\n/// A `MeshBuffer` is a linear representation of a polygonal mesh that is\n/// composed of two separate but related linear buffers: an _index buffer_ and a\n/// _vertex buffer_. The index buffer contains ordered indices into the data in\n/// the vertex buffer and describes the topology of the mesh. The vertex buffer\n/// contains arbitrary data that describes each vertex.\n///\n/// `MeshBuffer` only explicitly respresents vertices via the vertex buffer and\n/// surfaces via the index buffer. There is no explicit representation of\n/// structures like edges and faces.\n///\n/// The `R` type parameter specifies the [`Grouping`] of the index buffer. See\n/// the [`index`] module documention for more information.\n///\n/// [`Grouping`]: crate::index::Grouping\n/// [`index`]: crate::index\n#[derive(Debug)]\npub struct MeshBuffer<R, G>\nwhere\n    R: Grouping,\n{\n    indices: Vec<R::Group>,\n    vertices: Vec<G>,\n}\n\nimpl<R, G> MeshBuffer<R, G>\nwhere\n    R: Grouping,\n    Vec<R::Group>: IndexBuffer<R>,\n{\n    pub(in crate::buffer) fn from_raw_buffers_unchecked(\n        indices: Vec<R::Group>,\n        vertices: Vec<G>,\n    ) -> Self {\n        MeshBuffer { indices, vertices }\n    }\n\n    /// Creates an empty `MeshBuffer`.\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// use plexus::buffer::MeshBuffer;\n    /// use plexus::index::Flat3;\n    ///\n    /// let buffer = MeshBuffer::<Flat3<u64>, (f64, f64, f64)>::new();\n    /// ```\n    pub fn new() -> Self {\n        Self::default()\n    }\n}\n\nimpl<R, G> MeshBuffer<R, G>\nwhere\n    R: Grouping,\n{\n    /// Converts a `MeshBuffer` into its index and vertex buffers.\n    pub fn into_raw_buffers(self) -> (Vec<R::Group>, Vec<G>) {\n        let MeshBuffer { indices, vertices } = self;\n        (indices, vertices)\n    }\n\n    /// Maps over the vertex data in a `MeshBuffer`.\n    ///\n    /// # Examples\n    ///\n    /// Translating the position data in a buffer:\n    ///\n    /// ```rust\n    /// # extern crate decorum;\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use decorum::R64;\n    /// use nalgebra::{Point3, Vector3};\n    /// use plexus::buffer::MeshBuffer3;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::generate::Position;\n    /// use plexus::primitive::sphere::UvSphere;\n    ///\n    /// let buffer: MeshBuffer3<usize, Point3<f64>> = UvSphere::new(16, 8)\n    ///     .polygons::<Position<Point3<R64>>>()\n    ///     .triangulate()\n    ///     .collect();\n    /// // Translate the positions.\n    /// let translation = Vector3::<f64>::x() * 2.0;\n    /// let buffer = buffer.map_vertices(|position| position + translation);\n    /// ```\n    pub fn map_vertices<H, F>(self, f: F) -> MeshBuffer<R, H>\n    where\n        F: FnMut(G) -> H,\n    {\n        let (indices, vertices) = self.into_raw_buffers();\n        MeshBuffer {\n            indices,\n            vertices: vertices.into_iter().map(f).collect::<Vec<_>>(),\n        }\n    }\n\n    /// Gets a slice over the index data.\n    pub fn as_index_slice(&self) -> &[R::Group] {\n        self.indices.as_slice()\n    }\n\n    /// Gets a slice over the vertex data.\n    pub fn as_vertex_slice(&self) -> &[G] {\n        self.vertices.as_slice()\n    }\n}\n\n/// Exposes a [`MeshBuilder`] that can be used to construct a [`MeshBuffer`]\n/// incrementally from _surfaces_ and _facets_.\n///\n/// Note that the facet data for [`MeshBuffer`] is always the unit type `()`.\n///\n/// See the documentation for the [`builder`] module.\n///\n/// # Examples\n///\n/// Creating a [`MeshBuffer`] from a triangle:\n///\n/// ```rust\n/// # extern crate nalgebra;\n/// # extern crate plexus;\n/// #\n/// use nalgebra::Point2;\n/// use plexus::buffer::MeshBuffer3;\n/// use plexus::builder::Buildable;\n/// use plexus::prelude::*;\n///\n/// let mut builder = MeshBuffer3::<usize, Point2<f64>>::builder();\n/// let buffer = builder\n///     .surface_with(|builder| {\n///         let a = builder.insert_vertex((0.0, 0.0))?;\n///         let b = builder.insert_vertex((1.0, 0.0))?;\n///         let c = builder.insert_vertex((0.0, 1.0))?;\n///         builder.facets_with(|builder| builder.insert_facet(&[a, b, c], ()))\n///     })\n///     .and_then(|_| builder.build())\n///     .unwrap();\n/// ```\n///\n/// [`MeshBuffer`]: crate::buffer::MeshBuffer\n/// [`MeshBuilder`]: crate::builder::MeshBuilder\n/// [`builder`]: crate::builder\nimpl<R, G> Buildable for MeshBuffer<R, G>\nwhere\n    R: Grouping,\n    Vec<R::Group>: IndexBuffer<R>,\n    BufferBuilder<R, G>: MeshBuilder<Error = BufferError, Commit = Self, Vertex = G, Facet = ()>,\n{\n    type Builder = BufferBuilder<R, G>;\n    type Error = BufferError;\n\n    type Vertex = G;\n    type Facet = ();\n\n    fn builder() -> Self::Builder {\n        BufferBuilder::default()\n    }\n}\n\nimpl<R, G> Default for MeshBuffer<R, G>\nwhere\n    R: Grouping,\n    Vec<R::Group>: IndexBuffer<R>,\n{\n    fn default() -> Self {\n        MeshBuffer {\n            indices: Default::default(),\n            vertices: Default::default(),\n        }\n    }\n}\n\nimpl<T, G, const N: usize> DynamicArity for MeshBuffer<Flat<T, N>, G>\nwhere\n    Constant<N>: ToType,\n    TypeOf<N>: NonZero,\n    T: Copy + Integer + Unsigned,\n{\n    type Dynamic = <Flat<T, N> as StaticArity>::Static;\n\n    fn arity(&self) -> Self::Dynamic {\n        Flat::<T, N>::ARITY\n    }\n}\n\nimpl<P, G> DynamicArity for MeshBuffer<P, G>\nwhere\n    P: Grouping + Monomorphic + Polygonal,\n    P::Vertex: Copy + Integer + Unsigned,\n{\n    type Dynamic = <P as StaticArity>::Static;\n\n    fn arity(&self) -> Self::Dynamic {\n        P::ARITY\n    }\n}\n\nimpl<N, G> DynamicArity for MeshBuffer<BoundedPolygon<N>, G>\nwhere\n    N: Copy + Integer + Unsigned,\n{\n    type Dynamic = MeshArity;\n\n    fn arity(&self) -> Self::Dynamic {\n        MeshArity::from_components::<BoundedPolygon<N>, _>(self.indices.iter())\n    }\n}\n\nimpl<N, G> DynamicArity for MeshBuffer<UnboundedPolygon<N>, G>\nwhere\n    N: Copy + Integer + Unsigned,\n{\n    type Dynamic = MeshArity;\n\n    fn arity(&self) -> Self::Dynamic {\n        MeshArity::from_components::<UnboundedPolygon<N>, _>(self.indices.iter())\n    }\n}\n\nimpl<R, G> Monomorphic for MeshBuffer<R, G> where R: Grouping + Monomorphic {}\n\nimpl<R, G> StaticArity for MeshBuffer<R, G>\nwhere\n    R: Grouping,\n{\n    type Static = <R as StaticArity>::Static;\n\n    const ARITY: Self::Static = R::ARITY;\n}\n\nimpl<T, G, const N: usize> MeshBuffer<Flat<T, N>, G>\nwhere\n    Constant<N>: ToType,\n    TypeOf<N>: NonZero,\n    T: Copy + Integer + NumCast + Unsigned,\n{\n    /// Appends the contents of a flat `MeshBuffer` into another `MeshBuffer`.\n    /// The source buffer is drained.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if an index overflows.\n    pub fn append<R, H>(&mut self, buffer: &mut MeshBuffer<R, H>) -> Result<(), BufferError>\n    where\n        G: FromGeometry<H>,\n        R: Grouping,\n        R::Group: Into<<Flat<T, N> as Grouping>::Group>,\n    {\n        let offset = T::from(self.vertices.len()).ok_or(BufferError::IndexOverflow)?;\n        self.vertices.extend(\n            buffer\n                .vertices\n                .drain(..)\n                .map(|vertex| vertex.into_geometry()),\n        );\n        self.indices\n            .extend(buffer.indices.drain(..).map(|index| index.into() + offset));\n        Ok(())\n    }\n}\n\nimpl<P, G> MeshBuffer<P, G>\nwhere\n    P: Grouping + Polygonal,\n    P::Vertex: Copy + Integer + NumCast + Unsigned,\n{\n    /// Appends the contents of a structured `MeshBuffer` into another\n    /// `MeshBuffer`. The source buffer is drained.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if an index overflows.\n    pub fn append<R, H>(&mut self, buffer: &mut MeshBuffer<R, H>) -> Result<(), BufferError>\n    where\n        G: FromGeometry<H>,\n        R: Grouping,\n        R::Group: Into<<P as Grouping>::Group>,\n        <P as Grouping>::Group:\n            Map<P::Vertex, Output = <P as Grouping>::Group> + Topological<Vertex = P::Vertex>,\n    {\n        let offset =\n            <P::Vertex as NumCast>::from(self.vertices.len()).ok_or(BufferError::IndexOverflow)?;\n        self.vertices.extend(\n            buffer\n                .vertices\n                .drain(..)\n                .map(|vertex| vertex.into_geometry()),\n        );\n        self.indices.extend(\n            buffer\n                .indices\n                .drain(..)\n                .map(|topology| topology.into().map(|index| index + offset)),\n        );\n        Ok(())\n    }\n}\n\nimpl<P, Q, T, R, N, G> From<P> for MeshBuffer<R, G>\nwhere\n    P: IntoIndexed<N, Indexed = Q> + Polygonal,\n    Q: Clone + Map<G, Output = T> + Map<N, Output = R> + Polygonal<Vertex = (N, P::Vertex)>,\n    T: Polygonal<Vertex = G>,\n    R: Grouping<Group = R> + Polygonal<Vertex = N>,\n    N: Copy + Integer + NumCast + Unsigned,\n    G: FromGeometry<P::Vertex>,\n{\n    fn from(polygon: P) -> Self {\n        let indexed = polygon.into_indexed();\n        MeshBuffer::from_raw_buffers(\n            // It is tempting to use a range over the polygon's arity to\n            // construct `R`, but that weakens the relationship between the\n            // input polygon `P` and the index buffer grouping `R`. These types\n            // must have compatible type-level arity, so this implementation\n            // relies on the `Map` implementation from `P` to `R`.\n            Some(indexed.clone().map(|(index, _)| index)),\n            Map::<G>::map(indexed, |(_, vertex)| vertex.into_geometry()),\n        )\n        .expect(\"inconsistent index buffer\")\n    }\n}\n\nimpl<E, P, G> FromEncoding<E> for MeshBuffer<P, G>\nwhere\n    E: FaceDecoder<Face = ()> + VertexDecoder,\n    E::Index: AsRef<[P::Vertex]>,\n    P: Polygonal<Vertex = usize>,\n    G: FromGeometry<E::Vertex>,\n    Self: FromRawBuffers<P, G, Error = BufferError>,\n{\n    type Error = <Self as FromRawBuffers<P, G>>::Error;\n\n    fn from_encoding(\n        vertices: <E as VertexDecoder>::Output,\n        faces: <E as FaceDecoder>::Output,\n    ) -> Result<Self, Self::Error> {\n        let indices: Vec<_> = faces\n            .into_iter()\n            .map(|(index, _)| {\n                P::try_from_slice(index.as_ref()).ok_or(BufferError::ArityConflict {\n                    expected: P::ARITY.into_interval().0,\n                    actual: index.as_ref().len(),\n                })\n            })\n            .collect::<Result<_, _>>()?;\n        let vertices = vertices.into_iter().map(|vertex| vertex.into_geometry());\n        MeshBuffer::from_raw_buffers(indices, vertices)\n    }\n}\n\nimpl<R, P, G> FromIndexer<P, P> for MeshBuffer<R, G>\nwhere\n    R: Grouping,\n    G: FromGeometry<P::Vertex>,\n    P: Map<IndexOf<R>> + Topological,\n    P::Output: Topological<Vertex = IndexOf<R>>,\n    BufferOf<R>: Push<R, P::Output>,\n    IndexOf<R>: NumCast,\n    Self: FromRawBuffers<R::Group, G>,\n{\n    type Error = <Self as FromRawBuffers<R::Group, G>>::Error;\n\n    fn from_indexer<I, M>(input: I, indexer: M) -> Result<Self, Self::Error>\n    where\n        I: IntoIterator<Item = P>,\n        M: Indexer<P, P::Vertex>,\n    {\n        let (indices, vertices) = input.into_iter().index_vertices(indexer);\n        MeshBuffer::<R, _>::from_raw_buffers(\n            indices,\n            vertices.into_iter().map(|vertex| vertex.into_geometry()),\n        )\n    }\n}\n\nimpl<R, P, G> FromIterator<P> for MeshBuffer<R, G>\nwhere\n    R: Grouping,\n    G: FromGeometry<P::Vertex>,\n    P: Topological,\n    P::Vertex: Copy + Eq + Hash,\n    BufferOf<R>: IndexBuffer<R>,\n    Self: FromIndexer<P, P>,\n{\n    fn from_iter<I>(input: I) -> Self\n    where\n        I: IntoIterator<Item = P>,\n    {\n        Self::from_indexer(input, HashIndexer::default()).unwrap_or_else(|_| Self::default())\n    }\n}\n\nimpl<T, U, G, H, const N: usize> FromRawBuffers<U, H> for MeshBuffer<Flat<T, N>, G>\nwhere\n    Constant<N>: ToType,\n    TypeOf<N>: NonZero,\n    T: Copy + Integer + NumCast + Unsigned,\n    U: Copy + Integer + NumCast + Unsigned,\n    G: FromGeometry<H>,\n{\n    type Error = BufferError;\n\n    /// Creates a flat `MeshBuffer` from raw index and vertex buffers.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the index data is out of bounds within the vertex\n    /// buffer or if the number of indices disagrees with the arity of the index\n    /// buffer.\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// # extern crate decorum;\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use decorum::R64;\n    /// use nalgebra::Point3;\n    /// use plexus::buffer::MeshBuffer;\n    /// use plexus::geometry::Vector;\n    /// use plexus::index::{Flat3, HashIndexer};\n    /// use plexus::prelude::*;\n    /// use plexus::primitive;\n    /// use plexus::primitive::cube::Cube;\n    /// use plexus::primitive::generate::{Normal, Position};\n    ///\n    /// type E3 = Point3<R64>;\n    /// type Vertex = (E3, Vector<E3>); // Position and normal.\n    ///\n    /// let cube = Cube::new();\n    /// let (indices, vertices) = primitive::zip_vertices((\n    ///     cube.polygons::<Position<E3>>(),\n    ///     cube.polygons::<Normal<E3>>()\n    ///         .map_vertices(|normal| normal.into_inner()),\n    /// ))\n    /// .triangulate()\n    /// .index_vertices::<Flat3, _>(HashIndexer::default());\n    /// let buffer = MeshBuffer::<Flat3, Vertex>::from_raw_buffers(indices, vertices).unwrap();\n    /// ```\n    fn from_raw_buffers<I, J>(indices: I, vertices: J) -> Result<Self, BufferError>\n    where\n        I: IntoIterator<Item = U>,\n        J: IntoIterator<Item = H>,\n    {\n        let indices = indices\n            .into_iter()\n            .map(|index| <T as NumCast>::from(index).ok_or(BufferError::IndexOverflow))\n            .collect::<Result<Vec<_>, _>>()?;\n        if indices.len() % N != 0 {\n            Err(BufferError::IndexUnaligned)\n        }\n        else {\n            let vertices: Vec<_> = vertices\n                .into_iter()\n                .map(|vertex| vertex.into_geometry())\n                .collect();\n            let len = T::from(vertices.len()).unwrap();\n            if indices.iter().any(|index| *index >= len) {\n                Err(BufferError::IndexOutOfBounds)\n            }\n            else {\n                Ok(MeshBuffer { indices, vertices })\n            }\n        }\n    }\n}\n\nimpl<P, Q, G, H> FromRawBuffers<Q, H> for MeshBuffer<P, G>\nwhere\n    P: From<Q> + Grouping<Group = P> + Polygonal,\n    P::Vertex: Copy + Integer + NumCast + Unsigned,\n    G: FromGeometry<H>,\n{\n    type Error = BufferError;\n\n    /// Creates a structured `MeshBuffer` from raw index and vertex buffers.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the index data is out of bounds within the vertex\n    /// buffer.\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use nalgebra::Point3;\n    /// use plexus::buffer::MeshBufferN;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::generate::Position;\n    /// use plexus::primitive::sphere::UvSphere;\n    ///\n    /// type E3 = Point3<f64>;\n    ///\n    /// let sphere = UvSphere::new(8, 8);\n    /// let buffer = MeshBufferN::<usize, E3>::from_raw_buffers(\n    ///     sphere.indexing_polygons::<Position>(),\n    ///     sphere.vertices::<Position<E3>>(),\n    /// )\n    /// .unwrap();\n    /// ```\n    fn from_raw_buffers<I, J>(indices: I, vertices: J) -> Result<Self, BufferError>\n    where\n        I: IntoIterator<Item = Q>,\n        J: IntoIterator<Item = H>,\n    {\n        let indices: Vec<_> = indices.into_iter().map(P::from).collect();\n        let vertices: Vec<_> = vertices\n            .into_iter()\n            .map(|vertex| vertex.into_geometry())\n            .collect();\n        let is_out_of_bounds = {\n            let len =\n                <P::Vertex as NumCast>::from(vertices.len()).ok_or(BufferError::IndexOverflow)?;\n            indices\n                .iter()\n                .any(|polygon| polygon.as_ref().iter().any(|index| *index >= len))\n        };\n        if is_out_of_bounds {\n            Err(BufferError::IndexOutOfBounds)\n        }\n        else {\n            Ok(MeshBuffer { indices, vertices })\n        }\n    }\n}\n\nimpl<T, G, const N: usize> IntoFlatIndex<G, N> for MeshBuffer<Flat<T, N>, G>\nwhere\n    Constant<N>: ToType,\n    TypeOf<N>: NonZero,\n    T: Copy + Integer + Unsigned,\n{\n    type Item = T;\n\n    fn into_flat_index(self) -> MeshBuffer<Flat<Self::Item, N>, G> {\n        self\n    }\n}\n\nimpl<N, G> IntoFlatIndex<G, 3> for MeshBuffer<Trigon<N>, G>\nwhere\n    N: Copy + Integer + Unsigned,\n{\n    type Item = N;\n\n    /// Converts the index buffer of a `MeshBuffer` from structured data into\n    /// flat data.\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use nalgebra::Point3;\n    /// use plexus::buffer::MeshBuffer;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::cube::Cube;\n    /// use plexus::primitive::generate::Position;\n    /// use plexus::primitive::Trigon;\n    ///\n    /// type E3 = Point3<f32>;\n    ///\n    /// let cube = Cube::new();\n    /// let buffer = MeshBuffer::<Trigon<usize>, E3>::from_raw_buffers(\n    ///     cube.indexing_polygons::<Position>().triangulate(),\n    ///     cube.vertices::<Position<E3>>(),\n    /// )\n    /// .unwrap();\n    /// let buffer = buffer.into_flat_index();\n    /// for index in buffer.as_index_slice() {\n    ///     // ...\n    /// }\n    /// ```\n    fn into_flat_index(self) -> MeshBuffer<Flat<Self::Item, 3>, G> {\n        let MeshBuffer { indices, vertices } = self;\n        MeshBuffer {\n            indices: indices\n                .into_iter()\n                .flat_map(|trigon| trigon.into_vertices())\n                .collect(),\n            vertices,\n        }\n    }\n}\n\nimpl<N, G> IntoFlatIndex<G, 4> for MeshBuffer<Tetragon<N>, G>\nwhere\n    N: Copy + Integer + Unsigned,\n{\n    type Item = N;\n\n    /// Converts the index buffer of a `MeshBuffer` from flat data into\n    /// structured data.\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use nalgebra::Point3;\n    /// use plexus::buffer::MeshBuffer;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::cube::Cube;\n    /// use plexus::primitive::generate::Position;\n    /// use plexus::primitive::Tetragon;\n    ///\n    /// type E3 = Point3<f64>;\n    ///\n    /// let cube = Cube::new();\n    /// let buffer = MeshBuffer::<Tetragon<usize>, E3>::from_raw_buffers(\n    ///     cube.indexing_polygons::<Position>(),\n    ///     cube.vertices::<Position<E3>>(),\n    /// )\n    /// .unwrap();\n    /// let buffer = buffer.into_flat_index();\n    /// for index in buffer.as_index_slice() {\n    ///     // ...\n    /// }\n    /// ```\n    fn into_flat_index(self) -> MeshBuffer<Flat<Self::Item, 4>, G> {\n        let MeshBuffer { indices, vertices } = self;\n        MeshBuffer {\n            indices: indices\n                .into_iter()\n                .flat_map(|tetragon| tetragon.into_vertices())\n                .collect(),\n            vertices,\n        }\n    }\n}\n\nimpl<N, G> IntoPolygons for MeshBuffer<Flat3<N>, G>\nwhere\n    N: Copy + Integer + NumCast + Unsigned,\n    G: Clone,\n    Trigon<N>: Grouping<Group = Trigon<N>>,\n{\n    type Output = vec::IntoIter<Self::Polygon>;\n    type Polygon = Trigon<G>;\n\n    /// Converts a triangular flat `MeshBuffer` into an iterator of [`Trigon`]s\n    /// containing vertex data.\n    ///\n    /// [`Trigon`]: crate::primitive::Trigon\n    fn into_polygons(self) -> Self::Output {\n        let (indices, vertices) = self.into_raw_buffers();\n        indices\n            .into_iter()\n            .chunks(U3::USIZE)\n            .into_iter()\n            .map(|chunk| {\n                // These conversions should never fail.\n                Trigon::try_from_iter(chunk.map(|index| {\n                    let index = <usize as NumCast>::from(index).expect(\"index overflow\");\n                    vertices[index].clone()\n                }))\n                .expect(\"inconsistent index buffer\")\n            })\n            .collect::<Vec<_>>()\n            .into_iter()\n    }\n}\n\nimpl<N, G> IntoPolygons for MeshBuffer<Flat4<N>, G>\nwhere\n    N: Copy + Integer + NumCast + Unsigned,\n    G: Clone,\n    Trigon<N>: Grouping<Group = Trigon<N>>,\n{\n    type Output = vec::IntoIter<Self::Polygon>;\n    type Polygon = Tetragon<G>;\n\n    /// Converts a quadrilateral flat `MeshBuffer` into an iterator of\n    /// [`Tetragon`]s containing vertex data.\n    ///\n    /// # Examples\n    ///\n    /// Mapping over the polygons described by a flat buffer:\n    ///\n    /// ```rust\n    /// # extern crate decorum;\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use decorum::R64;\n    /// use nalgebra::Point3;\n    /// use plexus::buffer::MeshBuffer;\n    /// use plexus::graph::MeshGraph;\n    /// use plexus::index::Flat4;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::cube::Cube;\n    /// use plexus::primitive::generate::Position;\n    ///\n    /// type E3 = Point3<R64>;\n    ///\n    /// let buffer: MeshBuffer<Flat4, E3> = Cube::new().polygons::<Position<E3>>().collect();\n    /// let graph: MeshGraph<E3> = buffer\n    ///     .into_polygons()\n    ///     .map_vertices(|position| position * R64::assert(2.0))\n    ///     .collect();\n    /// ```\n    ///\n    /// [`Tetragon`]: crate::primitive::Tetragon\n    fn into_polygons(self) -> Self::Output {\n        let (indices, vertices) = self.into_raw_buffers();\n        indices\n            .into_iter()\n            .chunks(U4::USIZE)\n            .into_iter()\n            .map(|chunk| {\n                // These conversions should never fail.\n                Tetragon::try_from_iter(chunk.map(|index| {\n                    let index = <usize as NumCast>::from(index).expect(\"index overflow\");\n                    vertices[index].clone()\n                }))\n                .expect(\"inconsistent index buffer\")\n            })\n            .collect::<Vec<_>>()\n            .into_iter()\n    }\n}\n\nimpl<P, G> IntoPolygons for MeshBuffer<P, G>\nwhere\n    P: Grouping + Polygonal,\n    P::Group: Map<G> + Polygonal,\n    <P::Group as Map<G>>::Output: Polygonal<Vertex = G>,\n    <P::Group as Topological>::Vertex: NumCast,\n    P::Vertex: Copy + Integer + NumCast + Unsigned,\n    G: Clone,\n{\n    type Output = vec::IntoIter<Self::Polygon>;\n    type Polygon = <P::Group as Map<G>>::Output;\n\n    /// Converts a structured `MeshBuffer` into an iterator of polygons\n    /// containing vertex data.\n    ///\n    /// # Examples\n    ///\n    /// Mapping over the polygons described by a structured buffer:\n    ///\n    /// ```rust\n    /// # extern crate decorum;\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use decorum::R64;\n    /// use nalgebra::Point3;\n    /// use plexus::buffer::MeshBuffer;\n    /// use plexus::graph::MeshGraph;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::generate::Position;\n    /// use plexus::primitive::sphere::UvSphere;\n    /// use plexus::primitive::BoundedPolygon;\n    ///\n    /// type E3 = Point3<R64>;\n    ///\n    /// let buffer: MeshBuffer<BoundedPolygon<usize>, E3> =\n    ///     UvSphere::new(8, 8).polygons::<Position<E3>>().collect();\n    /// let graph: MeshGraph<E3> = buffer\n    ///     .into_polygons()\n    ///     .map_vertices(|position| position * R64::assert(2.0))\n    ///     .triangulate()\n    ///     .collect();\n    /// ```\n    fn into_polygons(self) -> Self::Output {\n        let (indices, vertices) = self.into_raw_buffers();\n        indices\n            .into_iter()\n            .map(|polygon| {\n                polygon.map(|index| {\n                    // This conversion should never fail.\n                    let index = <usize as NumCast>::from(index).expect(\"index overflow\");\n                    vertices[index].clone()\n                })\n            })\n            .collect::<Vec<_>>()\n            .into_iter()\n    }\n}\n\nimpl<P, G> IntoStructuredIndex<G> for MeshBuffer<P, G>\nwhere\n    P: Grouping + Polygonal,\n    P::Vertex: Copy + Integer + Unsigned,\n{\n    type Item = P;\n\n    fn into_structured_index(self) -> MeshBuffer<Self::Item, G> {\n        self\n    }\n}\n\nimpl<N, G> IntoStructuredIndex<G> for MeshBuffer<Flat3<N>, G>\nwhere\n    N: Copy + Integer + Unsigned,\n    Trigon<N>: Grouping<Group = Trigon<N>>,\n{\n    type Item = Trigon<N>;\n\n    /// Converts the index buffer of a `MeshBuffer` from flat data into\n    /// structured data.\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use nalgebra::Point3;\n    /// use plexus::buffer::MeshBuffer;\n    /// use plexus::index::Flat3;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::cube::Cube;\n    /// use plexus::primitive::generate::Position;\n    ///\n    /// type E3 = Point3<f64>;\n    ///\n    /// let cube = Cube::new();\n    /// let buffer = MeshBuffer::<Flat3, E3>::from_raw_buffers(\n    ///     cube.indexing_polygons::<Position>()\n    ///         .triangulate()\n    ///         .vertices(),\n    ///     cube.vertices::<Position<E3>>(),\n    /// )\n    /// .unwrap();\n    /// let buffer = buffer.into_structured_index();\n    /// for trigon in buffer.as_index_slice() {\n    ///     // ...\n    /// }\n    /// ```\n    fn into_structured_index(self) -> MeshBuffer<Self::Item, G> {\n        let MeshBuffer { indices, vertices } = self;\n        let indices = indices\n            .into_iter()\n            .chunks(U3::USIZE)\n            .into_iter()\n            .map(<Self::Item as Grouping>::Group::try_from_iter)\n            .collect::<Result<Vec<_>, _>>()\n            .expect(\"inconsistent index buffer\");\n        MeshBuffer { indices, vertices }\n    }\n}\n\nimpl<N, G> IntoStructuredIndex<G> for MeshBuffer<Flat4<N>, G>\nwhere\n    N: Copy + Integer + Unsigned,\n    Tetragon<N>: Grouping<Group = Tetragon<N>>,\n{\n    type Item = Tetragon<N>;\n\n    /// Converts the index buffer of a `MeshBuffer` from flat data into\n    /// structured data.\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use nalgebra::Point3;\n    /// use plexus::buffer::MeshBuffer4;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::cube::Cube;\n    /// use plexus::primitive::generate::Position;\n    ///\n    /// type E3 = Point3<f64>;\n    ///\n    /// let cube = Cube::new();\n    /// let buffer = MeshBuffer4::<usize, E3>::from_raw_buffers(\n    ///     cube.indexing_polygons::<Position>(),\n    ///     cube.vertices::<Position<E3>>(),\n    /// )\n    /// .unwrap();\n    /// let buffer = buffer.into_structured_index();\n    /// for tetragon in buffer.as_index_slice() {\n    ///     // ...\n    /// }\n    /// ```\n    fn into_structured_index(self) -> MeshBuffer<Self::Item, G> {\n        let MeshBuffer { indices, vertices } = self;\n        let indices = indices\n            .into_iter()\n            .chunks(U4::USIZE)\n            .into_iter()\n            .map(<Self::Item as Grouping>::Group::try_from_iter)\n            .collect::<Result<Vec<_>, _>>()\n            .expect(\"inconsistent index buffer\");\n        MeshBuffer { indices, vertices }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use decorum::R64;\n    use nalgebra::Point3;\n\n    use crate::buffer::{MeshBuffer, MeshBuffer4, MeshBufferN};\n    use crate::graph::MeshGraph;\n    use crate::index::Flat3;\n    use crate::prelude::*;\n    use crate::primitive::cube::Cube;\n    use crate::primitive::generate::Position;\n    use crate::primitive::sphere::UvSphere;\n    use crate::primitive::{BoundedPolygon, UnboundedPolygon};\n\n    type E3 = Point3<R64>;\n\n    #[test]\n    fn collect_into_flat_buffer() {\n        let buffer: MeshBuffer<Flat3<usize>, E3> = UvSphere::new(3, 2)\n            .polygons::<Position<E3>>() // 6 triangles, 18 vertices.\n            .triangulate()\n            .collect();\n\n        assert_eq!(18, buffer.as_index_slice().len());\n        assert_eq!(5, buffer.as_vertex_slice().len());\n    }\n\n    #[test]\n    fn collect_into_bounded_buffer() {\n        let buffer: MeshBuffer<BoundedPolygon<usize>, E3> = UvSphere::new(3, 2)\n            .polygons::<Position<E3>>() // 6 triangles, 18 vertices.\n            .collect();\n\n        assert_eq!(6, buffer.as_index_slice().len());\n        assert_eq!(5, buffer.as_vertex_slice().len());\n    }\n\n    #[test]\n    fn collect_into_unbounded_buffer() {\n        let buffer: MeshBuffer<UnboundedPolygon<usize>, E3> =\n            Cube::new().polygons::<Position<E3>>().collect();\n\n        assert_eq!(6, buffer.as_index_slice().len());\n        assert_eq!(8, buffer.as_vertex_slice().len());\n        for polygon in buffer.as_index_slice() {\n            assert_eq!(4, polygon.arity());\n        }\n    }\n\n    #[test]\n    fn append_structured_buffers() {\n        let mut buffer: MeshBufferN<usize, E3> = UvSphere::new(3, 2)\n            .polygons::<Position<E3>>() // 6 triangles, 18 vertices.\n            .collect();\n        buffer\n            .append(\n                &mut Cube::new()\n                    .polygons::<Position<E3>>() // 6 quadrilaterals, 24 vertices.\n                    .collect::<MeshBuffer4<usize, E3>>(),\n            )\n            .unwrap();\n\n        assert_eq!(12, buffer.as_index_slice().len());\n        assert_eq!(13, buffer.as_vertex_slice().len());\n    }\n\n    #[test]\n    fn convert_mesh_to_buffer_by_vertex() {\n        let graph: MeshGraph<E3> = UvSphere::new(3, 2)\n            .polygons::<Position<E3>>() // 6 triangles, 18 vertices.\n            .collect();\n        let buffer: MeshBufferN<usize, E3> = graph.to_mesh_by_vertex().unwrap();\n\n        assert_eq!(6, buffer.as_index_slice().len());\n        assert_eq!(5, buffer.as_vertex_slice().len());\n    }\n\n    #[test]\n    fn convert_mesh_to_buffer_by_face() {\n        let graph: MeshGraph<E3> = UvSphere::new(3, 2)\n            .polygons::<Position<E3>>() // 6 triangles, 18 vertices.\n            .collect();\n        let buffer: MeshBufferN<usize, E3> = graph.to_mesh_by_face().unwrap();\n\n        assert_eq!(6, buffer.as_index_slice().len());\n        assert_eq!(18, buffer.as_vertex_slice().len());\n    }\n}\n"
  },
  {
    "path": "plexus/src/builder.rs",
    "content": "//! Incremental polygonal mesh construction.\n//!\n//! This module provides traits for incrementally constructing mesh data\n//! structures. This API allows for meshes to be constructed in a way that is\n//! agnostic to the specific data structure used to represent the mesh.\n//!\n//! [`Buildable`] is the primary trait of this API. It is implemented by mesh\n//! data structures and exposes various associated types for their associated\n//! data.  [`Buildable`] exposes a builder type via its\n//! [`builder`][`Buildable::builder`] function. This builder type in turn\n//! provides additional builders that can be used to construct a mesh from\n//! _surfaces_ and _facets_.\n//!\n//! # Examples\n//!\n//! A function that generates a triangle from point geometry using builders:\n//!\n//! ```rust\n//! # extern crate nalgebra;\n//! # extern crate plexus;\n//! #\n//! use nalgebra::Point2;\n//! use plexus::buffer::MeshBuffer3;\n//! use plexus::builder::Buildable;\n//! use plexus::geometry::FromGeometry;\n//! use plexus::graph::MeshGraph;\n//! use plexus::prelude::*;\n//!\n//! type E2 = Point2<f64>;\n//!\n//! fn trigon<B, T>(points: [T; 3]) -> Result<B, B::Error>\n//! where\n//!     B: Buildable,\n//!     B::Vertex: FromGeometry<T>,\n//! {\n//!     let mut builder = B::builder();\n//!     builder.surface_with(|builder| {\n//!         let [a, b, c] = points;\n//!         let a = builder.insert_vertex(a)?;\n//!         let b = builder.insert_vertex(b)?;\n//!         let c = builder.insert_vertex(c)?;\n//!         builder.facets_with(|builder| builder.insert_facet(&[a, b, c], B::Facet::default()))\n//!     })?;\n//!     builder.build()\n//! }\n//!\n//! // `MeshBuffer` and `MeshGraph` implement the `Buildable` trait.\n//! let graph: MeshGraph<E2> = trigon([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0)]).unwrap();\n//! let buffer: MeshBuffer3<usize, E2> = trigon([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0)]).unwrap();\n//! ```\n//!\n//! [`Buildable::builder`]: crate::builder::Buildable::builder\n//! [`Buildable`]: crate::builder::Buildable\n\n// TODO: Is it useful to use a separate `FacetBuilder` type?\n// TODO: Keys are not opaque. Especially for `MeshBuffer`, it may be possible to\n//       \"forge\" keys. This could be prevented by using a wrapper type that is\n//       not exported, but would introduce a performance cost to map and collect\n//       slices of keys.\n\nuse std::fmt::Debug;\nuse std::hash::Hash;\n\nuse crate::geometry::FromGeometry;\nuse crate::transact::ClosedInput;\n\n/// Polygonal mesh data structure that can be built incrementally.\n///\n/// This trait is the primary entrypoint into the builder API. Types that\n/// implement this trait expose a [`MeshBuilder`] that can be used to construct\n/// an instance of the type from surfaces and facets.\n///\n/// [`MeshBuilder`]: crate::builder::MeshBuilder\npub trait Buildable: Sized {\n    type Builder: MeshBuilder<\n        Commit = Self,\n        Error = Self::Error,\n        Vertex = Self::Vertex,\n        Facet = Self::Facet,\n    >;\n    type Error: Debug;\n\n    /// Vertex data.\n    ///\n    /// This type represents the data associated with vertices in the mesh.\n    /// This typically includes positional data, but no data is required and\n    /// this type may be the unit type `()`.\n    ///\n    /// Each builder trait also exposes such an associated type which is\n    /// constrained by the `Builder` type.\n    type Vertex;\n    /// Facet data.\n    ///\n    /// This type represents the data associated with facets in the mesh. No\n    /// data is required and this type may be the unit type `()`.\n    ///\n    /// Each builder trait also exposes such an associated type which is\n    /// constrained by the `Builder` type.\n    type Facet: Default;\n\n    fn builder() -> Self::Builder;\n}\n\n/// Incremental polygonal mesh builder.\n///\n/// This trait exposes types that allow for mesh data structures to be\n/// constructed incrementally from _surfaces_ and _facets_. A _surface_ is a\n/// collection of vertices and facets connecting those vertices and typically\n/// describes a _manifold_. A _facet_ is the connectivity between vertices in a\n/// surface. Facets may also include associated data.\n///\n/// Construction is hierarchical, beginning with a surface and its vertices and\n/// then facets. The association between a surface, its vertices, and facets is\n/// enforced by the API, which accepts functions that operate on increasingly\n/// specific builder types. The [`build`][`MeshBuilder::build`] function is used\n/// to complete the construction of a mesh.\n///\n/// Builders may emit errors at any stage and errors depend on the\n/// implementation of the builder types (and by extension the details of the\n/// underlying data structure).\n///\n/// [`MeshBuilder::build`]: crate::builder::MeshBuilder::build\npub trait MeshBuilder: ClosedInput {\n    type Builder: SurfaceBuilder<Error = Self::Error, Vertex = Self::Vertex, Facet = Self::Facet>;\n\n    type Vertex;\n    type Facet: Default;\n\n    /// Constructs a surface.\n    ///\n    /// The given function is invoked with a [`SurfaceBuilder`], which can be\n    /// used to insert vertices and construct facets.\n    ///\n    /// [`SurfaceBuilder`]: crate::builder::SurfaceBuilder\n    fn surface_with<F, T, E>(&mut self, f: F) -> Result<T, Self::Error>\n    where\n        Self::Error: From<E>,\n        F: FnOnce(&mut Self::Builder) -> Result<T, E>;\n\n    /// Builds the mesh.\n    ///\n    /// The builder is consumed and a mesh with the constructed surfaces and\n    /// facets is produced.\n    ///\n    /// # Errors\n    ///\n    /// Returns a latent error if the constructed surfaces and facets are\n    /// incompatible with the underlying data structure. May return other\n    /// errors depending on the details of the implementation.\n    fn build(self) -> Result<Self::Commit, Self::Error> {\n        self.commit().map_err(|(_, error)| error)\n    }\n}\n\npub trait SurfaceBuilder: ClosedInput {\n    type Builder: FacetBuilder<Self::Key, Error = Self::Error, Facet = Self::Facet>;\n    /// Vertex key.\n    ///\n    /// Each vertex is associated with a key of this type. This key is used to\n    /// reference a given vertex and is required to insert faces with a\n    /// [`FacetBuilder`].\n    ///\n    /// [`FacetBuilder`]: crate::builder::FacetBuilder\n    type Key: Copy + Eq + Hash;\n\n    type Vertex;\n    type Facet: Default;\n\n    /// Constructs facets in the surface.\n    ///\n    /// The given function is invoked with a [`FacetBuilder`], which can be used\n    /// to insert facets.\n    ///\n    /// [`FacetBuilder`]: crate::builder::FacetBuilder\n    fn facets_with<F, T, E>(&mut self, f: F) -> Result<T, Self::Error>\n    where\n        Self::Error: From<E>,\n        F: FnOnce(&mut Self::Builder) -> Result<T, E>;\n\n    /// Inserts a vertex into the surface.\n    ///\n    /// Returns a key that refers to the inserted vertex. This key can be used\n    /// to insert facets with a [`FacetBuilder`].\n    ///\n    /// [`FacetBuilder`]: crate::builder::FacetBuilder\n    fn insert_vertex<T>(&mut self, data: T) -> Result<Self::Key, Self::Error>\n    where\n        Self::Vertex: FromGeometry<T>;\n}\n\npub trait FacetBuilder<K>: ClosedInput\nwhere\n    K: Eq + Hash,\n{\n    /// Facet key.\n    ///\n    /// Each facet is associated with a key of this type.\n    type Key: Copy + Eq + Hash;\n\n    type Facet: Default;\n\n    /// Inserts a facet into the associated surface.\n    ///\n    /// A facet is formed from connectivity between vertices represented by an\n    /// ordered slice of vertex keys from the associated [`SurfaceBuilder`].\n    ///\n    /// Returns a key that refers to the inserted facet.\n    ///\n    /// [`SurfaceBuilder`]: crate::builder::SurfaceBuilder\n    fn insert_facet<T, U>(&mut self, keys: T, data: U) -> Result<Self::Key, Self::Error>\n    where\n        Self::Facet: FromGeometry<U>,\n        T: AsRef<[K]>;\n}\n"
  },
  {
    "path": "plexus/src/constant.rs",
    "content": "//! Morphisms between constant generics and numeric types.\n//!\n//! This module provides conversions between `typenum`'s unsigned integer types\n//! and `usize` constant generics. These conversions are necessary to perform\n//! static computations and comparisons, which cannot yet be done using constant\n//! generics alone at the time of writing (e.g., `{N >= 3}`).\n//!\n//! See discussion on the [Rust internals\n//! forum](https://internals.rust-lang.org/t/const-generics-where-restrictions/12742/7).\n\n// TODO: Move this into the `theon` crate as part of its public API.\n\npub type ConstantOf<N> = <N as ToConstant>::Output;\npub type TypeOf<const N: usize> = <Constant<N> as ToType>::Output;\n\npub struct Constant<const N: usize>;\n\npub trait ToConstant {\n    type Output;\n}\n\npub trait ToType {\n    type Output;\n}\n\nmacro_rules! impl_morphisms {\n    (types => $($n:ident),*$(,)?) => (\n        use typenum::Unsigned;\n\n        $(\n            impl ToConstant for typenum::$n {\n                type Output = Constant<{ typenum::$n::USIZE }>;\n            }\n\n            impl ToType for Constant<{ typenum::$n::USIZE }> {\n                type Output = typenum::$n;\n            }\n        )*\n    );\n}\nimpl_morphisms!(types =>\n    U0, U1, U2, U3, U4, U5, U6, U7, U8, U9, U10, U11, U12, U13, U14, U15, U16, U17, U18, U19, U21,\n    U22, U23, U24, U25, U26, U27, U28, U29, U30, U31, U32,\n);\n"
  },
  {
    "path": "plexus/src/encoding/mod.rs",
    "content": "//! Serialization and encodings.\n//!\n//! This module provides encoding support enabled via Cargo features. Each\n//! enabled encoding has a corresponding sub-module. For example, when [PLY]\n//! support is enabled, the `ply` module is exposed. The following table\n//! summarizes the encodings supported by Plexus:\n//!\n//! | Feature        | Default | Encoding | Read | Write |\n//! |----------------|---------|----------|------|-------|\n//! | `encoding-ply` | No      | [PLY]    | Yes  | No    |\n//!\n//! This module provides traits used by all encodings. These traits describe the\n//! outputs and inputs of decoders and encoders, respectively. Generally, these\n//! traits should **not** be used directly. Instead, prefer the conversion\n//! traits exposed for specific encodings, such as `FromPly` when using [PLY].\n//!\n//! [PLY]: https://en.wikipedia.org/wiki/ply_(file_format)\n\npub mod ply;\n\nuse std::fmt::Debug;\n\npub trait VertexDecoder {\n    type Output: IntoIterator<Item = Self::Vertex>;\n    type Vertex;\n}\n\npub trait FaceDecoder {\n    type Output: IntoIterator<Item = (Self::Index, Self::Face)>;\n    type Index: IntoIterator<Item = usize>;\n    type Face;\n}\n\n// TODO: This trait is a bit limiting. Consider implementing more specific\n//       traits like `FromPly` directly. This could allow more specific\n//       features to be supported, such as edge geometry for `MeshGraph`s.\npub trait FromEncoding<E>: Sized\nwhere\n    E: FaceDecoder + VertexDecoder,\n{\n    type Error: Debug;\n\n    fn from_encoding(\n        vertices: <E as VertexDecoder>::Output,\n        faces: <E as FaceDecoder>::Output,\n    ) -> Result<Self, Self::Error>;\n}\n"
  },
  {
    "path": "plexus/src/encoding/ply.rs",
    "content": "//! [PLY] encoding.\n//!\n//! This module provides support for the [PLY] format via the [`FromPly`] and\n//! [`ToPly`] traits. These traits can be used with a decoder and encoder to\n//! read and write mesh data structures to and from the [PLY] format.\n//!\n//! [PLY] support is implemented using the [`ply-rs`] crate and some of its\n//! types are re-exported here.\n//!\n//! # Examples\n//!\n//! Reading a [PLY] file into a [`MeshGraph`]:\n//!\n//! ```rust\n//! # extern crate nalgebra;\n//! # extern crate plexus;\n//! #\n//! use nalgebra::Point3;\n//! use plexus::encoding::ply::{FromPly, PositionEncoding};\n//! use plexus::graph::MeshGraph;\n//! use std::io::Read;\n//!\n//! type E3 = Point3<f64>;\n//!\n//! // Read from a file, network, etc.\n//! fn read() -> impl Read {\n//!     // ...\n//!     # let ply: &[u8] = include_bytes!(\"../../../data/cube.ply\");\n//!     # ply\n//! }\n//!\n//! let encoding = PositionEncoding::<E3>::default();\n//! let (graph, _) = MeshGraph::<E3>::from_ply(encoding, read()).unwrap();\n//! ```\n//!\n//! [PLY]: https://en.wikipedia.org/wiki/PLY_(file_format)\n//!\n//! [`ply-rs`]: https://crates.io/crates/ply-rs\n//!\n//! [`FromPly`]: crate::encoding::ply::FromPly\n//! [`ToPly`]: crate::encoding::ply::ToPly\n//! [`MeshGraph`]: crate::graph::MeshGraph\n\n#![cfg(feature = \"encoding-ply\")]\n\nuse num::cast;\nuse num::NumCast;\nuse ply_rs::parser::Parser;\nuse ply_rs::ply::KeyMap;\nuse smallvec::SmallVec;\nuse std::io::{self, Read, Write};\nuse std::iter::FromIterator;\nuse std::marker::PhantomData;\nuse theon::space::{EuclideanSpace, FiniteDimensional};\nuse thiserror::Error;\nuse typenum::{NonZero, Unsigned, U2, U3};\n\nuse crate::encoding::{FaceDecoder, FromEncoding, VertexDecoder};\n\npub use ply_rs::ply::{\n    ElementDef as ElementDefinition, Property, PropertyDef as PropertyDefinition, PropertyType,\n};\n\n// TODO: These traits only allow a single element to be read for each topology\n//       (vertices, faces, etc.). It may be useful to allow code to aggregate\n//       various elements to produce an output for a single topology.\n// TODO: Consider using the newtype pattern to hide underlying types and expose\n//       a smaller and more tailored API surface.\n\npub type Header = KeyMap<ElementDefinition>;\npub type Payload = KeyMap<Vec<Element>>;\npub type Element = KeyMap<Property>;\n\npub struct Ply {\n    pub header: Header,\n    pub payload: Payload,\n}\n\nimpl Ply {\n    pub fn parse(mut read: impl Read) -> io::Result<Self> {\n        Parser::<Element>::new().read_ply(&mut read).map(|ply| Ply {\n            header: ply.header.elements,\n            payload: ply.payload,\n        })\n    }\n}\n\n/// Errors concerning the [PLY] encoding.\n///\n/// [PLY]: https://en.wikipedia.org/wiki/PLY_(file_format)\n#[derive(Debug, Error)]\npub enum PlyError {\n    #[error(\"required element not found\")]\n    ElementNotFound,\n    #[error(\"required property not found\")]\n    PropertyNotFound,\n    /// The type of a property conflicts with a decoding.\n    #[error(\"conflicting property type found\")]\n    PropertyTypeConflict,\n    /// A polygonal mesh data structure is not compatible with encoded PLY data.\n    #[error(\"encoding operation failed\")]\n    EncodingIncompatible,\n    /// An I/O operation (read or write via the `Read` and `Write` traits)\n    /// failed.\n    #[error(\"I/O operation failed\")]\n    Io(io::Error),\n}\n\nimpl From<io::Error> for PlyError {\n    fn from(error: io::Error) -> Self {\n        PlyError::Io(error)\n    }\n}\n\npub trait ElementExt {\n    fn scalar<K, T>(&self, key: K) -> Result<T, PlyError>\n    where\n        K: AsRef<str>,\n        T: NumCast;\n\n    fn list<K, T, I>(&self, key: K) -> Result<I, PlyError>\n    where\n        K: AsRef<str>,\n        T: NumCast,\n        I: FromIterator<T>;\n}\n\nimpl ElementExt for Element {\n    fn scalar<K, T>(&self, key: K) -> Result<T, PlyError>\n    where\n        K: AsRef<str>,\n        T: NumCast,\n    {\n        self.get(key.as_ref())\n            .ok_or(PlyError::PropertyNotFound)?\n            .clone()\n            .into_scalar()\n    }\n\n    fn list<K, T, I>(&self, key: K) -> Result<I, PlyError>\n    where\n        K: AsRef<str>,\n        T: NumCast,\n        I: FromIterator<T>,\n    {\n        self.get(key.as_ref())\n            .ok_or(PlyError::PropertyNotFound)?\n            .clone()\n            .into_list()\n    }\n}\n\npub trait PropertyExt {\n    fn into_scalar<T>(self) -> Result<T, PlyError>\n    where\n        T: NumCast;\n\n    fn into_list<T, I>(self) -> Result<I, PlyError>\n    where\n        T: NumCast,\n        I: FromIterator<T>;\n}\n\nimpl PropertyExt for Property {\n    fn into_scalar<T>(self) -> Result<T, PlyError>\n    where\n        T: NumCast,\n    {\n        match self {\n            Property::Char(value) => num_cast_scalar(value),\n            Property::UChar(value) => num_cast_scalar(value),\n            Property::Short(value) => num_cast_scalar(value),\n            Property::UShort(value) => num_cast_scalar(value),\n            Property::Int(value) => num_cast_scalar(value),\n            Property::UInt(value) => num_cast_scalar(value),\n            Property::Float(value) => num_cast_scalar(value),\n            Property::Double(value) => num_cast_scalar(value),\n            _ => Err(PlyError::PropertyTypeConflict),\n        }\n    }\n\n    fn into_list<T, I>(self) -> Result<I, PlyError>\n    where\n        T: NumCast,\n        I: FromIterator<T>,\n    {\n        match self {\n            Property::ListChar(values) => num_cast_list(values),\n            Property::ListUChar(values) => num_cast_list(values),\n            Property::ListShort(values) => num_cast_list(values),\n            Property::ListUShort(values) => num_cast_list(values),\n            Property::ListInt(values) => num_cast_list(values),\n            Property::ListUInt(values) => num_cast_list(values),\n            Property::ListFloat(values) => num_cast_list(values),\n            Property::ListDouble(values) => num_cast_list(values),\n            _ => Err(PlyError::PropertyTypeConflict),\n        }\n    }\n}\n\npub trait VertexElementDecoder {\n    fn decode_vertex_elements<'a>(\n        &self,\n        definitions: &'a Header,\n        elements: &'a Payload,\n    ) -> Result<(&'a ElementDefinition, &'a Vec<Element>), PlyError> {\n        decode_elements(definitions, elements, \"vertex\")\n    }\n}\n\npub trait VertexPropertyDecoder: VertexDecoder {\n    fn decode_vertex_properties<'a, I>(\n        &self,\n        definition: &'a ElementDefinition,\n        elements: I,\n    ) -> Result<Self::Output, PlyError>\n    where\n        I: IntoIterator<Item = &'a Element>;\n}\n\npub trait FaceElementDecoder {\n    fn decode_face_elements<'a>(\n        &self,\n        definitions: &'a Header,\n        elements: &'a Payload,\n    ) -> Result<(&'a ElementDefinition, &'a Vec<Element>), PlyError> {\n        decode_elements(definitions, elements, \"face\")\n    }\n}\n\npub trait FacePropertyDecoder: FaceDecoder {\n    fn decode_face_properties<'a, I>(\n        &self,\n        definition: &'a ElementDefinition,\n        elements: I,\n    ) -> Result<Self::Output, PlyError>\n    where\n        I: IntoIterator<Item = &'a Element>;\n}\n\npub trait FromPly<E>: Sized {\n    fn from_ply(decoder: E, read: impl Read) -> Result<(Self, Ply), PlyError>;\n}\n\nimpl<T, E> FromPly<E> for T\nwhere\n    T: FromEncoding<E>,\n    E: FaceElementDecoder + FacePropertyDecoder + VertexPropertyDecoder + VertexElementDecoder,\n{\n    fn from_ply(decoder: E, mut read: impl Read) -> Result<(Self, Ply), PlyError> {\n        let ply = Ply::parse(&mut read)?;\n        let mesh = T::from_encoding(\n            decode_vertex_properties(&decoder, &ply.header, &ply.payload)?,\n            decode_face_properties(&decoder, &ply.header, &ply.payload)?,\n        )\n        .map_err(|_| PlyError::EncodingIncompatible)?;\n        Ok((mesh, ply))\n    }\n}\n\npub trait ToPly<E> {\n    fn to_ply(\n        &self,\n        definitions: &Header,\n        encoder: E,\n        write: impl Write,\n    ) -> Result<usize, PlyError>;\n}\n\npub trait DecodePosition<N>: FiniteDimensional<N = N> + Sized\nwhere\n    N: NonZero + Unsigned,\n{\n    fn decode_position(element: &Element) -> Result<Self, PlyError>;\n}\n\nimpl<T> DecodePosition<U2> for T\nwhere\n    T: EuclideanSpace + FiniteDimensional<N = U2>,\n{\n    fn decode_position(element: &Element) -> Result<Self, PlyError> {\n        let position = EuclideanSpace::from_xy(element.scalar(\"x\")?, element.scalar(\"y\")?);\n        Ok(position)\n    }\n}\n\nimpl<T> DecodePosition<U3> for T\nwhere\n    T: EuclideanSpace + FiniteDimensional<N = U3>,\n{\n    fn decode_position(element: &Element) -> Result<Self, PlyError> {\n        let position = EuclideanSpace::from_xyz(\n            element.scalar(\"x\")?,\n            element.scalar(\"y\")?,\n            element.scalar(\"z\")?,\n        );\n        Ok(position)\n    }\n}\n\npub struct PositionEncoding<T> {\n    phantom: PhantomData<fn() -> T>,\n}\n\nimpl<T> Default for PositionEncoding<T> {\n    fn default() -> Self {\n        PositionEncoding {\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<T> FaceDecoder for PositionEncoding<T> {\n    type Output = Vec<(Self::Index, Self::Face)>;\n    type Index = SmallVec<[usize; 4]>;\n    type Face = ();\n}\n\nimpl<T> FaceElementDecoder for PositionEncoding<T> {}\n\nimpl<T> FacePropertyDecoder for PositionEncoding<T> {\n    fn decode_face_properties<'a, I>(\n        &self,\n        _: &'a ElementDefinition,\n        elements: I,\n    ) -> Result<<Self as FaceDecoder>::Output, PlyError>\n    where\n        I: IntoIterator<Item = &'a Element>,\n    {\n        elements\n            .into_iter()\n            .map(|element| {\n                let indices = element.list(\"vertex_index\")?;\n                Ok((indices, ()))\n            })\n            .collect()\n    }\n}\n\nimpl<T> VertexDecoder for PositionEncoding<T> {\n    type Output = Vec<Self::Vertex>;\n    type Vertex = T;\n}\n\nimpl<T> VertexElementDecoder for PositionEncoding<T> {}\n\nimpl<T, N> VertexPropertyDecoder for PositionEncoding<T>\nwhere\n    T: DecodePosition<N> + FiniteDimensional<N = N>,\n    N: NonZero + Unsigned,\n{\n    fn decode_vertex_properties<'a, I>(\n        &self,\n        _: &'a ElementDefinition,\n        elements: I,\n    ) -> Result<<Self as VertexDecoder>::Output, PlyError>\n    where\n        I: IntoIterator<Item = &'a Element>,\n    {\n        elements\n            .into_iter()\n            .map(|element| T::decode_position(element))\n            .collect()\n    }\n}\n\npub fn decode_elements<'a, K>(\n    definitions: &'a Header,\n    elements: &'a Payload,\n    key: K,\n) -> Result<(&'a ElementDefinition, &'a Vec<Element>), PlyError>\nwhere\n    K: AsRef<str>,\n{\n    definitions\n        .get(key.as_ref())\n        .ok_or(PlyError::ElementNotFound)\n        .and_then(|definition| {\n            elements\n                .get(&definition.name)\n                .ok_or(PlyError::ElementNotFound)\n                .map(|elements| (definition, elements))\n        })\n}\n\npub fn decode_vertex_properties<E>(\n    decoder: &E,\n    definitions: &Header,\n    elements: &Payload,\n) -> Result<E::Output, PlyError>\nwhere\n    E: VertexElementDecoder + VertexPropertyDecoder,\n{\n    decoder\n        .decode_vertex_elements(definitions, elements)\n        .and_then(|(definition, elements)| decoder.decode_vertex_properties(definition, elements))\n}\n\npub fn decode_face_properties<E>(\n    decoder: &E,\n    definitions: &Header,\n    elements: &Payload,\n) -> Result<E::Output, PlyError>\nwhere\n    E: FaceElementDecoder + FacePropertyDecoder,\n{\n    decoder\n        .decode_face_elements(definitions, elements)\n        .and_then(|(definition, elements)| decoder.decode_face_properties(definition, elements))\n}\n\nfn num_cast_scalar<T, U>(value: T) -> Result<U, PlyError>\nwhere\n    T: NumCast,\n    U: NumCast,\n{\n    cast::cast(value).ok_or(PlyError::PropertyTypeConflict)\n}\n\nfn num_cast_list<T, U, I>(values: Vec<T>) -> Result<I, PlyError>\nwhere\n    T: NumCast,\n    U: NumCast,\n    I: FromIterator<U>,\n{\n    values\n        .into_iter()\n        .map(num_cast_scalar)\n        .collect::<Result<_, _>>()\n}\n\n#[cfg(test)]\nmod tests {\n    use nalgebra::Point3;\n\n    use crate::buffer::MeshBuffer;\n    use crate::encoding::ply::{FromPly, PositionEncoding};\n    use crate::graph::MeshGraph;\n    use crate::primitive::Tetragon;\n\n    type E3 = Point3<f64>;\n\n    #[test]\n    fn decode_into_buffer() {\n        let (buffer, _) = {\n            let ply: &[u8] = include_bytes!(\"../../../data/cube.ply\");\n            MeshBuffer::<Tetragon<usize>, E3>::from_ply(PositionEncoding::<E3>::default(), ply)\n                .unwrap()\n        };\n        assert_eq!(8, buffer.as_vertex_slice().len());\n        assert_eq!(6, buffer.as_index_slice().len());\n    }\n\n    #[test]\n    fn decode_into_graph() {\n        let (graph, _) = {\n            let ply: &[u8] = include_bytes!(\"../../../data/cube.ply\");\n            MeshGraph::<E3>::from_ply(PositionEncoding::<E3>::default(), ply).unwrap()\n        };\n        assert_eq!(8, graph.vertex_count());\n        assert_eq!(12, graph.edge_count());\n        assert_eq!(6, graph.face_count());\n    }\n}\n"
  },
  {
    "path": "plexus/src/entity/borrow.rs",
    "content": "pub trait Reborrow {\n    type Target;\n\n    fn reborrow(&self) -> &Self::Target;\n}\n\npub trait ReborrowMut: Reborrow {\n    fn reborrow_mut(&mut self) -> &mut Self::Target;\n}\n\npub trait ReborrowInto<'a>: Reborrow {\n    fn reborrow_into(self) -> &'a Self::Target;\n}\n\nimpl<T> Reborrow for &'_ T {\n    type Target = T;\n\n    fn reborrow(&self) -> &Self::Target {\n        self\n    }\n}\n\nimpl<T> Reborrow for &'_ mut T {\n    type Target = T;\n\n    fn reborrow(&self) -> &Self::Target {\n        self\n    }\n}\n\nimpl<T> ReborrowMut for &'_ mut T {\n    fn reborrow_mut(&mut self) -> &mut Self::Target {\n        self\n    }\n}\n\nimpl<'a, T> ReborrowInto<'a> for &'a T {\n    fn reborrow_into(self) -> &'a Self::Target {\n        self\n    }\n}\n\nimpl<'a, T> ReborrowInto<'a> for &'a mut T {\n    fn reborrow_into(self) -> &'a Self::Target {\n        &*self\n    }\n}\n"
  },
  {
    "path": "plexus/src/entity/dijkstra.rs",
    "content": "use derivative::Derivative;\nuse std::cmp::Reverse;\nuse std::collections::hash_map::Entry;\nuse std::collections::{BinaryHeap, HashMap, HashSet};\n\nuse crate::entity::storage::{AsStorage, Enumerate, Get};\nuse crate::entity::traverse::Adjacency;\nuse crate::entity::view::{Bind, Unbind};\nuse crate::entity::EntityError;\nuse crate::geometry::Metric;\n\npub type MetricTree<K, Q> = HashMap<K, (Option<K>, Q)>;\n\n#[derive(Derivative)]\n#[derivative(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]\nstruct KeyedMetric<K, Q>(\n    #[derivative(Ord = \"ignore\", PartialEq = \"ignore\", PartialOrd = \"ignore\")] K,\n    Q,\n)\nwhere\n    Q: Eq + Ord;\n\npub fn metrics_with<'a, M, T, Q, F>(\n    from: T,\n    to: Option<T::Key>,\n    f: F,\n) -> Result<MetricTree<T::Key, Q>, EntityError>\nwhere\n    M: 'a + AsStorage<T::Entity>,\n    T: Adjacency + Bind<&'a M> + Copy + Unbind<&'a M>,\n    Q: Copy + Metric,\n    F: Fn(T, T) -> Q,\n{\n    let (storage, from) = from.unbind();\n    let capacity = if let Some(key) = to {\n        if !storage.as_storage().contains_key(&key) {\n            return Err(EntityError::EntityNotFound);\n        }\n        0\n    }\n    else {\n        storage.as_storage().len()\n    };\n    let mut buffer = BinaryHeap::new();\n    let mut breadcrumbs = HashSet::with_capacity(capacity);\n    let mut metrics = HashMap::with_capacity(capacity);\n\n    metrics.insert(from, (None, Q::zero()));\n    buffer.push(KeyedMetric(from, Reverse(Q::zero())));\n    while let Some(KeyedMetric(key, Reverse(metric))) = buffer.pop() {\n        if Some(key) == to {\n            break;\n        }\n        let entity = T::bind(storage, key).ok_or(EntityError::EntityNotFound)?;\n        if breadcrumbs.insert(entity.key()) {\n            for adjacent in entity\n                .adjacency()\n                .into_iter()\n                .map(|key| T::bind(storage, key))\n            {\n                let adjacent = adjacent.ok_or(EntityError::EntityNotFound)?;\n                let summand = f(entity, adjacent);\n                if summand < Q::zero() {\n                    return Err(EntityError::Data);\n                }\n                let metric = metric + summand;\n                match metrics.entry(adjacent.key()) {\n                    Entry::Occupied(entry) => {\n                        if metric < entry.get().1 {\n                            entry.into_mut().1 = metric;\n                        }\n                    }\n                    Entry::Vacant(entry) => {\n                        entry.insert((Some(entity.key()), metric));\n                    }\n                }\n                buffer.push(KeyedMetric(adjacent.key(), Reverse(metric)));\n            }\n        }\n    }\n    Ok(metrics)\n}\n\n#[cfg(test)]\nmod tests {\n    use decorum::R64;\n    use nalgebra::Point2;\n    use theon::space::InnerSpace;\n\n    use crate::entity::dijkstra::{self, MetricTree};\n    use crate::entity::EntityError;\n    use crate::graph::MeshGraph;\n    use crate::prelude::*;\n    use crate::primitive::{Tetragon, Trigon};\n\n    #[test]\n    fn decreasing_summand() {\n        let graph = MeshGraph::<Point2<f64>>::from_raw_buffers(\n            vec![Tetragon::new(0usize, 1, 2, 3)],\n            vec![(-1.0, -1.0), (1.0, -1.0), (1.0, 1.0), (-1.0, 1.0)],\n        )\n        .unwrap();\n        let vertex = graph.vertices().next().unwrap();\n        assert_eq!(\n            Err(EntityError::Data),\n            dijkstra::metrics_with(vertex, None, |_, _| -1isize)\n        )\n    }\n\n    #[test]\n    fn logical_metrics() {\n        let graph = MeshGraph::<()>::from_raw_buffers(vec![Trigon::new(0usize, 1, 2)], vec![(); 3])\n            .unwrap();\n        let vertex = graph.vertices().next().unwrap();\n        let metrics = dijkstra::metrics_with(vertex, None, |_, _| 1usize).unwrap();\n        let a = vertex.key();\n        let b = vertex.outgoing_arc().destination_vertex().key();\n        let c = vertex.outgoing_arc().next_arc().destination_vertex().key();\n        let aq = *metrics.get(&a).unwrap();\n        let bq = *metrics.get(&b).unwrap();\n        let cq = *metrics.get(&c).unwrap();\n\n        assert_eq!(aq, (None, 0));\n        assert_eq!(bq, (Some(a), 1));\n        assert_eq!(cq, (Some(a), 1));\n    }\n\n    // TODO: Use approximated comparisons in assertions.\n    #[test]\n    fn euclidean_distance_metrics() {\n        let graph = MeshGraph::<Point2<f64>>::from_raw_buffers(\n            vec![Tetragon::new(0usize, 1, 2, 3)],\n            vec![(-1.0, -1.0), (1.0, -1.0), (1.0, 1.0), (-1.0, 1.0)],\n        )\n        .unwrap();\n        let vertex = graph.vertices().next().unwrap();\n        let metrics: MetricTree<_, R64> = dijkstra::metrics_with(vertex, None, |from, to| {\n            R64::assert((to.position() - from.position()).magnitude())\n        })\n        .unwrap();\n        let a = vertex.key();\n        let b = vertex.outgoing_arc().destination_vertex().key();\n        let c = vertex.outgoing_arc().next_arc().destination_vertex().key();\n        let d = vertex\n            .outgoing_arc()\n            .next_arc()\n            .next_arc()\n            .destination_vertex()\n            .key();\n        let aq = *metrics.get(&a).unwrap();\n        let bq = *metrics.get(&b).unwrap();\n        let cq = *metrics.get(&c).unwrap();\n        let dq = *metrics.get(&d).unwrap();\n\n        assert_eq!(aq, (None, R64::assert(0.0)));\n        assert_eq!(bq, (Some(a), R64::assert(2.0)));\n        assert_eq!(cq, (Some(b), R64::assert(4.0)));\n        assert_eq!(dq, (Some(a), R64::assert(2.0)));\n    }\n}\n"
  },
  {
    "path": "plexus/src/entity/mod.rs",
    "content": "pub mod borrow;\npub mod dijkstra;\npub mod storage;\npub mod traverse;\npub mod view;\n\nuse thiserror::Error;\n\nuse crate::entity::storage::{Dispatch, Key, Storage};\n\n#[derive(Debug, Eq, Error, PartialEq)]\npub enum EntityError {\n    #[error(\"required entity not found\")]\n    EntityNotFound,\n    #[error(\"data operation failed\")]\n    Data,\n}\n\npub trait Entity: Sized {\n    type Key: Key;\n    type Storage: Default + Dispatch<Self> + Storage<Self>;\n}\n\npub trait Payload: Entity {\n    type Data;\n\n    fn get(&self) -> &Self::Data;\n\n    fn get_mut(&mut self) -> &mut Self::Data;\n}\n"
  },
  {
    "path": "plexus/src/entity/storage/hash.rs",
    "content": "use ahash::AHashMap;\nuse std::hash::Hash;\nuse std::marker::PhantomData;\n\nuse crate::entity::storage::{\n    AsStorage, AsStorageMut, DependentStorage, Dispatch, Dynamic, Enumerate, Get, IncrementalKeyer,\n    IndependentStorage, InnerKey, Insert, InsertWithKey, Key, Keyer, Mode, Remove, Static,\n    StorageTarget,\n};\nuse crate::entity::{Entity, Payload};\n\n// TODO: The `Keyer` parameter `R` of `HashStorage` cannot be parameterized when\n//       implementing the `AsStorage` and `Dispatch` traits even if the\n//       conflicting implementations use a private local type or the `Keyer`\n//       trait is private. Instead, this is implemented more specifically for\n//       `IncrementalKeyer`. Perhaps this will be possible in the future.\n//\n//       See https://github.com/rust-lang/rust/issues/48869\n\npub struct HashStorage<E, R = (), P = Static>\nwhere\n    E: Entity,\n    R: Default,\n    P: Mode,\n{\n    inner: AHashMap<InnerKey<<E as Entity>::Key>, E>,\n    keyer: R,\n    phantom: PhantomData<fn() -> P>,\n}\n\nimpl<E, R, P> HashStorage<E, R, P>\nwhere\n    E: Entity,\n    InnerKey<E::Key>: Eq + Hash,\n    R: Default,\n    P: Mode,\n{\n    pub fn shrink_to_fit(&mut self) {\n        self.inner.shrink_to_fit();\n    }\n}\n\nimpl<E> AsStorage<E> for HashStorage<E, (), Dynamic>\nwhere\n    E: Entity<Storage = Self>,\n    InnerKey<E::Key>: Eq + Hash,\n{\n    fn as_storage(&self) -> &StorageTarget<E> {\n        self\n    }\n}\n\nimpl<E> AsStorage<E> for HashStorage<E, IncrementalKeyer, Dynamic>\nwhere\n    E: Entity<Storage = Self>,\n    E::Key: Key<Inner = u64>,\n{\n    fn as_storage(&self) -> &StorageTarget<E> {\n        self\n    }\n}\n\nimpl<E, R> AsStorage<E> for HashStorage<E, R, Static>\nwhere\n    E: Entity<Storage = Self>,\n    InnerKey<E::Key>: Eq + Hash,\n    R: 'static + Default,\n{\n    fn as_storage(&self) -> &StorageTarget<E> {\n        self\n    }\n}\n\nimpl<E> AsStorageMut<E> for HashStorage<E, (), Dynamic>\nwhere\n    E: Entity<Storage = Self>,\n    InnerKey<E::Key>: Eq + Hash,\n{\n    fn as_storage_mut(&mut self) -> &mut StorageTarget<E> {\n        self\n    }\n}\n\nimpl<E> AsStorageMut<E> for HashStorage<E, IncrementalKeyer, Dynamic>\nwhere\n    E: Entity<Storage = Self>,\n    E::Key: Key<Inner = u64>,\n{\n    fn as_storage_mut(&mut self) -> &mut StorageTarget<E> {\n        self\n    }\n}\n\nimpl<E, R> AsStorageMut<E> for HashStorage<E, R, Static>\nwhere\n    E: Entity<Storage = Self>,\n    InnerKey<E::Key>: Eq + Hash,\n    R: 'static + Default,\n{\n    fn as_storage_mut(&mut self) -> &mut StorageTarget<E> {\n        self\n    }\n}\n\nimpl<E, R, P> Default for HashStorage<E, R, P>\nwhere\n    E: Entity,\n    R: Default,\n    P: Mode,\n{\n    fn default() -> Self {\n        HashStorage {\n            inner: Default::default(),\n            keyer: Default::default(),\n            phantom: PhantomData,\n        }\n    }\n}\n\n#[rustfmt::skip]\nimpl<E> Dispatch<E> for HashStorage<E, (), Dynamic>\nwhere\n    E: Entity<Storage = Self>,\n    InnerKey<E::Key>: Eq + Hash,\n{\n    type Target<'a> = dyn 'a + DependentStorage<E> where E: 'a;\n}\n\n#[rustfmt::skip]\nimpl<E> Dispatch<E> for HashStorage<E, IncrementalKeyer, Dynamic>\nwhere\n    E: Entity<Storage = Self>,\n    E::Key: Key<Inner = u64>,\n{\n    type Target<'a> = dyn 'a + IndependentStorage<E> where E: 'a;\n}\n\n#[rustfmt::skip]\nimpl<E, R> Dispatch<E> for HashStorage<E, R, Static>\nwhere\n    E: Entity<Storage = Self>,\n    InnerKey<E::Key>: Eq + Hash,\n    R: 'static + Default,\n{\n    type Target<'a> = Self where E: 'a;\n}\n\nimpl<E, R, P> Enumerate<E> for HashStorage<E, R, P>\nwhere\n    E: Entity,\n    InnerKey<E::Key>: Eq + Hash,\n    R: Default,\n    P: Mode,\n{\n    fn len(&self) -> usize {\n        self.inner.len()\n    }\n\n    fn iter(&self) -> Box<dyn '_ + Iterator<Item = (E::Key, &'_ E)>> {\n        Box::new(\n            self.inner\n                .iter()\n                .map(|(key, entity)| (E::Key::from_inner(*key), entity)),\n        )\n    }\n\n    fn iter_mut(&mut self) -> Box<dyn '_ + Iterator<Item = (E::Key, &'_ mut E::Data)>>\n    where\n        E: Payload,\n    {\n        Box::new(\n            self.inner\n                .iter_mut()\n                .map(|(key, entity)| (E::Key::from_inner(*key), entity.get_mut())),\n        )\n    }\n}\n\nimpl<E, R, P> Get<E> for HashStorage<E, R, P>\nwhere\n    E: Entity,\n    InnerKey<E::Key>: Eq + Hash,\n    R: Default,\n    P: Mode,\n{\n    fn get(&self, key: &E::Key) -> Option<&E> {\n        self.inner.get(&key.into_inner())\n    }\n\n    fn get_mut(&mut self, key: &E::Key) -> Option<&mut E> {\n        self.inner.get_mut(&key.into_inner())\n    }\n}\n\nimpl<E, R, P> Insert<E> for HashStorage<E, R, P>\nwhere\n    E: Entity,\n    InnerKey<E::Key>: Eq + Hash,\n    R: Keyer<E::Key>,\n    P: Mode,\n{\n    fn insert(&mut self, entity: E) -> E::Key {\n        let key = self.keyer.next();\n        self.inner.insert(key, entity);\n        Key::from_inner(key)\n    }\n}\n\nimpl<E, P> InsertWithKey<E> for HashStorage<E, (), P>\nwhere\n    E: Entity,\n    InnerKey<E::Key>: Eq + Hash,\n    P: Mode,\n{\n    fn insert_with_key(&mut self, key: &E::Key, entity: E) -> Option<E> {\n        self.inner.insert(key.into_inner(), entity)\n    }\n}\n\nimpl<E, R, P> Remove<E> for HashStorage<E, R, P>\nwhere\n    E: Entity,\n    InnerKey<E::Key>: Eq + Hash,\n    R: Default,\n    P: Mode,\n{\n    fn remove(&mut self, key: &E::Key) -> Option<E> {\n        self.inner.remove(&key.into_inner())\n    }\n}\n"
  },
  {
    "path": "plexus/src/entity/storage/mod.rs",
    "content": "mod hash;\n\nuse std::hash::Hash;\n\nuse crate::entity::{Entity, Payload};\n\npub use crate::entity::storage::hash::HashStorage;\n\npub mod prelude {\n    pub use crate::entity::storage::{Enumerate, Get, Insert, InsertWithKey, Remove};\n}\n\npub type StorageTarget<'a, E> = <<E as Entity>::Storage as Dispatch<E>>::Target<'a>;\n\npub type InnerKey<K> = <K as Key>::Inner;\n\npub trait Key: Copy + Eq + Hash + Sized {\n    type Inner: Copy + Sized;\n\n    fn from_inner(key: Self::Inner) -> Self;\n\n    fn into_inner(self) -> Self::Inner;\n}\n\npub trait Keyer<K>: Clone + Default\nwhere\n    K: Key,\n{\n    fn next(&mut self) -> K::Inner;\n}\n\n#[derive(Clone, Copy, Default)]\npub struct IncrementalKeyer {\n    key: u64,\n}\n\nimpl<K> Keyer<K> for IncrementalKeyer\nwhere\n    K: Key<Inner = u64>,\n{\n    fn next(&mut self) -> K::Inner {\n        let key = self.key;\n        self.key = self.key.checked_add(1).expect(\"keyspace exhausted\");\n        key\n    }\n}\n\n#[rustfmt::skip]\npub trait Dispatch<E>\nwhere\n    E: Entity,\n{\n    type Target<'a>: 'a + ?Sized + Storage<E>\n    where\n        E: 'a;\n}\n\npub trait Mode {}\n\npub enum Static {}\n\nimpl Mode for Static {}\n\npub enum Dynamic {}\n\nimpl Mode for Dynamic {}\n\n// TODO: GATs cannot yet be used here while still supporting trait objects,\n//       because the types cannot be bound in a supertrait. To support trait\n//       objects, the associated types must be bound (likely to `Box<dyn ...>`).\n//       See https://github.com/rust-lang/rust/issues/67510\npub trait Enumerate<E>\nwhere\n    E: Entity,\n{\n    fn len(&self) -> usize;\n\n    fn iter(&self) -> Box<dyn '_ + Iterator<Item = (E::Key, &'_ E)>>;\n\n    fn iter_mut(&mut self) -> Box<dyn '_ + Iterator<Item = (E::Key, &'_ mut E::Data)>>\n    where\n        E: Payload;\n}\n\npub trait Get<E>\nwhere\n    E: Entity,\n{\n    fn get(&self, key: &E::Key) -> Option<&E>;\n\n    fn get_mut(&mut self, key: &E::Key) -> Option<&mut E>;\n\n    fn contains_key(&self, key: &E::Key) -> bool {\n        self.get(key).is_some()\n    }\n}\n\npub trait Insert<E>\nwhere\n    E: Entity,\n{\n    fn insert(&mut self, entity: E) -> E::Key;\n}\n\npub trait InsertWithKey<E>\nwhere\n    E: Entity,\n{\n    fn insert_with_key(&mut self, key: &E::Key, entity: E) -> Option<E>;\n}\n\npub trait Remove<E>\nwhere\n    E: Entity,\n{\n    fn remove(&mut self, key: &E::Key) -> Option<E>;\n}\n\npub trait Storage<E>: AsStorage<E> + AsStorageMut<E> + Enumerate<E> + Get<E> + Remove<E>\nwhere\n    E: Entity,\n{\n}\n\nimpl<T, E> Storage<E> for T\nwhere\n    T: AsStorage<E> + AsStorageMut<E> + Enumerate<E> + Get<E> + Remove<E>,\n    E: Entity,\n{\n}\n\npub trait DependentStorage<E>: InsertWithKey<E> + Storage<E>\nwhere\n    E: Entity,\n{\n}\n\nimpl<T, E> DependentStorage<E> for T\nwhere\n    T: InsertWithKey<E> + Storage<E>,\n    E: Entity,\n{\n}\n\npub trait IndependentStorage<E>: Insert<E> + Storage<E>\nwhere\n    E: Entity,\n{\n}\n\nimpl<T, E> IndependentStorage<E> for T\nwhere\n    T: Insert<E> + Storage<E>,\n    E: Entity,\n{\n}\n\npub trait Fuse<M, T>\nwhere\n    M: AsStorage<T>,\n    T: Entity,\n{\n    type Output: AsStorage<T>;\n\n    fn fuse(self, source: M) -> Self::Output;\n}\n\n// TODO: It may not be possible for storage wrapper types to implement this\n//       generally for all underlying storage types when using trait objects. An\n//       input type parameter for the wrapped storage type may be required with\n//       an implementation for each type that can be wrapped. Is there some way\n//       to support blanket implementations?\npub trait AsStorage<E>\nwhere\n    E: Entity,\n{\n    fn as_storage(&self) -> &StorageTarget<E>;\n}\n\nimpl<E, T> AsStorage<E> for &'_ T\nwhere\n    E: Entity,\n    T: AsStorage<E> + ?Sized,\n{\n    fn as_storage(&self) -> &StorageTarget<E> {\n        <T as AsStorage<E>>::as_storage(self)\n    }\n}\n\nimpl<E, T> AsStorage<E> for &'_ mut T\nwhere\n    E: Entity,\n    T: AsStorage<E> + ?Sized,\n{\n    fn as_storage(&self) -> &StorageTarget<E> {\n        <T as AsStorage<E>>::as_storage(self)\n    }\n}\n\npub trait AsStorageMut<E>: AsStorage<E>\nwhere\n    E: Entity,\n{\n    fn as_storage_mut(&mut self) -> &mut StorageTarget<E>;\n}\n\nimpl<E, T> AsStorageMut<E> for &'_ mut T\nwhere\n    E: Entity,\n    T: AsStorageMut<E> + ?Sized,\n{\n    fn as_storage_mut(&mut self) -> &mut StorageTarget<E> {\n        <T as AsStorageMut<E>>::as_storage_mut(self)\n    }\n}\n\npub trait AsStorageOf {\n    fn as_storage_of<E>(&self) -> &StorageTarget<E>\n    where\n        E: Entity,\n        Self: AsStorage<E>,\n    {\n        self.as_storage()\n    }\n\n    fn as_storage_mut_of<E>(&mut self) -> &mut StorageTarget<E>\n    where\n        E: Entity,\n        Self: AsStorageMut<E>,\n    {\n        self.as_storage_mut()\n    }\n}\n\nimpl<T> AsStorageOf for T {}\n"
  },
  {
    "path": "plexus/src/entity/traverse.rs",
    "content": "use std::collections::{HashSet, VecDeque};\nuse std::hash::Hash;\nuse std::marker::PhantomData;\n\nuse crate::entity::borrow::Reborrow;\nuse crate::entity::storage::{AsStorage, Enumerate};\nuse crate::entity::view::{Bind, ClosedView, Unbind};\n\npub enum Breadth {}\npub enum Depth {}\n\npub trait Buffer<R, T>: Default + Extend<T>\nwhere\n    R: Order<T>,\n{\n    fn push(&mut self, item: T);\n    fn pop(&mut self) -> Option<T>;\n}\n\nimpl<T> Buffer<Depth, T> for Vec<T> {\n    fn push(&mut self, item: T) {\n        Vec::<T>::push(self, item)\n    }\n\n    fn pop(&mut self) -> Option<T> {\n        Vec::<T>::pop(self)\n    }\n}\n\nimpl<T> Buffer<Breadth, T> for VecDeque<T> {\n    fn push(&mut self, item: T) {\n        VecDeque::<T>::push_back(self, item)\n    }\n\n    fn pop(&mut self) -> Option<T> {\n        VecDeque::<T>::pop_front(self)\n    }\n}\n\n/// Traversal ordering.\n///\n/// Provides a default type implementing [`Buffer`] for the ordering described\n/// by `Self`. This reduces the number of required type parameters in types\n/// implementing traversals, as only an ordering type is needed to derive the\n/// buffer. Note that the item type can typically be derived from other required\n/// type parameters.\n///\n/// See [`Traversal`].\n///\n/// [`Buffer`]: crate::entity::traverse::Buffer\n/// [`Traversal`]: crate::entity::traverse::Traversal\npub trait Order<T>: Sized {\n    type Buffer: Buffer<Self, T>;\n}\n\nimpl<T> Order<T> for Breadth {\n    type Buffer = VecDeque<T>;\n}\n\nimpl<T> Order<T> for Depth {\n    type Buffer = Vec<T>;\n}\n\npub trait Adjacency: ClosedView {\n    type Output: IntoIterator<Item = Self::Key>;\n\n    fn adjacency(&self) -> Self::Output;\n}\n\n#[derive(Debug)]\npub struct Traversal<B, T, R = Depth>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<T::Entity>,\n    T: Adjacency,\n    R: Order<T::Key>,\n{\n    storage: B,\n    breadcrumbs: HashSet<T::Key>,\n    buffer: R::Buffer,\n    phantom: PhantomData<fn() -> T>,\n}\n\nimpl<B, T, R> Clone for Traversal<B, T, R>\nwhere\n    B: Clone + Reborrow,\n    B::Target: AsStorage<T::Entity>,\n    T: Adjacency,\n    R: Order<T::Key>,\n    R::Buffer: Clone,\n{\n    fn clone(&self) -> Self {\n        Traversal {\n            storage: self.storage.clone(),\n            breadcrumbs: self.breadcrumbs.clone(),\n            buffer: self.buffer.clone(),\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<B, T, R> From<T> for Traversal<B, T, R>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<T::Entity>,\n    T: Adjacency + Unbind<B>,\n    R: Order<T::Key>,\n{\n    fn from(view: T) -> Self {\n        let (storage, key) = view.unbind();\n        let capacity = storage.reborrow().as_storage().len();\n        let mut buffer = R::Buffer::default();\n        buffer.push(key);\n        Traversal {\n            storage,\n            breadcrumbs: HashSet::with_capacity(capacity),\n            buffer,\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<'a, M, T, R> Iterator for Traversal<&'a M, T, R>\nwhere\n    M: 'a + AsStorage<T::Entity>,\n    T: Adjacency + Bind<&'a M>,\n    R: Order<T::Key>,\n{\n    type Item = T;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        while let Some(view) = self.buffer.pop().and_then(|key| T::bind(self.storage, key)) {\n            if self.breadcrumbs.insert(view.key()) {\n                self.buffer.extend(view.adjacency());\n                return Some(view);\n            }\n        }\n        None\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        (\n            1,\n            Some(AsStorage::<T::Entity>::as_storage(&self.storage).len()),\n        )\n    }\n}\n\n/// Trace of a traversal, iteration, etc.\n///\n/// A trace caches _breadcrumbs_, which identify entities encountered during a\n/// traversal.\npub trait Trace<T> {\n    /// Inserts the given breadcrumb into the trace. The breadcrumb may or may\n    /// not be cached.\n    ///\n    /// A _collision_ occurs if a breadcrumb that has been cached by the trace\n    /// is reinserted. If a collision with the trace is detected, then this\n    /// function returns `false` and otherwise returns `true` (similarly to\n    /// collections like [`HashSet`]).\n    ///\n    /// If `false` is returned, then any traversal or iteration should\n    /// terminate.\n    ///\n    /// [`HashSet`]: std::collections::HashSet\n    fn insert(&mut self, breadcrumb: T) -> bool;\n}\n\n/// Trace that caches and detects collisions with only the first breadcrumb that\n/// is inserted.\n///\n/// A collision only occurs if the first breadcrumb is reinserted; no other\n/// breadcrumbs are cached.\n///\n/// This trace should **not** be used when traversing a structure with unknown\n/// consistency, because it may never signal that the iteration should\n/// terminate. However, it requires very little space and time to operate.\n#[derive(Clone, Copy, Debug, Default)]\npub struct TraceFirst<T>\nwhere\n    T: Copy,\n{\n    breadcrumb: Option<T>,\n}\n\nimpl<T> Trace<T> for TraceFirst<T>\nwhere\n    T: Copy + Eq,\n{\n    fn insert(&mut self, breadcrumb: T) -> bool {\n        match self.breadcrumb {\n            Some(collision) => collision != breadcrumb,\n            None => {\n                self.breadcrumb = Some(breadcrumb);\n                true\n            }\n        }\n    }\n}\n\n/// Trace that caches all inserted breadcrumbs and detects collisions with any\n/// such breadcrumb.\n///\n/// This trace is very robust and reliably signals termination of a traversal,\n/// but requires non-trivial space to cache breadcrumbs and must hash\n/// breadcrumbs to detect collisions.\n#[derive(Clone, Debug, Default)]\npub struct TraceAny<T>\nwhere\n    T: Copy + Eq + Hash,\n{\n    breadcrumbs: HashSet<T>,\n}\n\nimpl<T> Trace<T> for TraceAny<T>\nwhere\n    T: Copy + Eq + Hash,\n{\n    fn insert(&mut self, breadcrumb: T) -> bool {\n        self.breadcrumbs.insert(breadcrumb)\n    }\n}\n"
  },
  {
    "path": "plexus/src/entity/view.rs",
    "content": "use std::hash::{Hash, Hasher};\nuse std::ops::{Deref, DerefMut};\n\nuse crate::entity::borrow::{Reborrow, ReborrowInto, ReborrowMut};\nuse crate::entity::storage::{AsStorage, AsStorageMut, Get, Key};\nuse crate::entity::{Entity, Payload};\n\npub trait ClosedView {\n    type Key: Key;\n    type Entity: Entity<Key = Self::Key>;\n\n    fn key(&self) -> Self::Key;\n}\n\npub trait Bind<B>: ClosedView + Sized\nwhere\n    B: Reborrow,\n{\n    fn bind(storage: B, key: Self::Key) -> Option<Self>;\n}\n\n// Note that orphan views do not gain this implementation without a\n// `From<View<_, _>>` implementation.\nimpl<B, T> Bind<B> for T\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<T::Entity>,\n    T: ClosedView + From<View<B, <T as ClosedView>::Entity>> + Sized,\n{\n    fn bind(storage: B, key: Self::Key) -> Option<Self> {\n        View::bind(storage, key).map(Self::from)\n    }\n}\n\npub trait Rebind<B, T>: ClosedView\nwhere\n    B: Reborrow,\n    T: ClosedView,\n{\n    fn rebind(self, key: T::Key) -> Option<T>;\n}\n\nimpl<B, T, U> Rebind<B, T> for U\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<T::Entity> + AsStorage<U::Entity>,\n    T: ClosedView + From<View<B, <T as ClosedView>::Entity>>,\n    U: ClosedView + Into<View<B, <U as ClosedView>::Entity>>,\n{\n    fn rebind(self, key: T::Key) -> Option<T> {\n        self.into().rebind(key).map(T::from)\n    }\n}\n\npub trait Unbind<B>: ClosedView\nwhere\n    B: Reborrow,\n{\n    fn unbind(self) -> (B, Self::Key);\n}\n\nimpl<B, T> Unbind<B> for T\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<T::Entity>,\n    T: ClosedView + Into<View<B, <T as ClosedView>::Entity>>,\n{\n    fn unbind(self) -> (B, Self::Key) {\n        self.into().unbind()\n    }\n}\n\npub struct View<B, E>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<E>,\n    E: Entity,\n{\n    storage: B,\n    key: E::Key,\n}\n\nimpl<B, E> View<B, E>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<E>,\n    E: Entity,\n{\n    pub fn bind(storage: B, key: E::Key) -> Option<Self> {\n        storage\n            .reborrow()\n            .as_storage()\n            .contains_key(&key)\n            .then(|| View::bind_unchecked(storage, key))\n    }\n\n    pub fn bind_unchecked(storage: B, key: E::Key) -> Self {\n        View { storage, key }\n    }\n\n    pub fn bind_into<T>(storage: B, key: E::Key) -> Option<T>\n    where\n        T: From<Self>,\n    {\n        View::bind(storage, key).map(T::from)\n    }\n\n    pub fn unbind(self) -> (B, E::Key) {\n        let View { storage, key, .. } = self;\n        (storage, key)\n    }\n\n    pub fn rebind<T>(self, key: T::Key) -> Option<View<B, T>>\n    where\n        B::Target: AsStorage<T>,\n        T: Entity,\n    {\n        let (storage, _) = self.unbind();\n        View::bind(storage, key)\n    }\n\n    pub fn rebind_into<T, U>(self, key: U::Key) -> Option<T>\n    where\n        B::Target: AsStorage<U>,\n        T: From<View<B, U>>,\n        U: Entity,\n    {\n        self.rebind(key).map(T::from)\n    }\n\n    pub fn get(&self) -> &E::Data\n    where\n        E: Payload,\n    {\n        self.as_entity().get()\n    }\n\n    pub fn key(&self) -> E::Key {\n        self.key\n    }\n\n    pub fn to_ref(&self) -> View<&B::Target, E> {\n        View::bind_unchecked(self.storage.reborrow(), self.key)\n    }\n\n    fn as_entity(&self) -> &E {\n        self.storage\n            .reborrow()\n            .as_storage()\n            .get(&self.key)\n            .expect(\"view key invalidated\")\n    }\n}\n\nimpl<B, E> View<B, E>\nwhere\n    B: ReborrowMut,\n    B::Target: AsStorage<E>,\n    E: Entity,\n{\n    /// Mutably reborrows the interior of the view.\n    ///\n    /// It is possible to invalidate views using this function. Care must be taken to ensure that\n    /// the originating view's key is still present in storage after the reborrowed view is\n    /// dropped.\n    // LINT: The \"unannotated\" name of this function is `to_mut`, but \"unchecked\" is used to\n    //       indicate that this function can be used incorrectly and corrupt views. `to_mut` does\n    //       not violate lints, but `to_mut_unchecked` does. This function and its proxies allow\n    //       this unconventional name.\n    #[expect(clippy::wrong_self_convention)]\n    pub fn to_mut_unchecked(&mut self) -> View<&mut B::Target, E> {\n        View::bind_unchecked(self.storage.reborrow_mut(), self.key)\n    }\n}\n\nimpl<B, E> View<B, E>\nwhere\n    B: ReborrowMut,\n    B::Target: AsStorageMut<E>,\n    E: Entity,\n{\n    pub fn get_mut(&mut self) -> &mut E::Data\n    where\n        E: Payload,\n    {\n        self.as_entity_mut().get_mut()\n    }\n\n    fn as_entity_mut(&mut self) -> &mut E {\n        self.storage\n            .reborrow_mut()\n            .as_storage_mut()\n            .get_mut(&self.key)\n            .expect(\"view key invalidated\")\n    }\n}\n\nimpl<'a, B, E> View<B, E>\nwhere\n    B: ReborrowInto<'a>,\n    B::Target: AsStorage<E>,\n    E: Entity,\n{\n    pub fn into_ref(self) -> View<&'a B::Target, E> {\n        let (storage, key) = self.unbind();\n        View::bind_unchecked(storage.reborrow_into(), key)\n    }\n}\n\nimpl<B, E> AsRef<E::Key> for View<B, E>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<E>,\n    E: Entity,\n{\n    fn as_ref(&self) -> &E::Key {\n        &self.key\n    }\n}\n\nimpl<B, E> Clone for View<B, E>\nwhere\n    B: Clone + Reborrow,\n    B::Target: AsStorage<E>,\n    E: Entity,\n{\n    fn clone(&self) -> Self {\n        View {\n            storage: self.storage.clone(),\n            key: self.key,\n        }\n    }\n}\n\nimpl<B, E> ClosedView for View<B, E>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<E>,\n    E: Entity,\n{\n    type Key = E::Key;\n    type Entity = E;\n\n    fn key(&self) -> Self::Key {\n        self.key\n    }\n}\n\nimpl<B, E> Copy for View<B, E>\nwhere\n    B: Copy + Reborrow,\n    B::Target: AsStorage<E>,\n    E: Entity,\n{\n}\n\nimpl<B, E> Deref for View<B, E>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<E>,\n    E: Entity,\n{\n    type Target = E;\n\n    fn deref(&self) -> &Self::Target {\n        self.as_entity()\n    }\n}\n\nimpl<B, E> DerefMut for View<B, E>\nwhere\n    B: ReborrowMut,\n    B::Target: AsStorageMut<E>,\n    E: Entity,\n{\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        self.as_entity_mut()\n    }\n}\n\nimpl<B, E> Eq for View<B, E>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<E>,\n    E: Entity,\n{\n}\n\nimpl<B, E> Hash for View<B, E>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<E>,\n    E: Entity,\n{\n    fn hash<H>(&self, state: &mut H)\n    where\n        H: Hasher,\n    {\n        self.key.hash(state);\n    }\n}\n\nimpl<B, E> PartialEq for View<B, E>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<E>,\n    E: Entity,\n{\n    fn eq(&self, other: &Self) -> bool {\n        self.key == other.key\n    }\n}\n\npub struct Orphan<'a, E>\nwhere\n    E: Payload,\n{\n    data: &'a mut E::Data,\n    key: E::Key,\n}\n\nimpl<'a, E> Orphan<'a, E>\nwhere\n    E: Payload,\n    E::Data: 'a,\n{\n    pub fn bind<M>(storage: &'a mut M, key: E::Key) -> Option<Self>\n    where\n        E: 'a,\n        M: AsStorageMut<E>,\n    {\n        View::bind(storage, key).map(Orphan::from)\n    }\n\n    pub fn bind_unchecked(data: &'a mut E::Data, key: E::Key) -> Self {\n        Orphan { data, key }\n    }\n\n    pub fn bind_into<T, M>(storage: &'a mut M, key: E::Key) -> Option<T>\n    where\n        E: 'a,\n        T: From<Self>,\n        M: AsStorageMut<E>,\n    {\n        Orphan::bind(storage, key).map(T::from)\n    }\n\n    pub fn get(&self) -> &E::Data {\n        &*self.data\n    }\n\n    pub fn get_mut(&mut self) -> &mut E::Data {\n        self.data\n    }\n\n    pub fn key(&self) -> E::Key {\n        self.key\n    }\n}\n\nimpl<'a, E> AsRef<E::Key> for Orphan<'a, E>\nwhere\n    E: Payload,\n    E::Data: 'a,\n{\n    fn as_ref(&self) -> &E::Key {\n        &self.key\n    }\n}\n\nimpl<'a, E> ClosedView for Orphan<'a, E>\nwhere\n    E: Payload,\n    E::Data: 'a,\n{\n    type Key = E::Key;\n    type Entity = E;\n\n    fn key(&self) -> Self::Key {\n        self.key\n    }\n}\n\nimpl<'a, E, M> From<View<&'a mut M, E>> for Orphan<'a, E>\nwhere\n    E: 'a + Payload,\n    E::Data: 'a,\n    M: AsStorageMut<E>,\n{\n    fn from(view: View<&'a mut M, E>) -> Self {\n        let (storage, key) = view.unbind();\n        let entity = storage\n            .as_storage_mut()\n            .get_mut(&key)\n            .expect(\"view key invalidated\");\n        Orphan::bind_unchecked(entity.get_mut(), key)\n    }\n}\n\nimpl<'a, E> Eq for Orphan<'a, E>\nwhere\n    E: Payload,\n    E::Data: 'a,\n{\n}\n\nimpl<'a, E> Hash for Orphan<'a, E>\nwhere\n    E: Payload,\n    E::Data: 'a,\n{\n    fn hash<H>(&self, state: &mut H)\n    where\n        H: Hasher,\n    {\n        self.key.hash(state);\n    }\n}\n\nimpl<'a, E> PartialEq for Orphan<'a, E>\nwhere\n    E: Payload,\n    E::Data: 'a,\n{\n    fn eq(&self, other: &Self) -> bool {\n        self.key == other.key\n    }\n}\n"
  },
  {
    "path": "plexus/src/geometry/mod.rs",
    "content": "//! Geometric traits and computational geometry.\n//!\n//! Plexus uses the [`theon`] crate to abstract over types that represent Euclidean spaces and\n//! implement linear algebra. Types and traits are re-exported from [`theon`] in this module, but\n//! it may be necessary to import additional types from [`theon`].\n//!\n//! [`theon`]: https://crates.io/crates/theon\n\nuse num::{One, Zero};\n\npub mod partition;\n\npub use theon::query::*;\npub use theon::space::{Scalar, Vector};\npub use theon::{AsPosition, AsPositionMut, Position};\n\npub trait FromGeometry<T> {\n    fn from_geometry(other: T) -> Self;\n}\n\nimpl<T> FromGeometry<T> for T {\n    fn from_geometry(other: T) -> Self {\n        other\n    }\n}\n\n/// Geometry elision into `()`.\nimpl<T> FromGeometry<T> for ()\nwhere\n    T: UnitGeometry,\n{\n    fn from_geometry(_: T) -> Self {}\n}\n\n/// Geometry elision from `()`.\nimpl<T> FromGeometry<()> for T\nwhere\n    T: UnitGeometry + Default,\n{\n    fn from_geometry(_: ()) -> Self {\n        T::default()\n    }\n}\n\n/// Geometry elision.\n///\n/// Geometric types that implement this trait may be elided. In particular,\n/// these types may be converted into and from `()` via the [`FromGeometry`] and\n/// [`IntoGeometry`] traits.\n///\n/// For a geometric type `T`, the following table illustrates the elisions in\n/// which `T` may participate:\n///\n/// | Bounds on `T`            | From | Into |\n/// |--------------------------|------|------|\n/// | `UnitGeometry`           | `T`  | `()` |\n/// | `Default + UnitGeometry` | `()` | `T`  |\n///\n/// These conversions are useful when converting between mesh data structures\n/// with incompatible geometry, such as from a [`MeshGraph`] with face geometry\n/// to a [`MeshBuffer`] that cannot support such geometry.\n///\n/// When geometry features are enabled, `UnitGeometry` is implemented for\n/// integrated foreign types.\n///\n/// [`FromGeometry`]: crate::geometry::FromGeometry\n/// [`IntoGeometry`]: crate::geometry::IntoGeometry\n/// [`MeshBuffer`]: crate::buffer::MeshBuffer\n/// [`MeshGraph`]: crate::graph::MeshGraph\npub trait UnitGeometry {}\n\npub trait IntoGeometry<T> {\n    fn into_geometry(self) -> T;\n}\n\nimpl<T, U> IntoGeometry<U> for T\nwhere\n    U: FromGeometry<T>,\n{\n    fn into_geometry(self) -> U {\n        U::from_geometry(self)\n    }\n}\n\npub trait Metric: Eq + One + Ord + Zero {}\n\nimpl<Q> Metric for Q where Q: Eq + One + Ord + Zero {}\n"
  },
  {
    "path": "plexus/src/geometry/partition.rs",
    "content": "use approx::abs_diff_eq;\nuse num::traits::real::Real;\nuse num::Zero;\nuse std::cmp::Ordering;\nuse theon::query::{Line, Plane};\nuse theon::space::{EuclideanSpace, FiniteDimensional};\nuse typenum::{U1, U2, U3};\n\n// \"Left\" and \"right\" are arbitrary here and refer to the partitioned spaces\n// formed by a geometric entity. This is a point, line, and plane in one, two,\n// three dimensions, respectively.\n#[derive(Clone, Copy, Eq, Hash, PartialEq)]\npub enum BinaryPartition {\n    Left,\n    Right,\n}\n\npub trait PointPartition<S>\nwhere\n    S: EuclideanSpace,\n{\n    fn partition(&self, point: S) -> Option<BinaryPartition>;\n}\n\nimpl<S> PointPartition<S> for S\nwhere\n    S: EuclideanSpace + FiniteDimensional<N = U1>,\n{\n    // TODO: Should `EmptyOrd` be used here?\n    fn partition(&self, point: S) -> Option<BinaryPartition> {\n        let ax = self.into_x();\n        let px = point.into_x();\n        match px.partial_cmp(&ax) {\n            Some(Ordering::Less) => Some(BinaryPartition::Left),\n            Some(Ordering::Greater) => Some(BinaryPartition::Right),\n            _ => None,\n        }\n    }\n}\n\nimpl<S> PointPartition<S> for Line<S>\nwhere\n    S: EuclideanSpace + FiniteDimensional<N = U2>,\n{\n    fn partition(&self, point: S) -> Option<BinaryPartition> {\n        // Compute the determinant of a matrix composed of points along the line\n        // and the queried point. This can also be thought of as a two-\n        // dimensional cross product.\n        // TODO: Perhaps this should be exposed by Theon instead.\n        let (ax, ay) = self.origin.into_xy();\n        let (bx, by) = (self.origin + *self.direction.get()).into_xy();\n        let (px, py) = point.into_xy();\n        let determinant = ((bx - ax) * (py - ay)) - ((by - ay) * (px - ax));\n        if abs_diff_eq!(determinant, Zero::zero()) {\n            None\n        }\n        else {\n            Some(if determinant.is_sign_positive() {\n                BinaryPartition::Left\n            }\n            else {\n                BinaryPartition::Right\n            })\n        }\n    }\n}\n\nimpl<S> PointPartition<S> for Plane<S>\nwhere\n    S: EuclideanSpace + FiniteDimensional<N = U3>,\n{\n    fn partition(&self, point: S) -> Option<BinaryPartition> {\n        let _ = point;\n        todo!()\n    }\n}\n"
  },
  {
    "path": "plexus/src/graph/builder.rs",
    "content": "use crate::builder::{FacetBuilder, MeshBuilder, SurfaceBuilder};\nuse crate::geometry::{FromGeometry, IntoGeometry};\nuse crate::graph::data::GraphData;\nuse crate::graph::face::FaceKey;\nuse crate::graph::mutation::face::{self, FaceInsertCache};\nuse crate::graph::mutation::vertex;\nuse crate::graph::mutation::{Immediate, Mutation};\nuse crate::graph::vertex::VertexKey;\nuse crate::graph::{GraphError, MeshGraph};\nuse crate::transact::{ClosedInput, Transact};\n\npub struct GraphBuilder<G>\nwhere\n    G: GraphData,\n{\n    mutation: Mutation<Immediate<MeshGraph<G>>>,\n}\n\nimpl<G> Default for GraphBuilder<G>\nwhere\n    G: GraphData,\n{\n    fn default() -> Self {\n        GraphBuilder {\n            mutation: Mutation::from(MeshGraph::default()),\n        }\n    }\n}\n\nimpl<G> ClosedInput for GraphBuilder<G>\nwhere\n    G: GraphData,\n{\n    type Input = ();\n}\n\nimpl<G> MeshBuilder for GraphBuilder<G>\nwhere\n    G: GraphData,\n{\n    type Builder = Self;\n\n    type Vertex = G::Vertex;\n    type Facet = G::Face;\n\n    fn surface_with<F, T, E>(&mut self, f: F) -> Result<T, Self::Error>\n    where\n        Self::Error: From<E>,\n        F: FnOnce(&mut Self::Builder) -> Result<T, E>,\n    {\n        f(self).map_err(|error| error.into())\n    }\n}\n\nimpl<G> Transact<<Self as ClosedInput>::Input> for GraphBuilder<G>\nwhere\n    G: GraphData,\n{\n    type Commit = MeshGraph<G>;\n    type Abort = ();\n    type Error = GraphError;\n\n    fn commit(self) -> Result<Self::Commit, (Self::Abort, Self::Error)> {\n        let GraphBuilder { mutation } = self;\n        mutation.commit()\n    }\n\n    fn abort(self) -> Self::Abort {}\n}\n\nimpl<G> SurfaceBuilder for GraphBuilder<G>\nwhere\n    G: GraphData,\n{\n    type Builder = Self;\n    type Key = VertexKey;\n\n    type Vertex = G::Vertex;\n    type Facet = G::Face;\n\n    fn facets_with<F, T, E>(&mut self, f: F) -> Result<T, Self::Error>\n    where\n        Self::Error: From<E>,\n        F: FnOnce(&mut Self::Builder) -> Result<T, E>,\n    {\n        f(self).map_err(|error| error.into())\n    }\n\n    fn insert_vertex<T>(&mut self, data: T) -> Result<Self::Key, Self::Error>\n    where\n        Self::Vertex: FromGeometry<T>,\n    {\n        Ok(vertex::insert(&mut self.mutation, data.into_geometry()))\n    }\n}\n\nimpl<G> FacetBuilder<VertexKey> for GraphBuilder<G>\nwhere\n    G: GraphData,\n{\n    type Facet = G::Face;\n    type Key = FaceKey;\n\n    fn insert_facet<T, U>(&mut self, keys: T, data: U) -> Result<Self::Key, Self::Error>\n    where\n        Self::Facet: FromGeometry<U>,\n        T: AsRef<[VertexKey]>,\n    {\n        let cache = FaceInsertCache::from_storage(&self.mutation, keys.as_ref())?;\n        let data = data.into_geometry();\n        face::insert_with(&mut self.mutation, cache, || (Default::default(), data))\n    }\n}\n"
  },
  {
    "path": "plexus/src/graph/core.rs",
    "content": "use std::marker::PhantomData;\n\nuse crate::entity::storage::{AsStorage, AsStorageMut, Fuse, StorageTarget};\nuse crate::entity::Entity;\nuse crate::graph::data::{GraphData, Parametric};\nuse crate::graph::edge::{Arc, Edge};\nuse crate::graph::face::Face;\nuse crate::graph::vertex::Vertex;\n\n/// A complete core that owns all of its storage.\npub type OwnedCore<G> = Core<\n    G,\n    <Vertex<G> as Entity>::Storage,\n    <Arc<G> as Entity>::Storage,\n    <Edge<G> as Entity>::Storage,\n    <Face<G> as Entity>::Storage,\n>;\n\n/// Adaptable graph representation that can incorporate arbitrary storage.\n///\n/// Cores act as a container for storage that comprises a graph and allow\n/// storage to be moved (_fused_ and _unfused_) as values or references. A core\n/// may or may not own its storage and may or may not provide storage for all\n/// entities. When a core does not own its storage, it is _ephemeral_.\n///\n/// Cores are used by the mutation API to unfuse storage and guard it behind\n/// per-entity APIs. Unlike `MeshGraph`, `Core` does not implement the\n/// `Consistent` trait.  `MeshGraph` contains a core, but does not mutate it\n/// outside of the mutation API, which maintains consistency.\n///\n/// A core's fields may be _unfused_ and _fused_. When a field is unfused, its\n/// type is `()`. An unfused field has no value and is zero-sized. A fused field\n/// has any type other than `()`. These fields should provide storage for their\n/// corresponding entity. The `Fuse` trait is used to transition from `()` to\n/// some other type by _fusing_ storage into a `Core`. `Fuse` implementations\n/// enforce storage constraints; it is not possible to fuse values that do not\n/// expose storage to yet unfused entities.\n///\n/// A `Core` with no unfused fields is _complete_.\npub struct Core<G, V = (), A = (), E = (), F = ()>\nwhere\n    G: GraphData,\n{\n    pub(in crate::graph) vertices: V,\n    pub(in crate::graph) arcs: A,\n    pub(in crate::graph) edges: E,\n    pub(in crate::graph) faces: F,\n    phantom: PhantomData<fn() -> G>,\n}\n\nimpl<G> Core<G>\nwhere\n    G: GraphData,\n{\n    pub fn empty() -> Self {\n        Core {\n            vertices: (),\n            arcs: (),\n            edges: (),\n            faces: (),\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<G, V, A, E, F> Core<G, V, A, E, F>\nwhere\n    G: GraphData,\n{\n    pub fn unfuse(self) -> (V, A, E, F) {\n        let Core {\n            vertices,\n            arcs,\n            edges,\n            faces,\n            ..\n        } = self;\n        (vertices, arcs, edges, faces)\n    }\n}\n\nimpl<G, V, A, E, F> AsStorage<Vertex<G>> for Core<G, V, A, E, F>\nwhere\n    V: AsStorage<Vertex<G>>,\n    G: GraphData,\n{\n    fn as_storage(&self) -> &StorageTarget<Vertex<G>> {\n        self.vertices.as_storage()\n    }\n}\n\nimpl<G, V, A, E, F> AsStorage<Arc<G>> for Core<G, V, A, E, F>\nwhere\n    A: AsStorage<Arc<G>>,\n    G: GraphData,\n{\n    fn as_storage(&self) -> &StorageTarget<Arc<G>> {\n        self.arcs.as_storage()\n    }\n}\n\nimpl<G, V, A, E, F> AsStorage<Edge<G>> for Core<G, V, A, E, F>\nwhere\n    E: AsStorage<Edge<G>>,\n    G: GraphData,\n{\n    fn as_storage(&self) -> &StorageTarget<Edge<G>> {\n        self.edges.as_storage()\n    }\n}\n\nimpl<G, V, A, E, F> AsStorage<Face<G>> for Core<G, V, A, E, F>\nwhere\n    F: AsStorage<Face<G>>,\n    G: GraphData,\n{\n    fn as_storage(&self) -> &StorageTarget<Face<G>> {\n        self.faces.as_storage()\n    }\n}\n\nimpl<G, V, A, E, F> AsStorageMut<Vertex<G>> for Core<G, V, A, E, F>\nwhere\n    V: AsStorageMut<Vertex<G>>,\n    G: GraphData,\n{\n    fn as_storage_mut(&mut self) -> &mut StorageTarget<Vertex<G>> {\n        self.vertices.as_storage_mut()\n    }\n}\n\nimpl<G, V, A, E, F> AsStorageMut<Arc<G>> for Core<G, V, A, E, F>\nwhere\n    A: AsStorageMut<Arc<G>>,\n    G: GraphData,\n{\n    fn as_storage_mut(&mut self) -> &mut StorageTarget<Arc<G>> {\n        self.arcs.as_storage_mut()\n    }\n}\n\nimpl<G, V, A, E, F> AsStorageMut<Edge<G>> for Core<G, V, A, E, F>\nwhere\n    E: AsStorageMut<Edge<G>>,\n    G: GraphData,\n{\n    fn as_storage_mut(&mut self) -> &mut StorageTarget<Edge<G>> {\n        self.edges.as_storage_mut()\n    }\n}\n\nimpl<G, V, A, E, F> AsStorageMut<Face<G>> for Core<G, V, A, E, F>\nwhere\n    F: AsStorageMut<Face<G>>,\n    G: GraphData,\n{\n    fn as_storage_mut(&mut self) -> &mut StorageTarget<Face<G>> {\n        self.faces.as_storage_mut()\n    }\n}\n\nimpl<G, V, A, E, F> Default for Core<G, V, A, E, F>\nwhere\n    G: GraphData,\n    V: Default,\n    A: Default,\n    E: Default,\n    F: Default,\n{\n    fn default() -> Self {\n        Core {\n            vertices: Default::default(),\n            arcs: Default::default(),\n            edges: Default::default(),\n            faces: Default::default(),\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<G, V, A, E, F> Fuse<V, Vertex<G>> for Core<G, (), A, E, F>\nwhere\n    V: AsStorage<Vertex<G>>,\n    G: GraphData,\n{\n    type Output = Core<G, V, A, E, F>;\n\n    fn fuse(self, vertices: V) -> Self::Output {\n        let Core {\n            arcs, edges, faces, ..\n        } = self;\n        Core {\n            vertices,\n            arcs,\n            edges,\n            faces,\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<G, V, A, E, F> Fuse<A, Arc<G>> for Core<G, V, (), E, F>\nwhere\n    A: AsStorage<Arc<G>>,\n    G: GraphData,\n{\n    type Output = Core<G, V, A, E, F>;\n\n    fn fuse(self, arcs: A) -> Self::Output {\n        let Core {\n            vertices,\n            edges,\n            faces,\n            ..\n        } = self;\n        Core {\n            vertices,\n            arcs,\n            edges,\n            faces,\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<G, V, A, E, F> Fuse<E, Edge<G>> for Core<G, V, A, (), F>\nwhere\n    E: AsStorage<Edge<G>>,\n    G: GraphData,\n{\n    type Output = Core<G, V, A, E, F>;\n\n    fn fuse(self, edges: E) -> Self::Output {\n        let Core {\n            vertices,\n            arcs,\n            faces,\n            ..\n        } = self;\n        Core {\n            vertices,\n            arcs,\n            edges,\n            faces,\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<G, V, A, E, F> Fuse<F, Face<G>> for Core<G, V, A, E, ()>\nwhere\n    F: AsStorage<Face<G>>,\n    G: GraphData,\n{\n    type Output = Core<G, V, A, E, F>;\n\n    fn fuse(self, faces: F) -> Self::Output {\n        let Core {\n            vertices,\n            arcs,\n            edges,\n            ..\n        } = self;\n        Core {\n            vertices,\n            arcs,\n            edges,\n            faces,\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<G, V, A, E, F> Parametric for Core<G, V, A, E, F>\nwhere\n    G: GraphData,\n{\n    type Data = G;\n}\n"
  },
  {
    "path": "plexus/src/graph/data.rs",
    "content": "use crate::entity::borrow::Reborrow;\n\npub type Data<M> = <M as Parametric>::Data;\n\n/// Graph data.\n///\n/// Specifies the types used to represent data in vertices, arcs, edges, and\n/// faces in a [`MeshGraph`]. Arbitrary types can be used, including the unit\n/// type `()` for no data at all.\n///\n/// Geometric operations depend on understanding the positional data in vertices\n/// exposed by the [`AsPosition`] trait. If the `Vertex` type implements\n/// [`AsPosition`], then geometric operations supported by the `Position` type\n/// are exposed by graph APIs.\n///\n/// # Examples\n///\n/// ```rust\n/// # extern crate decorum;\n/// # extern crate nalgebra;\n/// # extern crate num;\n/// # extern crate plexus;\n/// #\n/// use decorum::R64;\n/// use nalgebra::{Point3, Vector4};\n/// use num::Zero;\n/// use plexus::geometry::{AsPosition, IntoGeometry};\n/// use plexus::graph::{GraphData, MeshGraph};\n/// use plexus::prelude::*;\n/// use plexus::primitive::generate::Position;\n/// use plexus::primitive::sphere::UvSphere;\n///\n/// #[derive(Clone, Copy, Eq, Hash, PartialEq)]\n/// pub struct Vertex {\n///     pub position: Point3<R64>,\n///     pub color: Vector4<R64>,\n/// }\n///\n/// impl GraphData for Vertex {\n///     type Vertex = Self;\n///     type Arc = ();\n///     type Edge = ();\n///     type Face = ();\n/// }\n///\n/// impl AsPosition for Vertex {\n///     type Position = Point3<R64>;\n///\n///     fn as_position(&self) -> &Self::Position {\n///         &self.position\n///     }\n/// }\n///\n/// // Create a mesh from a uv-sphere.\n/// let mut graph: MeshGraph<Vertex> = UvSphere::new(8, 8)\n///     .polygons::<Position<Point3<R64>>>()\n///     .map_vertices(|position| Vertex {\n///         position,\n///         color: Zero::zero(),\n///     })\n///     .collect();\n/// ```\n///\n/// [`AsPosition`]: crate::geometry::AsPosition\n/// [`MeshGraph`]: crate::graph::MeshGraph\npub trait GraphData: Sized {\n    type Vertex: Clone;\n    type Arc: Clone + Default;\n    type Edge: Clone + Default;\n    type Face: Clone + Default;\n}\n\nimpl GraphData for () {\n    type Vertex = ();\n    type Arc = ();\n    type Edge = ();\n    type Face = ();\n}\n\nimpl<T> GraphData for (T, T)\nwhere\n    T: Clone,\n{\n    type Vertex = Self;\n    type Arc = ();\n    type Edge = ();\n    type Face = ();\n}\n\nimpl<T> GraphData for (T, T, T)\nwhere\n    T: Clone,\n{\n    type Vertex = Self;\n    type Arc = ();\n    type Edge = ();\n    type Face = ();\n}\n\nimpl<T> GraphData for [T; 2]\nwhere\n    T: Clone,\n{\n    type Vertex = Self;\n    type Arc = ();\n    type Edge = ();\n    type Face = ();\n}\n\nimpl<T> GraphData for [T; 3]\nwhere\n    T: Clone,\n{\n    type Vertex = Self;\n    type Arc = ();\n    type Edge = ();\n    type Face = ();\n}\n\npub trait Parametric {\n    type Data: GraphData;\n}\n\nimpl<B> Parametric for B\nwhere\n    B: Reborrow,\n    B::Target: Parametric,\n{\n    type Data = <B::Target as Parametric>::Data;\n}\n"
  },
  {
    "path": "plexus/src/graph/edge.rs",
    "content": "use arrayvec::ArrayVec;\nuse derivative::Derivative;\nuse std::borrow::Borrow;\nuse std::hash::{Hash, Hasher};\nuse std::ops::{Deref, DerefMut};\nuse theon::space::{EuclideanSpace, Scalar, Vector};\nuse theon::{AsPosition, AsPositionMut};\n\nuse crate::entity::borrow::{Reborrow, ReborrowInto, ReborrowMut};\nuse crate::entity::storage::{AsStorage, AsStorageMut, HashStorage, IncrementalKeyer, Key};\nuse crate::entity::view::{Bind, ClosedView, Orphan, Rebind, Unbind, View};\nuse crate::entity::{Entity, Payload};\nuse crate::graph::data::{Data, GraphData, Parametric};\nuse crate::graph::face::{Face, FaceKey, FaceOrphan, FaceView, Ring};\nuse crate::graph::geometry::{ArcNormal, EdgeMidpoint, VertexPosition};\nuse crate::graph::mutation::edge::{\n    self, ArcBridgeCache, ArcExtrudeCache, EdgeRemoveCache, EdgeSplitCache,\n};\nuse crate::graph::mutation::{self, Consistent, Immediate, Mutable};\nuse crate::graph::path::Path;\nuse crate::graph::vertex::{Vertex, VertexKey, VertexOrphan, VertexView};\nuse crate::graph::{\n    Circulator, GraphError, OptionExt as _, OrphanCirculator, ResultExt as _, Selector,\n    ViewCirculator,\n};\nuse crate::transact::{BypassOrCommit, Mutate};\n\ntype Mutation<M> = mutation::Mutation<Immediate<M>>;\n\npub trait ToArc<B>: Sized\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Arc<Data<B>>> + AsStorage<Edge<Data<B>>> + Consistent + Parametric,\n{\n    fn into_arc(self) -> ArcView<B>;\n\n    fn arc(&self) -> ArcView<&B::Target>;\n}\n\n// Unlike other graph structures, the vertex connectivity of an arc is immutable\n// and encoded within its key. This provides fast and reliable lookups even when\n// a graph is in an inconsistent state. However, it also complicates certain\n// topological mutations and sometimes requires that arcs be rekeyed. For this\n// reason, `Arc` has no fields representing its source and destination vertices\n// nor its opposite arc; such fields would be redundant.\n/// Arc entity.\n#[derive(Derivative)]\n#[derivative(Debug, Hash)]\npub struct Arc<G>\nwhere\n    G: GraphData,\n{\n    /// User data.\n    #[derivative(Debug = \"ignore\", Hash = \"ignore\")]\n    pub(crate) data: G::Arc,\n    /// Required key into the next arc.\n    pub(crate) next: Option<ArcKey>,\n    /// Required key into the previous arc.\n    pub(crate) previous: Option<ArcKey>,\n    /// Required key into the edge.\n    pub(crate) edge: Option<EdgeKey>,\n    /// Optional key into the face.\n    pub(crate) face: Option<FaceKey>,\n}\n\nimpl<G> Arc<G>\nwhere\n    G: GraphData,\n{\n    pub fn new(data: G::Arc) -> Self {\n        Arc {\n            data,\n            next: None,\n            previous: None,\n            edge: None,\n            face: None,\n        }\n    }\n}\n\nimpl<G> Entity for Arc<G>\nwhere\n    G: GraphData,\n{\n    type Key = ArcKey;\n    type Storage = HashStorage<Self>;\n}\n\nimpl<G> Payload for Arc<G>\nwhere\n    G: GraphData,\n{\n    type Data = G::Arc;\n\n    fn get(&self) -> &Self::Data {\n        &self.data\n    }\n\n    fn get_mut(&mut self) -> &mut Self::Data {\n        &mut self.data\n    }\n}\n\n/// Arc key.\n#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]\npub struct ArcKey(VertexKey, VertexKey);\n\nimpl ArcKey {\n    pub(in crate::graph) fn into_opposite(self) -> ArcKey {\n        let (a, b) = self.into();\n        (b, a).into()\n    }\n}\n\nimpl From<(VertexKey, VertexKey)> for ArcKey {\n    fn from(key: (VertexKey, VertexKey)) -> Self {\n        ArcKey(key.0, key.1)\n    }\n}\n\nimpl From<ArcKey> for (VertexKey, VertexKey) {\n    fn from(key: ArcKey) -> Self {\n        (key.0, key.1)\n    }\n}\n\nimpl Key for ArcKey {\n    type Inner = (VertexKey, VertexKey);\n\n    fn from_inner(key: Self::Inner) -> Self {\n        ArcKey(key.0, key.1)\n    }\n\n    fn into_inner(self) -> Self::Inner {\n        (self.0, self.1)\n    }\n}\n\n/// View of an arc entity.\n///\n/// An arc from a vertex $A$ to a vertex $B$ is notated $\\overrightarrow{AB}$.\n/// This is shorthand for the path notation $\\overrightarrow{(A,B)}$.\n///\n/// Arcs provide the connectivity information within a [`MeshGraph`] and are the\n/// primary mechanism for traversing its topology. Moreover, most edge-like\n/// operations are exposed by arcs.\n///\n/// See the [`graph`] module documentation for more information about views.\n///\n/// # Examples\n///\n/// Traversing a [`MeshGraph`] of a cube via its arcs to find an opposing face:\n///\n/// ```rust\n/// # extern crate decorum;\n/// # extern crate nalgebra;\n/// # extern crate plexus;\n/// #\n/// use decorum::R64;\n/// use nalgebra::Point3;\n/// use plexus::graph::MeshGraph;\n/// use plexus::index::HashIndexer;\n/// use plexus::prelude::*;\n/// use plexus::primitive::cube::Cube;\n/// use plexus::primitive::generate::Position;\n///\n/// type E3 = Point3<R64>;\n///\n/// let mut graph: MeshGraph<E3> = Cube::new()\n///     .polygons::<Position<E3>>()\n///     .collect_with_indexer(HashIndexer::default())\n///     .unwrap();\n///\n/// let face = graph.faces().next().unwrap();\n/// let opposite = face\n///     .into_arc()\n///     .into_opposite_arc()\n///     .into_next_arc()\n///     .into_next_arc()\n///     .into_opposite_arc()\n///     .into_face()\n///     .unwrap();\n/// ```\n///\n/// [`MeshGraph`]: crate::graph::MeshGraph\n/// [`graph`]: crate::graph\npub struct ArcView<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Arc<Data<B>>> + Parametric,\n{\n    inner: View<B, Arc<Data<B>>>,\n}\n\nimpl<B, M> ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<Data<B>>> + Parametric,\n{\n    pub fn to_ref(&self) -> ArcView<&M> {\n        self.inner.to_ref().into()\n    }\n\n    /// Returns `true` if this is a boundary arc.\n    ///\n    /// A boundary arc has no associated face.\n    pub fn is_boundary_arc(&self) -> bool {\n        self.face.is_none()\n    }\n}\n\nimpl<B, M> ArcView<B>\nwhere\n    B: ReborrowMut<Target = M>,\n    M: AsStorage<Arc<Data<B>>> + Parametric,\n{\n    // This function is also used to implement `Ring::to_mut_unchecked`.\n    // LINT: This convention is specifically used for interior reborrows and is consistent with\n    //       `to_ref`.\n    #[expect(clippy::wrong_self_convention)]\n    pub(in crate::graph) fn to_mut_unchecked(&mut self) -> ArcView<&mut M> {\n        self.inner.to_mut_unchecked().into()\n    }\n}\n\nimpl<'a, B, M, G> ArcView<B>\nwhere\n    B: ReborrowInto<'a, Target = M>,\n    M: AsStorage<Arc<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    // TODO: Relocate this documentation of `into_ref`.\n    /// # Examples\n    ///\n    /// ```rust\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use nalgebra::Point2;\n    /// use plexus::graph::MeshGraph;\n    /// use plexus::prelude::*;\n    ///\n    /// let mut graph = MeshGraph::<Point2<f64>>::from_raw_buffers_with_arity(\n    ///     vec![0u32, 1, 2, 3],\n    ///     vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)],\n    ///     4,\n    /// )\n    /// .unwrap();\n    /// let key = graph\n    ///     .arcs()\n    ///     .find(|arc| arc.is_boundary_arc())\n    ///     .unwrap()\n    ///     .key();\n    /// let arc = graph\n    ///     .arc_mut(key)\n    ///     .unwrap()\n    ///     .extrude_with_offset(1.0)\n    ///     .unwrap()\n    ///     .into_ref();\n    ///\n    /// // This would not be possible without conversion into an immutable view.\n    /// let _ = arc.into_next_arc().into_next_arc().into_face();\n    /// let _ = arc.into_opposite_arc().into_face();\n    /// ```\n    pub fn into_ref(self) -> ArcView<&'a M> {\n        self.inner.into_ref().into()\n    }\n}\n\nimpl<B, M, G> ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn get<'a>(&'a self) -> &'a G::Arc\n    where\n        G: 'a,\n    {\n        self.inner.get()\n    }\n}\n\nimpl<B, M, G> ArcView<B>\nwhere\n    B: ReborrowMut<Target = M>,\n    M: AsStorageMut<Arc<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn get_mut<'a>(&'a mut self) -> &'a mut G::Arc\n    where\n        G: 'a,\n    {\n        self.inner.get_mut()\n    }\n}\n\n/// Reachable API.\nimpl<B, M, G> ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub(in crate::graph) fn into_reachable_boundary_arc(self) -> Option<Self> {\n        if self.is_boundary_arc() {\n            Some(self)\n        }\n        else {\n            self.into_reachable_opposite_arc()\n                .and_then(|opposite| opposite.is_boundary_arc().then_some(opposite))\n        }\n    }\n\n    pub(in crate::graph) fn into_reachable_opposite_arc(self) -> Option<Self> {\n        let key = self.key().into_opposite();\n        self.rebind(key)\n    }\n\n    pub(in crate::graph) fn into_reachable_next_arc(self) -> Option<Self> {\n        let key = self.next;\n        key.and_then(|key| self.rebind(key))\n    }\n\n    pub(in crate::graph) fn into_reachable_previous_arc(self) -> Option<Self> {\n        let key = self.previous;\n        key.and_then(|key| self.rebind(key))\n    }\n}\n\nimpl<B, M, G> ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    /// Converts the arc into its ring.\n    pub fn into_ring(self) -> Ring<B> {\n        self.into()\n    }\n\n    /// Returns the arc if it is a boundary arc, otherwise `None`.\n    pub fn into_boundary_arc(self) -> Option<Self> {\n        self.into_reachable_boundary_arc()\n    }\n\n    /// Converts the arc into its opposite arc.\n    // Arcs are unique in that they have one-to-one traversals over themselves.\n    #[must_use]\n    pub fn into_opposite_arc(self) -> Self {\n        self.into_reachable_opposite_arc().expect_consistent()\n    }\n\n    /// Converts the arc into its next arc.\n    // Arcs are unique in that they have one-to-one traversals over themselves.\n    #[must_use]\n    pub fn into_next_arc(self) -> Self {\n        self.into_reachable_next_arc().expect_consistent()\n    }\n\n    /// Converts the arc into its previous arc.\n    // Arcs are unique in that they have one-to-one traversals over themselves.\n    #[must_use]\n    pub fn into_previous_arc(self) -> Self {\n        self.into_reachable_previous_arc().expect_consistent()\n    }\n\n    /// Gets the ring of the arc.\n    pub fn ring(&self) -> Ring<&M> {\n        self.to_ref().into()\n    }\n\n    /// Returns the same arc if it is a boundary arc, otherwise `None`.\n    pub fn boundary_arc(&self) -> Option<ArcView<&M>> {\n        self.to_ref().into_boundary_arc()\n    }\n\n    /// Gets the opposite arc.\n    pub fn opposite_arc(&self) -> ArcView<&M> {\n        self.to_ref().into_opposite_arc()\n    }\n\n    /// Gets the next arc.\n    pub fn next_arc(&self) -> ArcView<&M> {\n        self.to_ref().into_next_arc()\n    }\n\n    /// Gets the previous arc.\n    pub fn previous_arc(&self) -> ArcView<&M> {\n        self.to_ref().into_previous_arc()\n    }\n}\n\n/// Reachable API.\nimpl<B, M, G> ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub(in crate::graph) fn into_reachable_source_vertex(self) -> Option<VertexView<B>> {\n        let (key, _) = self.key().into();\n        self.rebind(key)\n    }\n\n    pub(in crate::graph) fn into_reachable_destination_vertex(self) -> Option<VertexView<B>> {\n        let (_, key) = self.key().into();\n        self.rebind(key)\n    }\n}\n\nimpl<B, M, G> ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn into_path(self) -> Path<'static, B> {\n        let (storage, ab) = self.unbind();\n        let (a, b) = ab.into();\n        Path::bind(storage, [a, b]).unwrap()\n    }\n\n    pub fn path(&self) -> Path<&M> {\n        self.to_ref().into_path()\n    }\n\n    /// Converts the arc into its source vertex.\n    pub fn into_source_vertex(self) -> VertexView<B> {\n        self.into_reachable_source_vertex().expect_consistent()\n    }\n\n    /// Converts the arc into its destination vertex.\n    pub fn into_destination_vertex(self) -> VertexView<B> {\n        self.into_reachable_destination_vertex().expect_consistent()\n    }\n\n    /// Gets the source vertex of the arc.\n    pub fn source_vertex(&self) -> VertexView<&M> {\n        self.to_ref().into_source_vertex()\n    }\n\n    /// Gets the destination vertex of the arc.\n    pub fn destination_vertex(&self) -> VertexView<&M> {\n        self.to_ref().into_destination_vertex()\n    }\n}\n\n/// Reachable API.\nimpl<B, M, G> ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Edge<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub(in crate::graph) fn into_reachable_edge(self) -> Option<EdgeView<B>> {\n        let key = self.edge;\n        key.and_then(|key| self.rebind(key))\n    }\n}\n\nimpl<B, M, G> ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Edge<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    /// Converts the arc into its edge.\n    pub fn into_edge(self) -> EdgeView<B> {\n        self.into_reachable_edge().expect_consistent()\n    }\n\n    /// Gets the edge of the arc.\n    pub fn edge(&self) -> EdgeView<&M> {\n        self.to_ref().into_edge()\n    }\n}\n\n/// Reachable API.\nimpl<B, M, G> ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub(in crate::graph) fn into_reachable_face(self) -> Option<FaceView<B>> {\n        let key = self.face;\n        key.and_then(|key| self.rebind(key))\n    }\n}\n\nimpl<B, M, G> ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Face<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    /// Converts the arc into its face.\n    ///\n    /// If this is a boundary arc, then `None` is returned.\n    pub fn into_face(self) -> Option<FaceView<B>> {\n        self.into_reachable_face()\n    }\n\n    /// Gets the face of this arc.\n    ///\n    /// If this is a boundary arc, then `None` is returned.\n    pub fn face(&self) -> Option<FaceView<&M>> {\n        self.to_ref().into_face()\n    }\n}\n\nimpl<B, M, G> ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn normal(&self) -> Vector<VertexPosition<G>>\n    where\n        G: ArcNormal,\n        G::Vertex: AsPosition,\n    {\n        <G as ArcNormal>::normal(self.to_ref()).expect_consistent()\n    }\n}\n\nimpl<B, M, G> ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>>\n        + AsStorage<Edge<G>>\n        + AsStorage<Vertex<G>>\n        + Consistent\n        + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn midpoint(&self) -> VertexPosition<G>\n    where\n        G: EdgeMidpoint,\n        G::Vertex: AsPosition,\n    {\n        G::midpoint(self.to_ref()).expect_consistent()\n    }\n}\n\nimpl<'a, B, M, G> ArcView<B>\nwhere\n    B: ReborrowInto<'a, Target = M>,\n    M: 'a + AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn into_adjacent_vertices(\n        self,\n    ) -> impl Clone + ExactSizeIterator<Item = VertexView<&'a M>> {\n        VertexCirculator::from(self.into_ref())\n    }\n}\n\nimpl<B, G> ArcView<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    /// Gets an iterator of views over the vertices connected by the arc.\n    pub fn adjacent_vertices(\n        &self,\n    ) -> impl Clone + ExactSizeIterator<Item = VertexView<&B::Target>> {\n        self.to_ref().into_adjacent_vertices()\n    }\n}\n\nimpl<'a, B, M, G> ArcView<B>\nwhere\n    B: ReborrowInto<'a, Target = M>,\n    M: 'a + AsStorage<Arc<G>> + AsStorage<Face<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn into_adjacent_faces(self) -> impl Clone + ExactSizeIterator<Item = FaceView<&'a M>> {\n        FaceCirculator::from(self.into_ref())\n    }\n}\n\nimpl<B, G> ArcView<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Arc<G>> + AsStorage<Face<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    /// Gets an iterator of views over the faces connected to the arc.\n    pub fn adjacent_faces(&self) -> impl Clone + ExactSizeIterator<Item = FaceView<&B::Target>> {\n        self.to_ref().into_adjacent_faces()\n    }\n}\n\nimpl<'a, M> ArcView<&'a mut M>\nwhere\n    M: AsStorage<Arc<M::Data>> + AsStorageMut<Vertex<M::Data>> + Consistent + Parametric,\n{\n    pub fn into_adjacent_vertex_orphans(\n        self,\n    ) -> impl ExactSizeIterator<Item = VertexOrphan<'a, M::Data>> {\n        VertexCirculator::from(self)\n    }\n}\n\nimpl<B> ArcView<B>\nwhere\n    B: ReborrowMut,\n    B::Target: AsStorage<Arc<Data<B>>> + AsStorageMut<Vertex<Data<B>>> + Consistent + Parametric,\n{\n    /// Gets an iterator of orphan views over the vertices connected by the arc.\n    pub fn adjacent_vertex_orphans(\n        &mut self,\n    ) -> impl ExactSizeIterator<Item = VertexOrphan<Data<B>>> {\n        self.to_mut_unchecked().into_adjacent_vertex_orphans()\n    }\n}\n\nimpl<'a, M> ArcView<&'a mut M>\nwhere\n    M: AsStorage<Arc<M::Data>> + AsStorageMut<Face<M::Data>> + Consistent + Parametric,\n{\n    pub fn into_adjacent_face_orphans(\n        self,\n    ) -> impl ExactSizeIterator<Item = FaceOrphan<'a, M::Data>> {\n        FaceCirculator::from(self)\n    }\n}\n\nimpl<B> ArcView<B>\nwhere\n    B: ReborrowMut,\n    B::Target: AsStorage<Arc<Data<B>>> + AsStorageMut<Face<Data<B>>> + Consistent + Parametric,\n{\n    /// Gets an iterator of orphan views over the faces connected to the arc.\n    pub fn adjacent_face_orphans(&mut self) -> impl ExactSizeIterator<Item = FaceOrphan<Data<B>>> {\n        self.to_mut_unchecked().into_adjacent_face_orphans()\n    }\n}\n\nimpl<'a, M, G> ArcView<&'a mut M>\nwhere\n    M: AsStorage<Arc<G>>\n        + AsStorage<Edge<G>>\n        + AsStorage<Face<G>>\n        + AsStorage<Vertex<G>>\n        + Default\n        + Mutable<Data = G>,\n    G: GraphData,\n{\n    /// Splits the composite edge of the arc into two adjacent edges that share\n    /// a vertex.\n    ///\n    /// Splitting inserts a new vertex with data provided by the given function.\n    /// Splitting an arc $\\overrightarrow{AB}$ returns a vertex $M$ that\n    /// subdivides the composite edge. The leading arc of $M$ is\n    /// $\\overrightarrow{MB}$ and is a part of the same ring as the initiating\n    /// arc.\n    ///\n    /// Returns the inserted vertex.\n    ///\n    /// # Examples\n    ///\n    /// Splitting an edge in a [`MeshGraph`] with weighted vertices:\n    ///\n    /// ```rust\n    /// use plexus::graph::{GraphData, MeshGraph};\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::NGon;\n    ///\n    /// pub enum Weight {}\n    ///\n    /// impl GraphData for Weight {\n    ///     type Vertex = f64;\n    ///     type Arc = ();\n    ///     type Edge = ();\n    ///     type Face = ();\n    /// }\n    ///\n    /// let mut graph =\n    ///     MeshGraph::<Weight>::from_raw_buffers(vec![NGon([0usize, 1, 2])], vec![1.0, 2.0, 0.5])\n    ///         .unwrap();\n    /// let key = graph.arcs().next().unwrap().key();\n    /// let vertex = graph.arc_mut(key).unwrap().split_with(|| 0.1);\n    /// ```\n    ///\n    /// [`MeshGraph`]: crate::graph::MeshGraph\n    pub fn split_with<F>(self, f: F) -> VertexView<&'a mut M>\n    where\n        F: FnOnce() -> G::Vertex,\n    {\n        // This should never fail here.\n        let cache = EdgeSplitCache::from_arc(self.to_ref()).expect_consistent();\n        let (storage, _) = self.unbind();\n        Mutation::take(storage)\n            .bypass_or_commit_with(|mutation| edge::split_with(mutation, cache, f))\n            .map(|(storage, m)| Bind::bind(storage, m).expect_consistent())\n            .map_err(|(_, error)| error)\n            .expect_consistent()\n    }\n\n    /// Splits the composite edge of the arc at its midpoint.\n    ///\n    /// Splitting inserts a new vertex with the data of the arc's source vertex\n    /// but modified such that the position of the vertex is the computed\n    /// midpoint of both of the arc's vertices.\n    ///\n    /// Splitting inserts a new vertex with data provided by the given function.\n    /// Splitting an arc $\\overrightarrow{AB}$ returns a vertex $M$ that\n    /// subdivides the composite edge. The leading arc of $M$ is\n    /// $\\overrightarrow{MB}$ and is a part of the same ring as the initiating\n    /// arc.\n    ///\n    /// This function is only available if a [`MeshGraph`] exposes positional\n    /// data in its vertices and that data supports interpolation. See the\n    /// [`EdgeMidpoint`] trait.\n    ///\n    /// Returns the inserted vertex.\n    ///\n    /// # Examples\n    ///\n    /// Splitting an edge in a triangle at its midpoint:\n    ///\n    /// ```rust\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use nalgebra::Point2;\n    /// use plexus::graph::MeshGraph;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::Trigon;\n    ///\n    /// let mut graph = MeshGraph::<Point2<f64>>::from_raw_buffers(\n    ///     vec![Trigon::new(0usize, 1, 2)],\n    ///     vec![(0.0, 0.0), (1.0, 0.0), (0.0, 1.0)],\n    /// )\n    /// .unwrap();\n    /// let key = graph.arcs().next().unwrap().key();\n    /// let vertex = graph.arc_mut(key).unwrap().split_at_midpoint();\n    /// ```\n    ///\n    /// [`EdgeMidpoint`]: crate::graph::EdgeMidpoint\n    /// [`MeshGraph`]: crate::graph::MeshGraph\n    pub fn split_at_midpoint(self) -> VertexView<&'a mut M>\n    where\n        G: EdgeMidpoint,\n        G::Vertex: AsPositionMut + Clone,\n    {\n        let mut data = self.source_vertex().get().clone();\n        let midpoint = self.midpoint();\n        self.split_with(move || {\n            *data.as_position_mut() = midpoint;\n            data\n        })\n    }\n\n    // TODO: What if an edge in the bridging quadrilateral is collapsed, such as\n    //       bridging arcs within a triangular ring? Document these edge cases\n    //       (no pun intended).\n    /// Connects the arc to another arc by inserting a face.\n    ///\n    /// Bridging arcs inserts a new face and, as needed, new arcs and edges.\n    /// The inserted face is always a quadrilateral. The bridged arcs must be\n    /// boundary arcs with an orientation that allows them to form a ring.\n    ///\n    /// Bridging two compatible arcs $\\overrightarrow{AB}$ and\n    /// $\\overrightarrow{CD}$ will result in a ring $\\overrightarrow{\\\\{A,B,\n    /// C,D\\\\}}$.\n    ///\n    /// Arcs can be bridged within a ring. The destination arc can be chosen by\n    /// key or index, where an index selects the $n^\\text{th}$ arc from the\n    /// source arc within the ring.\n    ///\n    /// Returns the inserted face.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the destination arc cannot be found, either arc is\n    /// not a boundary arc, or the orientation of the destination arc is\n    /// incompatible with the initiating arc.\n    ///\n    /// # Examples\n    ///\n    /// Bridging two disjoint quadrilaterals together:\n    ///\n    /// ```rust\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use nalgebra::Point2;\n    /// use plexus::geometry::FromGeometry;\n    /// use plexus::graph::{ArcKey, GraphData, MeshGraph, VertexKey, VertexView};\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::NGon;\n    ///\n    /// fn find<'a, I, T, G>(input: I, data: T) -> Option<VertexKey>\n    /// where\n    ///     I: IntoIterator<Item = VertexView<&'a MeshGraph<G>>>,\n    ///     G: 'a + GraphData,\n    ///     G::Vertex: FromGeometry<T> + PartialEq,\n    /// {\n    ///     let data = data.into_geometry();\n    ///     input\n    ///         .into_iter()\n    ///         .find(|vertex| *vertex.get() == data)\n    ///         .map(|vertex| vertex.key())\n    /// }\n    ///\n    /// let mut graph = MeshGraph::<Point2<f64>>::from_raw_buffers(\n    ///     vec![NGon([0usize, 1, 2, 3]), NGon([4, 5, 6, 7])],\n    ///     vec![\n    ///         (-2.0, 0.0),\n    ///         (-1.0, 0.0), // b\n    ///         (-1.0, 1.0), // a\n    ///         (-2.0, 1.0),\n    ///         (1.0, 0.0), // c\n    ///         (2.0, 0.0),\n    ///         (2.0, 1.0),\n    ///         (1.0, 1.0), // d\n    ///     ],\n    /// )\n    /// .unwrap();\n    /// let a = find(graph.vertices(), (-1.0, 1.0)).unwrap();\n    /// let b = find(graph.vertices(), (-1.0, 0.0)).unwrap();\n    /// let c = find(graph.vertices(), (1.0, 0.0)).unwrap();\n    /// let d = find(graph.vertices(), (1.0, 1.0)).unwrap();\n    /// let face = graph\n    ///     .arc_mut(ArcKey::from((a, b)))\n    ///     .unwrap()\n    ///     .bridge(ArcKey::from((c, d)))\n    ///     .unwrap();\n    /// ```\n    pub fn bridge(\n        self,\n        destination: impl Into<Selector<ArcKey>>,\n    ) -> Result<FaceView<&'a mut M>, GraphError> {\n        let destination = destination.into().key_or_else(|index| {\n            self.ring()\n                .arcs()\n                .nth(index)\n                .ok_or(GraphError::TopologyNotFound)\n                .map(|arc| arc.key())\n        })?;\n        let cache = ArcBridgeCache::from_arc(self.to_ref(), destination)?;\n        let (storage, _) = self.unbind();\n        Ok(Mutation::take(storage)\n            .bypass_or_commit_with(|mutation| edge::bridge(mutation, cache))\n            .map(|(storage, face)| Bind::bind(storage, face).expect_consistent())\n            .map_err(|(_, error)| error)\n            .expect_consistent())\n    }\n\n    /// Extrudes the arc along its normal.\n    ///\n    /// The positions of each extruded vertex are translated along the arc's\n    /// normal by the given offset.\n    ///\n    /// An arc's normal is perpendicular to the arc and also coplanar with the\n    /// arc and one of its adjacent arcs. This is computed via a projection and\n    /// supports both 2D and 3D geometries.\n    ///\n    /// Returns the extruded arc, which is in the same ring as the initiating\n    /// arc.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the arc is not a boundary arc.\n    ///\n    /// # Examples\n    ///\n    /// Extrude an exterior arc of a quadrilateral.\n    ///\n    /// ```rust\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use nalgebra::Point2;\n    /// use plexus::graph::MeshGraph;\n    /// use plexus::prelude::*;\n    ///\n    /// let mut graph = MeshGraph::<Point2<f64>>::from_raw_buffers_with_arity(\n    ///     vec![0usize, 1, 2, 3],\n    ///     vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)],\n    ///     4,\n    /// )\n    /// .unwrap();\n    /// let key = graph\n    ///     .arcs()\n    ///     .find(|arc| arc.is_boundary_arc())\n    ///     .map(|arc| arc.key())\n    ///     .unwrap();\n    /// graph\n    ///     .arc_mut(key)\n    ///     .unwrap()\n    ///     .extrude_with_offset(1.0)\n    ///     .unwrap();\n    /// ```\n    pub fn extrude_with_offset<T>(self, offset: T) -> Result<Self, GraphError>\n    where\n        T: Into<Scalar<VertexPosition<G>>>,\n        G: ArcNormal,\n        G::Vertex: AsPositionMut,\n        VertexPosition<G>: EuclideanSpace,\n    {\n        let translation = self.normal() * offset.into();\n        self.extrude_with_translation(translation)\n    }\n\n    /// Extrudes the arc along a translation.\n    ///\n    /// The positions of each extruded vertex are translated by the given\n    /// vector.\n    ///\n    /// Returns the extruded arc, which is in the same ring as the initiating\n    /// arc.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the arc is not a boundary arc.\n    pub fn extrude_with_translation(\n        self,\n        translation: Vector<VertexPosition<G>>,\n    ) -> Result<Self, GraphError>\n    where\n        G::Vertex: AsPositionMut,\n        VertexPosition<G>: EuclideanSpace,\n    {\n        self.extrude_with(|data| data.map_position(|position| *position + translation))\n    }\n\n    /// Extrudes the arc using the given vertex data.\n    ///\n    /// The data of each extruded vertex is determined by the given function,\n    /// which maps the data of each source vertex into the data of the\n    /// corresponding destination vertex.\n    ///\n    /// Returns the extruded arc, which is in the same ring as the initiating\n    /// arc.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the arc is not a boundary arc.\n    pub fn extrude_with<F>(self, f: F) -> Result<Self, GraphError>\n    where\n        F: Fn(G::Vertex) -> G::Vertex,\n    {\n        let cache = ArcExtrudeCache::from_arc(self.to_ref())?;\n        let (storage, _) = self.unbind();\n        Ok(Mutation::take(storage)\n            .bypass_or_commit_with(|mutation| edge::extrude_with(mutation, cache, f))\n            .map(|(storage, arc)| Bind::bind(storage, arc).expect_consistent())\n            .map_err(|(_, error)| error)\n            .expect_consistent())\n    }\n\n    /// Removes the arc and its composite edge.\n    ///\n    /// Any and all dependent entities are also removed, such as connected\n    /// faces, disjoint vertices, etc.\n    ///\n    /// Returns the source vertex of the initiating arc or `None` if that vertex\n    /// becomes disjoint and is also removed. If an arc $\\overrightarrow{AB}$ is\n    /// removed and its source vertex is not disjoint, then $A$ is returned.\n    pub fn remove(self) -> Option<VertexView<&'a mut M>> {\n        let a = self.source_vertex().key();\n        // This should never fail here.\n        let cache = EdgeRemoveCache::from_arc(self.to_ref()).expect_consistent();\n        let (storage, _) = self.unbind();\n        Mutation::take(storage)\n            .bypass_or_commit_with(|mutation| edge::remove(mutation, cache))\n            .map(|(storage, _)| Bind::bind(storage, a))\n            .map_err(|(_, error)| error)\n            .expect_consistent()\n    }\n}\n\nimpl<B> Borrow<ArcKey> for ArcView<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Arc<Data<B>>> + Parametric,\n{\n    fn borrow(&self) -> &ArcKey {\n        self.inner.as_ref()\n    }\n}\n\nimpl<B, M, G> Clone for ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Parametric<Data = G>,\n    G: GraphData,\n    View<B, Arc<G>>: Clone,\n{\n    fn clone(&self) -> Self {\n        ArcView {\n            inner: self.inner.clone(),\n        }\n    }\n}\n\nimpl<B, M, G> ClosedView for ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Key = ArcKey;\n    type Entity = Arc<G>;\n\n    /// Gets the key for the arc.\n    fn key(&self) -> Self::Key {\n        self.inner.key()\n    }\n}\n\nimpl<B, M, G> Copy for ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Parametric<Data = G>,\n    G: GraphData,\n    View<B, Arc<G>>: Copy,\n{\n}\n\nimpl<B, M, G> Deref for ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Target = Arc<G>;\n\n    fn deref(&self) -> &Self::Target {\n        self.inner.deref()\n    }\n}\n\nimpl<B, M, G> DerefMut for ArcView<B>\nwhere\n    B: ReborrowMut<Target = M>,\n    M: AsStorageMut<Arc<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        self.inner.deref_mut()\n    }\n}\n\nimpl<B, M, G> Eq for ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n}\n\nimpl<B, M, G> From<Ring<B>> for ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn from(ring: Ring<B>) -> Self {\n        ring.into_arc()\n    }\n}\n\nimpl<B, M, G> From<View<B, Arc<G>>> for ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn from(view: View<B, Arc<G>>) -> Self {\n        ArcView { inner: view }\n    }\n}\n\nimpl<B, M, G> From<ArcView<B>> for View<B, Arc<G>>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn from(arc: ArcView<B>) -> Self {\n        let ArcView { inner, .. } = arc;\n        inner\n    }\n}\n\nimpl<B, M, G> Hash for ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn hash<H>(&self, state: &mut H)\n    where\n        H: Hasher,\n    {\n        self.inner.hash(state);\n    }\n}\n\nimpl<B, M, G> PartialEq for ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn eq(&self, other: &Self) -> bool {\n        self.inner == other.inner\n    }\n}\n\nimpl<B, M, G> ToArc<B> for ArcView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Edge<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn into_arc(self) -> ArcView<B> {\n        self\n    }\n\n    fn arc(&self) -> ArcView<&M> {\n        self.to_ref()\n    }\n}\n\n/// Orphan view of an arc entity.\npub struct ArcOrphan<'a, G>\nwhere\n    G: GraphData,\n{\n    inner: Orphan<'a, Arc<G>>,\n}\n\nimpl<G> ArcOrphan<'_, G>\nwhere\n    G: GraphData,\n{\n    pub fn get(&self) -> &G::Arc {\n        self.inner.get()\n    }\n\n    pub fn get_mut(&mut self) -> &mut G::Arc {\n        self.inner.get_mut()\n    }\n}\n\nimpl<G> Borrow<ArcKey> for ArcOrphan<'_, G>\nwhere\n    G: GraphData,\n{\n    fn borrow(&self) -> &ArcKey {\n        self.inner.as_ref()\n    }\n}\n\nimpl<G> ClosedView for ArcOrphan<'_, G>\nwhere\n    G: GraphData,\n{\n    type Key = ArcKey;\n    type Entity = Arc<G>;\n\n    fn key(&self) -> Self::Key {\n        self.inner.key()\n    }\n}\n\nimpl<G> Eq for ArcOrphan<'_, G> where G: GraphData {}\n\nimpl<'a, M> From<ArcView<&'a mut M>> for ArcOrphan<'a, M::Data>\nwhere\n    M: AsStorageMut<Arc<M::Data>> + Parametric,\n{\n    fn from(arc: ArcView<&'a mut M>) -> Self {\n        Orphan::from(arc.inner).into()\n    }\n}\n\nimpl<'a, G> From<Orphan<'a, Arc<G>>> for ArcOrphan<'a, G>\nwhere\n    G: GraphData,\n{\n    fn from(inner: Orphan<'a, Arc<G>>) -> Self {\n        ArcOrphan { inner }\n    }\n}\n\nimpl<'a, M> From<View<&'a mut M, Arc<M::Data>>> for ArcOrphan<'a, M::Data>\nwhere\n    M: AsStorageMut<Arc<M::Data>> + Parametric,\n{\n    fn from(view: View<&'a mut M, Arc<M::Data>>) -> Self {\n        ArcOrphan { inner: view.into() }\n    }\n}\n\nimpl<G> Hash for ArcOrphan<'_, G>\nwhere\n    G: GraphData,\n{\n    fn hash<H>(&self, state: &mut H)\n    where\n        H: Hasher,\n    {\n        self.inner.hash(state);\n    }\n}\n\nimpl<G> PartialEq for ArcOrphan<'_, G>\nwhere\n    G: GraphData,\n{\n    fn eq(&self, other: &Self) -> bool {\n        self.inner == other.inner\n    }\n}\n\n/// Edge entity.\n#[derive(Derivative)]\n#[derivative(Debug, Hash)]\npub struct Edge<G>\nwhere\n    G: GraphData,\n{\n    /// User data.\n    #[derivative(Debug = \"ignore\", Hash = \"ignore\")]\n    pub(crate) data: G::Edge,\n    /// Required key into the leading arc.\n    pub(crate) arc: ArcKey,\n}\n\nimpl<G> Edge<G>\nwhere\n    G: GraphData,\n{\n    pub fn new(arc: ArcKey, data: G::Edge) -> Self {\n        Edge { data, arc }\n    }\n}\n\nimpl<G> Entity for Edge<G>\nwhere\n    G: GraphData,\n{\n    type Key = EdgeKey;\n    type Storage = HashStorage<Self, IncrementalKeyer>;\n}\n\nimpl<G> Payload for Edge<G>\nwhere\n    G: GraphData,\n{\n    type Data = G::Edge;\n\n    fn get(&self) -> &Self::Data {\n        &self.data\n    }\n\n    fn get_mut(&mut self) -> &mut Self::Data {\n        &mut self.data\n    }\n}\n\n/// Edge key.\n#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]\npub struct EdgeKey(u64);\n\nimpl Key for EdgeKey {\n    type Inner = u64;\n\n    fn from_inner(key: Self::Inner) -> Self {\n        EdgeKey(key)\n    }\n\n    fn into_inner(self) -> Self::Inner {\n        self.0\n    }\n}\n\n/// View of an edge entity.\n///\n/// An edge connecting a vertex $A$ and a vertex $B$ is notated\n/// $\\overleftrightarrow{AB}$ or $\\overleftrightarrow{BA}$.\n///\n/// See the [`graph`] module documentation for more information about views.\n///\n/// [`graph`]: crate::graph\npub struct EdgeView<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Edge<<B::Target as Parametric>::Data>> + Parametric,\n{\n    inner: View<B, Edge<<B::Target as Parametric>::Data>>,\n}\n\nimpl<B, M> EdgeView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Edge<Data<B>>> + Parametric,\n{\n    pub fn to_ref(&self) -> EdgeView<&M> {\n        self.inner.to_ref().into()\n    }\n}\n\nimpl<'a, B, M, G> EdgeView<B>\nwhere\n    B: ReborrowInto<'a, Target = M>,\n    M: AsStorage<Edge<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn into_ref(self) -> EdgeView<&'a M> {\n        self.inner.into_ref().into()\n    }\n}\n\nimpl<B, M, G> EdgeView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Edge<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn get<'a>(&'a self) -> &'a G::Edge\n    where\n        G: 'a,\n    {\n        self.inner.get()\n    }\n}\n\nimpl<B, M, G> EdgeView<B>\nwhere\n    B: ReborrowMut<Target = M>,\n    M: AsStorageMut<Edge<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn get_mut<'a>(&'a mut self) -> &'a mut G::Edge\n    where\n        G: 'a,\n    {\n        self.inner.get_mut()\n    }\n}\n\n/// Reachable API.\nimpl<B, M, G> EdgeView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Edge<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub(in crate::graph) fn into_reachable_arc(self) -> Option<ArcView<B>> {\n        let key = self.arc;\n        self.rebind(key)\n    }\n}\n\nimpl<B, M, G> EdgeView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Edge<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn into_arc(self) -> ArcView<B> {\n        self.into_reachable_arc().expect_consistent()\n    }\n\n    pub fn arc(&self) -> ArcView<&M> {\n        self.to_ref().into_arc()\n    }\n\n    pub fn is_boundary_edge(&self) -> bool {\n        let arc = self.arc();\n        arc.is_boundary_arc() || arc.opposite_arc().is_boundary_arc()\n    }\n}\n\nimpl<B, M, G> EdgeView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>>\n        + AsStorage<Edge<G>>\n        + AsStorage<Vertex<G>>\n        + Consistent\n        + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn midpoint(&self) -> VertexPosition<G>\n    where\n        G: EdgeMidpoint,\n        G::Vertex: AsPosition,\n    {\n        G::midpoint(self.to_ref()).expect_consistent()\n    }\n}\n\nimpl<B> Borrow<EdgeKey> for EdgeView<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Edge<Data<B>>> + Parametric,\n{\n    fn borrow(&self) -> &EdgeKey {\n        self.inner.as_ref()\n    }\n}\n\nimpl<B, M, G> Clone for EdgeView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Edge<G>> + Parametric<Data = G>,\n    G: GraphData,\n    View<B, Edge<G>>: Clone,\n{\n    fn clone(&self) -> Self {\n        EdgeView {\n            inner: self.inner.clone(),\n        }\n    }\n}\n\nimpl<B, M, G> ClosedView for EdgeView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Edge<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Key = EdgeKey;\n    type Entity = Edge<G>;\n\n    /// Gets the key for the edge.\n    fn key(&self) -> Self::Key {\n        self.inner.key()\n    }\n}\n\nimpl<B, M, G> Copy for EdgeView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Edge<G>> + Parametric<Data = G>,\n    G: GraphData,\n    View<B, Edge<G>>: Copy,\n{\n}\n\nimpl<B, M, G> Deref for EdgeView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Edge<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Target = Edge<G>;\n\n    fn deref(&self) -> &Self::Target {\n        self.inner.deref()\n    }\n}\n\nimpl<B, M, G> DerefMut for EdgeView<B>\nwhere\n    B: ReborrowMut<Target = M>,\n    M: AsStorageMut<Edge<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        self.inner.deref_mut()\n    }\n}\n\nimpl<B, M, G> Eq for EdgeView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Edge<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n}\n\nimpl<B, M, G> From<View<B, Edge<G>>> for EdgeView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Edge<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn from(view: View<B, Edge<G>>) -> Self {\n        EdgeView { inner: view }\n    }\n}\n\nimpl<B, M, G> From<EdgeView<B>> for View<B, Edge<G>>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Edge<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn from(edge: EdgeView<B>) -> Self {\n        let EdgeView { inner, .. } = edge;\n        inner\n    }\n}\n\nimpl<B, M, G> Hash for EdgeView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Edge<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn hash<H>(&self, state: &mut H)\n    where\n        H: Hasher,\n    {\n        self.inner.hash(state);\n    }\n}\n\nimpl<B, M, G> PartialEq for EdgeView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Edge<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn eq(&self, other: &Self) -> bool {\n        self.inner == other.inner\n    }\n}\n\nimpl<B, M, G> ToArc<B> for EdgeView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Edge<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn into_arc(self) -> ArcView<B> {\n        EdgeView::into_arc(self)\n    }\n\n    fn arc(&self) -> ArcView<&M> {\n        EdgeView::arc(self)\n    }\n}\n\n/// Orphan view of an edge entity.\npub struct EdgeOrphan<'a, G>\nwhere\n    G: GraphData,\n{\n    inner: Orphan<'a, Edge<G>>,\n}\n\nimpl<G> EdgeOrphan<'_, G>\nwhere\n    G: GraphData,\n{\n    pub fn get(&self) -> &G::Edge {\n        self.inner.get()\n    }\n\n    pub fn get_mut(&mut self) -> &mut G::Edge {\n        self.inner.get_mut()\n    }\n}\n\nimpl<G> Borrow<EdgeKey> for EdgeOrphan<'_, G>\nwhere\n    G: GraphData,\n{\n    fn borrow(&self) -> &EdgeKey {\n        self.inner.as_ref()\n    }\n}\n\nimpl<G> ClosedView for EdgeOrphan<'_, G>\nwhere\n    G: GraphData,\n{\n    type Key = EdgeKey;\n    type Entity = Edge<G>;\n\n    fn key(&self) -> Self::Key {\n        self.inner.key()\n    }\n}\n\nimpl<G> Eq for EdgeOrphan<'_, G> where G: GraphData {}\n\nimpl<'a, M> From<EdgeView<&'a mut M>> for EdgeOrphan<'a, M::Data>\nwhere\n    M: AsStorageMut<Edge<M::Data>> + Parametric,\n{\n    fn from(edge: EdgeView<&'a mut M>) -> Self {\n        Orphan::from(edge.inner).into()\n    }\n}\n\nimpl<'a, G> From<Orphan<'a, Edge<G>>> for EdgeOrphan<'a, G>\nwhere\n    G: GraphData,\n{\n    fn from(inner: Orphan<'a, Edge<G>>) -> Self {\n        EdgeOrphan { inner }\n    }\n}\n\nimpl<'a, M> From<View<&'a mut M, Edge<M::Data>>> for EdgeOrphan<'a, M::Data>\nwhere\n    M: AsStorageMut<Edge<M::Data>> + Parametric,\n{\n    fn from(view: View<&'a mut M, Edge<M::Data>>) -> Self {\n        EdgeOrphan { inner: view.into() }\n    }\n}\n\nimpl<G> Hash for EdgeOrphan<'_, G>\nwhere\n    G: GraphData,\n{\n    fn hash<H>(&self, state: &mut H)\n    where\n        H: Hasher,\n    {\n        self.inner.hash(state);\n    }\n}\n\nimpl<G> PartialEq for EdgeOrphan<'_, G>\nwhere\n    G: GraphData,\n{\n    fn eq(&self, other: &Self) -> bool {\n        self.inner == other.inner\n    }\n}\n\npub struct VertexCirculator<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Vertex<Data<B>>> + Parametric,\n{\n    storage: B,\n    inner: <ArrayVec<VertexKey, 2> as IntoIterator>::IntoIter,\n}\n\nimpl<B, M, G> Circulator<B> for VertexCirculator<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Entity = Vertex<G>;\n\n    fn next(&mut self) -> Option<<Self::Entity as Entity>::Key> {\n        self.inner.next()\n    }\n}\n\nimpl<B, M, G> From<ArcView<B>> for VertexCirculator<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn from(arc: ArcView<B>) -> Self {\n        let (a, b) = arc.key().into();\n        let (storage, _) = arc.unbind();\n        VertexCirculator {\n            storage,\n            inner: ArrayVec::from([a, b]).into_iter(),\n        }\n    }\n}\n\nimpl<B, M, G> Clone for VertexCirculator<B>\nwhere\n    B: Clone + Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn clone(&self) -> Self {\n        VertexCirculator {\n            storage: self.storage.clone(),\n            inner: self.inner.clone(),\n        }\n    }\n}\n\nimpl<B, M, G> ExactSizeIterator for VertexCirculator<B>\nwhere\n    Self: Iterator,\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n}\n\nimpl<'a, M, G> Iterator for VertexCirculator<&'a M>\nwhere\n    M: AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Item = VertexView<&'a M>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        self.bind_next_view()\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        (0, Some(self.inner.len()))\n    }\n}\n\nimpl<'a, M> Iterator for VertexCirculator<&'a mut M>\nwhere\n    M: AsStorageMut<Vertex<M::Data>> + Parametric,\n{\n    type Item = VertexOrphan<'a, M::Data>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        unsafe { self.bind_next_orphan() }\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        (0, Some(self.inner.len()))\n    }\n}\n\nimpl<'a, M> OrphanCirculator<'a, M> for VertexCirculator<&'a mut M>\nwhere\n    M: AsStorageMut<Vertex<M::Data>> + Parametric,\n{\n    fn target(&mut self) -> &mut M {\n        self.storage\n    }\n}\n\nimpl<'a, M> ViewCirculator<'a, M> for VertexCirculator<&'a M>\nwhere\n    M: AsStorage<Vertex<M::Data>> + Parametric,\n{\n    fn target(&self) -> &'a M {\n        self.storage\n    }\n}\n\npub struct FaceCirculator<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Face<Data<B>>> + Parametric,\n{\n    storage: B,\n    inner: <ArrayVec<FaceKey, 2> as IntoIterator>::IntoIter,\n}\n\nimpl<B, M, G> Circulator<B> for FaceCirculator<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Entity = Face<G>;\n\n    fn next(&mut self) -> Option<<Self::Entity as Entity>::Key> {\n        self.inner.next()\n    }\n}\n\nimpl<B, M, G> Clone for FaceCirculator<B>\nwhere\n    B: Clone + Reborrow<Target = M>,\n    M: AsStorage<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn clone(&self) -> Self {\n        FaceCirculator {\n            storage: self.storage.clone(),\n            inner: self.inner.clone(),\n        }\n    }\n}\n\nimpl<B, M, G> ExactSizeIterator for FaceCirculator<B>\nwhere\n    Self: Iterator,\n    B: Reborrow<Target = M>,\n    M: AsStorage<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n}\n\nimpl<B, M, G> From<ArcView<B>> for FaceCirculator<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn from(arc: ArcView<B>) -> Self {\n        let inner = arc\n            .face\n            .into_iter()\n            .chain(\n                arc.to_ref()\n                    .into_reachable_opposite_arc()\n                    .and_then(|opposite| opposite.face),\n            )\n            .collect::<ArrayVec<_, 2>>()\n            .into_iter();\n        let (storage, _) = arc.unbind();\n        FaceCirculator { storage, inner }\n    }\n}\n\nimpl<'a, M, G> Iterator for FaceCirculator<&'a M>\nwhere\n    M: AsStorage<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Item = FaceView<&'a M>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        self.bind_next_view()\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        (0, Some(self.inner.len()))\n    }\n}\n\nimpl<'a, M> Iterator for FaceCirculator<&'a mut M>\nwhere\n    M: AsStorageMut<Face<M::Data>> + Parametric,\n{\n    type Item = FaceOrphan<'a, M::Data>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        unsafe { self.bind_next_orphan() }\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        (0, Some(self.inner.len()))\n    }\n}\n\nimpl<'a, M> OrphanCirculator<'a, M> for FaceCirculator<&'a mut M>\nwhere\n    M: AsStorageMut<Face<M::Data>> + Parametric,\n{\n    fn target(&mut self) -> &mut M {\n        self.storage\n    }\n}\n\nimpl<'a, M> ViewCirculator<'a, M> for FaceCirculator<&'a M>\nwhere\n    M: AsStorage<Face<M::Data>> + Parametric,\n{\n    fn target(&self) -> &'a M {\n        self.storage\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use decorum::R64;\n    use nalgebra::{Point2, Point3};\n\n    use crate::geometry::FromGeometry;\n    use crate::graph::{ArcKey, GraphData, MeshGraph};\n    use crate::index::HashIndexer;\n    use crate::prelude::*;\n    use crate::primitive::cube::Cube;\n    use crate::primitive::generate::Position;\n    use crate::primitive::Tetragon;\n\n    type E2 = Point2<R64>;\n    type E3 = Point3<R64>;\n\n    fn find_arc<G, T>(graph: &MeshGraph<G>, data: (T, T)) -> Option<ArcKey>\n    where\n        G: GraphData,\n        G::Vertex: FromGeometry<T> + PartialEq,\n    {\n        let (source, destination) = data;\n        let source = source.into_geometry();\n        let destination = destination.into_geometry();\n        graph\n            .vertices()\n            .filter(|vertex| vertex.data == source)\n            .flat_map(|source| {\n                source\n                    .adjacent_vertices()\n                    .find(|vertex| vertex.data == destination)\n                    .map(|destination| (source.key(), destination.key()))\n            })\n            .map(|(a, b)| (a, b).into())\n            .next()\n    }\n\n    #[test]\n    fn extrude_arc() {\n        let mut graph = MeshGraph::<E2>::from_raw_buffers_with_arity(\n            vec![0u32, 1, 2, 3],\n            vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)],\n            4,\n        )\n        .unwrap();\n        let source = find_arc(&graph, ((1.0, 1.0), (1.0, 0.0))).unwrap();\n        graph\n            .arc_mut(source)\n            .unwrap()\n            .extrude_with_offset(R64::assert(1.0))\n            .unwrap();\n\n        assert_eq!(14, graph.arc_count());\n        assert_eq!(2, graph.face_count());\n    }\n\n    #[test]\n    fn bridge_arcs() {\n        // Construct a mesh with two disjoint quadrilaterals.\n        let mut graph = MeshGraph::<E3>::from_raw_buffers_with_arity(\n            vec![0u32, 1, 2, 3, 4, 5, 6, 7],\n            vec![\n                (-2.0, 0.0, 0.0),\n                (-1.0, 0.0, 0.0), // 1\n                (-1.0, 1.0, 0.0), // 2\n                (-2.0, 1.0, 0.0),\n                (1.0, 0.0, 0.0), // 4\n                (2.0, 0.0, 0.0),\n                (2.0, 1.0, 0.0),\n                (1.0, 1.0, 0.0), // 7\n            ],\n            4,\n        )\n        .unwrap();\n        let source = find_arc(&graph, ((-1.0, 1.0, 0.0), (-1.0, 0.0, 0.0))).unwrap();\n        let destination = find_arc(&graph, ((1.0, 0.0, 0.0), (1.0, 1.0, 0.0))).unwrap();\n        graph.arc_mut(source).unwrap().bridge(destination).unwrap();\n\n        assert_eq!(20, graph.arc_count());\n        assert_eq!(3, graph.face_count());\n    }\n\n    #[test]\n    fn split_edge() {\n        let (indices, vertices) = Cube::new()\n            .polygons::<Position<E3>>() // 6 quadrilaterals, 24 vertices.\n            .index_vertices::<Tetragon<usize>, _>(HashIndexer::default());\n        let mut graph = MeshGraph::<E3>::from_raw_buffers(indices, vertices).unwrap();\n        let key = graph.arcs().next().unwrap().key();\n        let vertex = graph.arc_mut(key).unwrap().split_at_midpoint().into_ref();\n\n        assert_eq!(5, vertex.into_outgoing_arc().into_face().unwrap().arity());\n        assert_eq!(\n            5,\n            vertex\n                .into_outgoing_arc()\n                .into_opposite_arc()\n                .into_face()\n                .unwrap()\n                .arity()\n        );\n    }\n\n    #[test]\n    fn remove_edge() {\n        // Construct a graph with two connected quadrilaterals.\n        let mut graph = MeshGraph::<E2>::from_raw_buffers_with_arity(\n            vec![0u32, 1, 2, 3, 0, 3, 4, 5],\n            vec![\n                (0.0, 0.0),  // 0\n                (1.0, 0.0),  // 1\n                (1.0, 1.0),  // 2\n                (0.0, 1.0),  // 3\n                (-1.0, 1.0), // 4\n                (-1.0, 0.0), // 5\n            ],\n            4,\n        )\n        .unwrap();\n\n        // The graph should begin with 2 faces.\n        assert_eq!(2, graph.face_count());\n\n        // Remove the edge joining the quadrilaterals from the graph.\n        let ab = find_arc(&graph, ((0.0, 0.0), (0.0, 1.0))).unwrap();\n        {\n            let vertex = graph.arc_mut(ab).unwrap().remove().unwrap().into_ref();\n\n            // The ring should be formed from 6 edges.\n            assert_eq!(6, vertex.into_outgoing_arc().into_ring().arity());\n        }\n\n        // After the removal, the graph should have no faces.\n        assert_eq!(0, graph.face_count());\n    }\n}\n"
  },
  {
    "path": "plexus/src/graph/face.rs",
    "content": "use derivative::Derivative;\nuse smallvec::SmallVec;\nuse std::borrow::Borrow;\nuse std::cmp;\nuse std::collections::HashSet;\nuse std::hash::{Hash, Hasher};\nuse std::ops::{Deref, DerefMut};\nuse theon::query::{Intersection, Line, Plane};\nuse theon::space::{EuclideanSpace, FiniteDimensional, Scalar, Vector};\nuse theon::{AsPosition, AsPositionMut};\nuse typenum::U3;\n\nuse crate::entity::borrow::{Reborrow, ReborrowInto, ReborrowMut};\nuse crate::entity::storage::prelude::*;\nuse crate::entity::storage::{\n    AsStorage, AsStorageMut, AsStorageOf, HashStorage, IncrementalKeyer, Key,\n};\nuse crate::entity::traverse::{Adjacency, Breadth, Depth, Trace, TraceFirst, Traversal};\nuse crate::entity::view::{Bind, ClosedView, Orphan, Rebind, Unbind, View};\nuse crate::entity::{Entity, Payload};\nuse crate::graph::data::{Data, GraphData, Parametric};\nuse crate::graph::edge::{Arc, ArcKey, ArcOrphan, ArcView, Edge};\nuse crate::graph::geometry::{FaceCentroid, FaceNormal, FacePlane, VertexPosition};\nuse crate::graph::mutation::face::{\n    self, FaceBridgeCache, FaceExtrudeCache, FaceInsertCache, FacePokeCache, FaceRemoveCache,\n    FaceSplitCache,\n};\nuse crate::graph::mutation::{self, Consistent, Immediate, Mutable};\nuse crate::graph::path::Path;\nuse crate::graph::vertex::{Vertex, VertexKey, VertexOrphan, VertexView};\nuse crate::graph::{\n    Circulator, GraphError, MeshGraph, OptionExt as _, OrphanCirculator, ResultExt as _, Selector,\n    ViewCirculator,\n};\nuse crate::transact::{BypassOrCommit, Mutate};\nuse crate::{DynamicArity, IteratorExt as _, StaticArity};\n\ntype Mutation<M> = mutation::Mutation<Immediate<M>>;\n\npub trait ToRing<B>: DynamicArity<Dynamic = usize> + Sized\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Arc<Data<B>>> + Consistent + Parametric,\n{\n    fn into_ring(self) -> Ring<B>;\n\n    fn ring(&self) -> Ring<&B::Target>;\n}\n\n/// Face entity.\n#[derive(Derivative)]\n#[derivative(Debug, Hash)]\npub struct Face<G>\nwhere\n    G: GraphData,\n{\n    /// User data.\n    #[derivative(Debug = \"ignore\", Hash = \"ignore\")]\n    pub(crate) data: G::Face,\n    /// Required key into the leading arc.\n    pub(crate) arc: ArcKey,\n}\n\nimpl<G> Face<G>\nwhere\n    G: GraphData,\n{\n    pub fn new(arc: ArcKey, data: G::Face) -> Self {\n        Face { data, arc }\n    }\n}\n\nimpl<G> Entity for Face<G>\nwhere\n    G: GraphData,\n{\n    type Key = FaceKey;\n    type Storage = HashStorage<Self, IncrementalKeyer>;\n}\n\nimpl<G> Payload for Face<G>\nwhere\n    G: GraphData,\n{\n    type Data = G::Face;\n\n    fn get(&self) -> &Self::Data {\n        &self.data\n    }\n\n    fn get_mut(&mut self) -> &mut Self::Data {\n        &mut self.data\n    }\n}\n\n/// Face key.\n#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]\npub struct FaceKey(u64);\n\nimpl Key for FaceKey {\n    type Inner = u64;\n\n    fn from_inner(key: Self::Inner) -> Self {\n        FaceKey(key)\n    }\n\n    fn into_inner(self) -> Self::Inner {\n        self.0\n    }\n}\n\n/// View of a face entity.\n///\n/// Faces are notated by the path of their associated ring. A triangular face\n/// with a perimeter formed by vertices $A$, $B$, and $C$ is notated\n/// $\\overrightarrow{\\\\{A,B,C\\\\}}$. While the precise ordering of vertices is\n/// determined by a face's leading arc, the same face may be notated using\n/// rotations of this set, such as $\\overrightarrow{\\\\{B,C,A\\\\}}$.\n///\n/// See the [`graph`] module documentation for more information about views.\n///\n/// [`MeshGraph`]: crate::graph::MeshGraph\n/// [`graph`]: crate::graph\npub struct FaceView<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Face<Data<B>>> + Parametric,\n{\n    inner: View<B, Face<Data<B>>>,\n}\n\nimpl<B, M> FaceView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Face<Data<B>>> + Parametric,\n{\n    pub fn to_ref(&self) -> FaceView<&M> {\n        self.inner.to_ref().into()\n    }\n}\n\nimpl<B, M> FaceView<B>\nwhere\n    B: ReborrowMut<Target = M>,\n    M: AsStorage<Face<Data<B>>> + Parametric,\n{\n    // LINT: This convention is specifically used for interior reborrows and is consistent with\n    //       `to_ref`.\n    #[expect(clippy::wrong_self_convention)]\n    fn to_mut_unchecked(&mut self) -> FaceView<&mut M> {\n        self.inner.to_mut_unchecked().into()\n    }\n}\n\nimpl<'a, B, M, G> FaceView<B>\nwhere\n    B: ReborrowInto<'a, Target = M>,\n    M: AsStorage<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    // TODO: Relocate this documentation of `into_ref`.\n    /// # Examples\n    ///\n    /// ```rust\n    /// # extern crate decorum;\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use decorum::R64;\n    /// use nalgebra::Point3;\n    /// use plexus::graph::MeshGraph;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::cube::Cube;\n    /// use plexus::primitive::generate::Position;\n    ///\n    /// type E3 = Point3<R64>;\n    ///\n    /// let mut graph: MeshGraph<E3> = Cube::new().polygons::<Position<E3>>().collect();\n    /// let key = graph.faces().next().unwrap().key();\n    /// let face = graph\n    ///     .face_mut(key)\n    ///     .unwrap()\n    ///     .extrude_with_offset(R64::assert(1.0))\n    ///     .unwrap()\n    ///     .into_ref();\n    ///\n    /// // This would not be possible without conversion into an immutable view.\n    /// let _ = face.into_arc();\n    /// let _ = face.into_arc().into_next_arc();\n    /// ```\n    pub fn into_ref(self) -> FaceView<&'a M> {\n        self.inner.into_ref().into()\n    }\n}\n\nimpl<B, M, G> FaceView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn get<'a>(&'a self) -> &'a G::Face\n    where\n        G: 'a,\n    {\n        self.inner.get()\n    }\n}\n\nimpl<B, M, G> FaceView<B>\nwhere\n    B: ReborrowMut<Target = M>,\n    M: AsStorageMut<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn get_mut<'a>(&'a mut self) -> &'a mut G::Face\n    where\n        G: 'a,\n    {\n        self.inner.get_mut()\n    }\n}\n\n/// Reachable API.\nimpl<B, M, G> FaceView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub(in crate::graph) fn into_reachable_arc(self) -> Option<ArcView<B>> {\n        let key = self.arc;\n        self.rebind(key)\n    }\n}\n\nimpl<B, M, G> FaceView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Face<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    /// Converts the face into its ring.\n    pub fn into_ring(self) -> Ring<B> {\n        self.into_arc().into_ring()\n    }\n\n    /// Converts the face into its leading arc.\n    pub fn into_arc(self) -> ArcView<B> {\n        self.into_reachable_arc().expect_consistent()\n    }\n\n    /// Gets the ring of the face.\n    pub fn ring(&self) -> Ring<&M> {\n        self.to_ref().into_ring()\n    }\n\n    /// Gets the leading arc of the face.\n    pub fn arc(&self) -> ArcView<&M> {\n        self.to_ref().into_arc()\n    }\n}\n\nimpl<B, M, G> FaceView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>>\n        + AsStorage<Face<G>>\n        + AsStorage<Vertex<G>>\n        + Consistent\n        + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn centroid(&self) -> VertexPosition<G>\n    where\n        G: FaceCentroid,\n        G::Vertex: AsPosition,\n    {\n        G::centroid(self.to_ref()).expect_consistent()\n    }\n\n    pub fn normal(&self) -> Result<Vector<VertexPosition<G>>, GraphError>\n    where\n        G: FaceNormal,\n        G::Vertex: AsPosition,\n    {\n        G::normal(self.to_ref())\n    }\n\n    pub fn plane(&self) -> Result<Plane<VertexPosition<G>>, GraphError>\n    where\n        G: FacePlane,\n        G::Vertex: AsPosition,\n        VertexPosition<G>: FiniteDimensional<N = U3>,\n    {\n        G::plane(self.to_ref())\n    }\n}\n\nimpl<B, M, G> FaceView<B>\nwhere\n    B: ReborrowMut<Target = M>,\n    M: AsStorage<Arc<G>>\n        + AsStorage<Face<G>>\n        + AsStorageMut<Vertex<G>>\n        + Consistent\n        + Parametric<Data = G>,\n    G: GraphData,\n{\n    /// Flattens the face by translating the positions of all vertices into a\n    /// best-fit plane.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if a best-fit plane could not be computed or positions\n    /// could not be translated into the plane.\n    pub fn flatten(&mut self) -> Result<(), GraphError>\n    where\n        G: FacePlane,\n        G::Vertex: AsPositionMut,\n        VertexPosition<G>: EuclideanSpace + FiniteDimensional<N = U3>,\n    {\n        if self.arity() == 3 {\n            return Ok(());\n        }\n        let plane = self.plane()?;\n        for mut vertex in self.adjacent_vertex_orphans() {\n            let position = *vertex.position();\n            let line = Line::<VertexPosition<G>> {\n                origin: position,\n                direction: plane.normal,\n            };\n            let distance = line\n                .intersection(&plane)\n                .expect(\"no line-plane intersection along normal\")\n                .into_time_of_impact()\n                .expect(\"normal is parallel to plane\");\n            let translation = *line.direction.get() * distance;\n            *vertex.get_mut().as_position_mut() = position + translation;\n        }\n        Ok(())\n    }\n}\n\nimpl<'a, B, M, G> FaceView<B>\nwhere\n    B: ReborrowInto<'a, Target = M>,\n    M: 'a + AsStorage<Arc<G>> + AsStorage<Face<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn into_adjacent_arcs(self) -> impl Clone + Iterator<Item = ArcView<&'a M>> {\n        self.into_ref().into_ring().into_arcs()\n    }\n\n    pub fn into_adjacent_faces(self) -> impl Clone + Iterator<Item = FaceView<&'a M>> {\n        FaceCirculator::from(ArcCirculator::from(self.into_ref().into_ring()))\n    }\n}\n\nimpl<B, G> FaceView<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Arc<G>> + AsStorage<Face<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    /// Gets an iterator of views over the arcs in the face's ring.\n    pub fn adjacent_arcs(&self) -> impl Clone + Iterator<Item = ArcView<&B::Target>> {\n        self.to_ref().into_adjacent_arcs()\n    }\n\n    /// Gets an iterator of views over adjacent faces.\n    pub fn adjacent_faces(&self) -> impl Clone + Iterator<Item = FaceView<&B::Target>> {\n        self.to_ref().into_adjacent_faces()\n    }\n}\n\nimpl<'a, B, M, G> FaceView<B>\nwhere\n    B: ReborrowInto<'a, Target = M>,\n    M: 'a\n        + AsStorage<Arc<G>>\n        + AsStorage<Face<G>>\n        + AsStorage<Vertex<G>>\n        + Consistent\n        + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn into_adjacent_vertices(self) -> impl Clone + Iterator<Item = VertexView<&'a M>> {\n        self.into_ref().into_ring().into_vertices()\n    }\n}\n\nimpl<B, G> FaceView<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Arc<G>>\n        + AsStorage<Face<G>>\n        + AsStorage<Vertex<G>>\n        + Consistent\n        + Parametric<Data = G>,\n    G: GraphData,\n{\n    /// Gets an iterator of views over the vertices that form the face.\n    pub fn adjacent_vertices(&self) -> impl Clone + Iterator<Item = VertexView<&B::Target>> {\n        self.to_ref().into_adjacent_vertices()\n    }\n}\n\nimpl<'a, M> FaceView<&'a mut M>\nwhere\n    M: AsStorageMut<Arc<M::Data>> + AsStorage<Face<M::Data>> + Consistent + Parametric,\n{\n    pub fn into_adjacent_arc_orphans(self) -> impl Iterator<Item = ArcOrphan<'a, M::Data>> {\n        self.into_ring().into_arc_orphans()\n    }\n}\n\nimpl<B> FaceView<B>\nwhere\n    B: ReborrowMut,\n    B::Target: AsStorageMut<Arc<Data<B>>> + AsStorage<Face<Data<B>>> + Consistent + Parametric,\n{\n    /// Gets an iterator of orphan views over the arcs in the face's ring.\n    pub fn adjacent_arc_orphans(&mut self) -> impl Iterator<Item = ArcOrphan<Data<B>>> {\n        self.to_mut_unchecked().into_adjacent_arc_orphans()\n    }\n}\n\nimpl<'a, M> FaceView<&'a mut M>\nwhere\n    M: AsStorage<Arc<M::Data>> + AsStorageMut<Face<M::Data>> + Consistent + Parametric,\n{\n    pub fn into_adjacent_face_orphans(self) -> impl Iterator<Item = FaceOrphan<'a, M::Data>> {\n        FaceCirculator::from(ArcCirculator::from(self.into_ring()))\n    }\n}\n\nimpl<B> FaceView<B>\nwhere\n    B: ReborrowMut,\n    B::Target: AsStorage<Arc<Data<B>>> + AsStorageMut<Face<Data<B>>> + Consistent + Parametric,\n{\n    /// Gets an iterator of orphan views over adjacent faces.\n    pub fn adjacent_face_orphans(&mut self) -> impl Iterator<Item = FaceOrphan<Data<B>>> {\n        self.to_mut_unchecked().into_adjacent_face_orphans()\n    }\n}\n\nimpl<'a, M> FaceView<&'a mut M>\nwhere\n    M: AsStorage<Arc<Data<M>>>\n        + AsStorage<Face<Data<M>>>\n        + AsStorageMut<Vertex<Data<M>>>\n        + Consistent\n        + Parametric,\n{\n    pub fn into_adjacent_vertex_orphans(self) -> impl Iterator<Item = VertexOrphan<'a, Data<M>>> {\n        VertexCirculator::from(ArcCirculator::from(self.into_ring()))\n    }\n}\n\nimpl<B> FaceView<B>\nwhere\n    B: ReborrowMut,\n    B::Target: AsStorage<Arc<Data<B>>>\n        + AsStorage<Face<Data<B>>>\n        + AsStorageMut<Vertex<Data<B>>>\n        + Consistent\n        + Parametric,\n{\n    /// Gets an iterator of orphan views over the vertices that form the face.\n    pub fn adjacent_vertex_orphans(&mut self) -> impl Iterator<Item = VertexOrphan<Data<B>>> {\n        self.to_mut_unchecked().into_adjacent_vertex_orphans()\n    }\n}\n\nimpl<B, G> FaceView<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Arc<G>> + AsStorage<Face<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    /// Gets an iterator that traverses adjacent faces by breadth.\n    ///\n    /// The traversal moves from the face to its adjacent faces and so on. If\n    /// there are disjoint sub-graphs in the graph, then a traversal will not\n    /// reach every face in the graph.\n    pub fn traverse_by_breadth(&self) -> impl Clone + Iterator<Item = FaceView<&B::Target>> {\n        Traversal::<_, _, Breadth>::from(self.to_ref())\n    }\n\n    /// Gets an iterator that traverses adjacent faces by depth.\n    ///\n    /// The traversal moves from the face to its adjacent faces and so on. If\n    /// there are disjoint sub-graphs in the graph, then a traversal will not\n    /// reach every face in the graph.\n    pub fn traverse_by_depth(&self) -> impl Clone + Iterator<Item = FaceView<&B::Target>> {\n        Traversal::<_, _, Depth>::from(self.to_ref())\n    }\n}\n\nimpl<'a, M, G> FaceView<&'a mut M>\nwhere\n    M: AsStorage<Arc<G>>\n        + AsStorage<Edge<G>>\n        + AsStorage<Face<G>>\n        + AsStorage<Vertex<G>>\n        + Default\n        + Mutable<Data = G>,\n    G: GraphData,\n{\n    /// Splits the face by bisecting it with a composite edge inserted between\n    /// two non-adjacent vertices within the face's perimeter.\n    ///\n    /// The vertices can be chosen by key or index, where index selects the\n    /// $n^\\text{th}$ vertex within the face's ring.\n    ///\n    /// Returns the arc inserted from the source vertex to the destination\n    /// vertex. If a face $\\overrightarrow{\\\\{A,B, C,D\\\\}}$ is split from $A$ to\n    /// $C$, then it will be decomposed into faces in the rings\n    /// $\\overrightarrow{\\\\{A,B,C\\\\}}$ and $\\overrightarrow{\\\\{C,D,A\\\\}}$ and\n    /// the arc $\\overrightarrow{AC}$ will be returned.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if either of the given vertices cannot be found, are\n    /// not within the face's perimeter, or the distance between the vertices\n    /// along the ring is less than two.\n    ///\n    /// # Examples\n    ///\n    /// Splitting a quadrilateral face:\n    ///\n    /// ```rust\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use nalgebra::Point2;\n    /// use plexus::graph::MeshGraph;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::Tetragon;\n    ///\n    /// let mut graph = MeshGraph::<Point2<f64>>::from_raw_buffers(\n    ///     vec![Tetragon::new(0usize, 1, 2, 3)],\n    ///     vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)],\n    /// )\n    /// .unwrap();\n    /// let key = graph.faces().next().unwrap().key();\n    /// let arc = graph\n    ///     .face_mut(key)\n    ///     .unwrap()\n    ///     .split(ByIndex(0), ByIndex(2))\n    ///     .unwrap()\n    ///     .into_ref();\n    /// ```\n    pub fn split(\n        self,\n        source: impl Into<Selector<VertexKey>>,\n        destination: impl Into<Selector<VertexKey>>,\n    ) -> Result<ArcView<&'a mut M>, GraphError> {\n        let key_at_index = |index| {\n            self.adjacent_vertices()\n                .nth(index)\n                .ok_or(GraphError::TopologyNotFound)\n                .map(|vertex| vertex.key())\n        };\n        let source = source.into().key_or_else(key_at_index)?;\n        let destination = destination.into().key_or_else(key_at_index)?;\n        let cache = FaceSplitCache::from_face(self.to_ref(), source, destination)?;\n        let (storage, _) = self.unbind();\n        Ok(Mutation::take(storage)\n            .bypass_or_commit_with(|mutation| face::split(mutation, cache))\n            .map(|(storage, arc)| Bind::bind(storage, arc).expect_consistent())\n            .map_err(|(_, error)| error)\n            .expect_consistent())\n    }\n\n    /// Merges the face into an adjacent face over a shared edge.\n    ///\n    /// The adjacent face can be chosen by key or index, where index selects\n    /// the $n^\\text{th}$ adjacent face.\n    ///\n    /// Returns the merged face.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the destination face cannot be found or is not\n    /// adjacent to the initiating face.\n    ///\n    /// # Examples\n    ///\n    /// Merging two adjacent quadrilateral faces:\n    ///\n    /// ```rust\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use nalgebra::Point2;\n    /// use plexus::graph::MeshGraph;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::Tetragon;\n    ///\n    /// let mut graph = MeshGraph::<Point2<f64>>::from_raw_buffers(\n    ///     vec![Tetragon::new(0usize, 1, 2, 3), Tetragon::new(0, 3, 4, 5)],\n    ///     vec![\n    ///         (0.0, 0.0),  // 0\n    ///         (1.0, 0.0),  // 1\n    ///         (1.0, 1.0),  // 2\n    ///         (0.0, 1.0),  // 3\n    ///         (-1.0, 1.0), // 4\n    ///         (-1.0, 0.0), // 5\n    ///     ],\n    /// )\n    /// .unwrap();\n    ///\n    /// let key = graph.faces().next().unwrap().key();\n    /// let face = graph\n    ///     .face_mut(key)\n    ///     .unwrap()\n    ///     .merge(ByIndex(0))\n    ///     .unwrap()\n    ///     .into_ref();\n    /// ```\n    pub fn merge(self, destination: impl Into<Selector<FaceKey>>) -> Result<Self, GraphError> {\n        let destination = destination.into().key_or_else(|index| {\n            self.adjacent_faces()\n                .nth(index)\n                .ok_or(GraphError::TopologyNotFound)\n                .map(|face| face.key())\n        })?;\n        let ab = self\n            .adjacent_arcs()\n            .find(|arc| match arc.opposite_arc().face() {\n                Some(face) => face.key() == destination,\n                _ => false,\n            })\n            .map(|arc| arc.key())\n            .ok_or(GraphError::TopologyNotFound)?;\n        // TODO: `Clone` should not be needed here. Consolidate this using the\n        //       mutation API and move the necessary face data instead of\n        //       cloning it.\n        let data = self.get().clone();\n        let arc: ArcView<_> = self.rebind(ab).expect_consistent();\n        Ok(arc\n            .remove()\n            // Removing an edge between faces must yield a vertex.\n            .expect_consistent()\n            .into_outgoing_arc()\n            .into_ring()\n            .get_or_insert_face_with(|| data))\n    }\n\n    /// Connects faces with equal arity with faces inserted along their\n    /// perimeters.\n    ///\n    /// The inserted faces are always quadrilateral. Both the initiating face\n    /// and destination face are removed.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the destination face cannot be found or the arity of\n    /// the face and its destination are not the same.\n    pub fn bridge(self, destination: FaceKey) -> Result<(), GraphError> {\n        let cache = FaceBridgeCache::from_face(self.to_ref(), destination)?;\n        let (storage, _) = self.unbind();\n        Mutation::take(storage)\n            .bypass_or_commit_with(|mutation| face::bridge(mutation, cache))\n            .map_err(|(_, error)| error)\n            .expect_consistent();\n        Ok(())\n    }\n\n    /// Decomposes the face into triangles. Does nothing if the face is\n    /// triangular.\n    ///\n    /// Returns the terminating face of the decomposition.\n    // LINT: This function has significant side effects and can be meaningfully called for those\n    //       side effects alone.\n    #[expect(clippy::return_self_not_must_use)]\n    pub fn triangulate(self) -> Self {\n        // TODO: This naive approach exhibits bad behaviors when faces are\n        //       concave, linear, collapsed, or are otherwise degenerate.\n        //       Additionally, splitting may fail under certain conditions!\n        //       Triangulation that ignores geometry is likely much less useful\n        //       than a triangulation algorithm that considers position data.\n        // TODO: This implementation differs from `MeshGraph::triangulate`,\n        //       because it is not possible to retry `split` in this context.\n        let mut face = self;\n        while face.arity() > 3 {\n            face = face\n                .split(0, 2)\n                .expect_consistent() // TODO: This may panic!\n                .into_face()\n                .expect_consistent();\n        }\n        face\n    }\n\n    /// Subdivides the face about a vertex. A triangle fan is formed from each\n    /// arc in the face's perimeter and the vertex.\n    ///\n    /// Poking inserts a new vertex with data provided by the given function.\n    ///\n    /// Returns the inserted vertex.\n    ///\n    /// # Examples\n    ///\n    /// Forming a pyramid from a triangular face:\n    ///\n    /// ```rust\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use nalgebra::Point3;\n    /// use plexus::geometry::{AsPosition, AsPositionMut};\n    /// use plexus::graph::MeshGraph;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::Trigon;\n    ///\n    /// let mut graph = MeshGraph::<Point3<f64>>::from_raw_buffers(\n    ///     vec![Trigon::new(0usize, 1, 2)],\n    ///     vec![(-1.0, 0.0, 0.0), (1.0, 0.0, 0.0), (0.0, 2.0, 0.0)],\n    /// )\n    /// .unwrap();\n    /// let key = graph.faces().next().unwrap().key();\n    /// let mut face = graph.face_mut(key).unwrap();\n    ///\n    /// // See also `poke_with_offset`, which provides this functionality.\n    /// let position = face.centroid() + face.normal().unwrap();\n    /// face.poke_with(move || position);\n    /// ```\n    pub fn poke_with<F>(self, f: F) -> VertexView<&'a mut M>\n    where\n        F: FnOnce() -> G::Vertex,\n    {\n        // This should never fail here.\n        let cache = FacePokeCache::from_face(self.to_ref()).expect_consistent();\n        let (storage, _) = self.unbind();\n        Mutation::take(storage)\n            .bypass_or_commit_with(|mutation| face::poke_with(mutation, cache, f))\n            .map(|(storage, vertex)| Bind::bind(storage, vertex).expect_consistent())\n            .map_err(|(_, error)| error)\n            .expect_consistent()\n    }\n\n    /// Subdivides the face about its centroid. A triangle fan is formed from\n    /// each arc in the face's perimeter and a vertex inserted at the centroid.\n    ///\n    /// Returns the inserted vertex.\n    pub fn poke_at_centroid(self) -> VertexView<&'a mut M>\n    where\n        G: FaceCentroid,\n        G::Vertex: AsPositionMut,\n    {\n        let mut data = self.arc().source_vertex().get().clone();\n        let centroid = self.centroid();\n        self.poke_with(move || {\n            *data.as_position_mut() = centroid;\n            data\n        })\n    }\n\n    /// Subdivides the face about its centroid. A triangle fan is formed from\n    /// each arc in the face's perimeter and a vertex inserted at the centroid.\n    /// The inserted vertex is then translated along the initiating face's\n    /// normal by the given offset.\n    ///\n    /// Returns the inserted vertex.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the geometry could not be computed.\n    ///\n    /// # Examples\n    ///\n    /// Constructing a \"spikey\" sphere:\n    ///\n    /// ```rust\n    /// # extern crate decorum;\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use decorum::R64;\n    /// use nalgebra::Point3;\n    /// use plexus::graph::MeshGraph;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::generate::Position;\n    /// use plexus::primitive::sphere::UvSphere;\n    ///\n    /// type E3 = Point3<R64>;\n    ///\n    /// let mut graph: MeshGraph<E3> = UvSphere::new(16, 8).polygons::<Position<E3>>().collect();\n    /// let keys = graph.faces().map(|face| face.key()).collect::<Vec<_>>();\n    /// for key in keys {\n    ///     graph\n    ///         .face_mut(key)\n    ///         .unwrap()\n    ///         .poke_with_offset(R64::assert(0.5))\n    ///         .unwrap();\n    /// }\n    /// ```\n    pub fn poke_with_offset<T>(self, offset: T) -> Result<VertexView<&'a mut M>, GraphError>\n    where\n        T: Into<Scalar<VertexPosition<G>>>,\n        G: FaceCentroid + FaceNormal,\n        G::Vertex: AsPositionMut,\n        VertexPosition<G>: EuclideanSpace,\n    {\n        let mut data = self.arc().source_vertex().get().clone();\n        let position = self.centroid() + (self.normal()? * offset.into());\n        Ok(self.poke_with(move || {\n            *data.as_position_mut() = position;\n            data\n        }))\n    }\n\n    /// Extrudes the face along its normal.\n    ///\n    /// Returns the extruded face.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the geometry could not be computed.\n    pub fn extrude_with_offset<T>(self, offset: T) -> Result<Self, GraphError>\n    where\n        T: Into<Scalar<VertexPosition<G>>>,\n        G: FaceNormal,\n        G::Vertex: AsPositionMut,\n        VertexPosition<G>: EuclideanSpace,\n    {\n        let translation = self.normal()? * offset.into();\n        Ok(self.extrude_with_translation(translation))\n    }\n\n    /// Extrudes the face along a translation.\n    ///\n    /// Returns the extruded face.\n    // LINT: This function has significant side effects and can be meaningfully called for those\n    //       side effects alone.\n    #[expect(clippy::return_self_not_must_use)]\n    pub fn extrude_with_translation(self, translation: Vector<VertexPosition<G>>) -> Self\n    where\n        G::Vertex: AsPositionMut,\n        VertexPosition<G>: EuclideanSpace,\n    {\n        self.extrude_with(|data| {\n            data.clone()\n                .map_position(|position| *position + translation)\n        })\n    }\n\n    /// Extrudes a face using the given vertex data.\n    ///\n    /// Returns the extruded face.\n    // LINT: This function has significant side effects and can be meaningfully called for those\n    //       side effects alone.\n    #[expect(clippy::return_self_not_must_use)]\n    pub fn extrude_with<F>(self, f: F) -> Self\n    where\n        F: Fn(&G::Vertex) -> G::Vertex,\n    {\n        // This should never fail here.\n        let cache = FaceExtrudeCache::from_face(self.to_ref()).expect_consistent();\n        let (storage, _) = self.unbind();\n        Mutation::take(storage)\n            .bypass_or_commit_with(|mutation| face::extrude_with(mutation, cache, f))\n            .map(|(storage, face)| Bind::bind(storage, face).expect_consistent())\n            .map_err(|(_, error)| error)\n            .expect_consistent()\n    }\n\n    /// Removes the face.\n    ///\n    /// Returns the remaining ring of the face if it is not entirely disjoint, otherwise `None`.\n    pub fn remove(self) -> Option<Ring<&'a mut M>> {\n        // This should never fail here.\n        let cache = FaceRemoveCache::from_face(self.to_ref()).expect_consistent();\n        let (storage, _) = self.unbind();\n        Mutation::take(storage)\n            .bypass_or_commit_with(|mutation| face::remove(mutation, cache))\n            .map(|(storage, face)| ArcView::bind(storage, face.arc))\n            .map_err(|(_, error)| error)\n            .expect_consistent()\n            .map(|arc| arc.into_ring())\n    }\n}\n\nimpl<B, M, G> Adjacency for FaceView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Face<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Output = SmallVec<[Self::Key; 8]>;\n\n    fn adjacency(&self) -> Self::Output {\n        self.adjacent_faces().keys().collect()\n    }\n}\n\nimpl<B> Borrow<FaceKey> for FaceView<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Face<Data<B>>> + Parametric,\n{\n    fn borrow(&self) -> &FaceKey {\n        self.inner.as_ref()\n    }\n}\n\nimpl<B, M, G> Clone for FaceView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n    View<B, Face<G>>: Clone,\n{\n    fn clone(&self) -> Self {\n        FaceView {\n            inner: self.inner.clone(),\n        }\n    }\n}\n\nimpl<B, M, G> ClosedView for FaceView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Key = FaceKey;\n    type Entity = Face<G>;\n\n    /// Gets the key for the face.\n    fn key(&self) -> Self::Key {\n        self.inner.key()\n    }\n}\n\nimpl<B, M, G> Copy for FaceView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n    View<B, Face<G>>: Copy,\n{\n}\n\nimpl<B, M, G> Deref for FaceView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Target = Face<G>;\n\n    fn deref(&self) -> &Self::Target {\n        self.inner.deref()\n    }\n}\n\nimpl<B, M, G> DerefMut for FaceView<B>\nwhere\n    B: ReborrowMut<Target = M>,\n    M: AsStorageMut<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        self.inner.deref_mut()\n    }\n}\n\nimpl<B, M, G> DynamicArity for FaceView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Face<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Dynamic = usize;\n\n    /// Gets the arity of the face. This is the number of arcs that form the\n    /// face's ring.\n    fn arity(&self) -> Self::Dynamic {\n        self.adjacent_arcs().count()\n    }\n}\n\nimpl<B, M, G> Eq for FaceView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Face<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n}\n\nimpl<B, M, G> From<View<B, Face<G>>> for FaceView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn from(view: View<B, Face<G>>) -> Self {\n        FaceView { inner: view }\n    }\n}\n\nimpl<B, M, G> From<FaceView<B>> for View<B, Face<G>>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn from(face: FaceView<B>) -> Self {\n        let FaceView { inner, .. } = face;\n        inner\n    }\n}\n\nimpl<B, M, G> Hash for FaceView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn hash<H>(&self, state: &mut H)\n    where\n        H: Hasher,\n    {\n        self.inner.hash(state);\n    }\n}\n\nimpl<B, M, G> PartialEq for FaceView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Face<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn eq(&self, other: &Self) -> bool {\n        self.inner == other.inner\n    }\n}\n\nimpl<B, M, G> StaticArity for FaceView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Static = <MeshGraph<G> as StaticArity>::Static;\n\n    const ARITY: Self::Static = MeshGraph::<G>::ARITY;\n}\n\nimpl<B, M, G> ToRing<B> for FaceView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Face<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn into_ring(self) -> Ring<B> {\n        FaceView::into_ring(self)\n    }\n\n    fn ring(&self) -> Ring<&M> {\n        FaceView::ring(self)\n    }\n}\n\n/// Orphan view of a face entity.\npub struct FaceOrphan<'a, G>\nwhere\n    G: GraphData,\n{\n    inner: Orphan<'a, Face<G>>,\n}\n\nimpl<G> FaceOrphan<'_, G>\nwhere\n    G: GraphData,\n{\n    pub fn get(&self) -> &G::Face {\n        self.inner.get()\n    }\n\n    pub fn get_mut(&mut self) -> &mut G::Face {\n        self.inner.get_mut()\n    }\n}\n\nimpl<G> ClosedView for FaceOrphan<'_, G>\nwhere\n    G: GraphData,\n{\n    type Key = FaceKey;\n    type Entity = Face<G>;\n\n    fn key(&self) -> Self::Key {\n        self.inner.key()\n    }\n}\n\nimpl<G> Eq for FaceOrphan<'_, G> where G: GraphData {}\n\nimpl<'a, M> From<FaceView<&'a mut M>> for FaceOrphan<'a, M::Data>\nwhere\n    M: AsStorageMut<Face<M::Data>> + Parametric,\n{\n    fn from(face: FaceView<&'a mut M>) -> Self {\n        Orphan::from(face.inner).into()\n    }\n}\n\nimpl<'a, G> From<Orphan<'a, Face<G>>> for FaceOrphan<'a, G>\nwhere\n    G: GraphData,\n{\n    fn from(inner: Orphan<'a, Face<G>>) -> Self {\n        FaceOrphan { inner }\n    }\n}\n\nimpl<'a, M> From<View<&'a mut M, Face<M::Data>>> for FaceOrphan<'a, M::Data>\nwhere\n    M: AsStorageMut<Face<M::Data>> + Parametric,\n{\n    fn from(view: View<&'a mut M, Face<M::Data>>) -> Self {\n        FaceOrphan { inner: view.into() }\n    }\n}\n\nimpl<G> PartialEq for FaceOrphan<'_, G>\nwhere\n    G: GraphData,\n{\n    fn eq(&self, other: &Self) -> bool {\n        self.inner == other.inner\n    }\n}\n\n/// Closed path formed by adjacent arcs.\n///\n/// Rings are closed paths formed by arcs and their immediately adjacent arcs.\n/// In a consistent graph, every arc forms such a path. Such paths may or may\n/// not be occupied by faces.\n///\n/// Rings are notated by their path. A ring with a perimeter formed by vertices\n/// $A$, $B$, and $C$ is notated $\\overrightarrow{\\\\{A,B,C\\\\}}$. Note that\n/// rotations of the set of vertices are equivalent, such as\n/// $\\overrightarrow{\\\\{B,C,A\\\\}}$.\npub struct Ring<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Arc<Data<B>>> + Consistent + Parametric,\n{\n    arc: ArcView<B>,\n}\n\nimpl<B, M, G> Ring<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn to_ref(&self) -> Ring<&M> {\n        self.arc.to_ref().into_ring()\n    }\n}\n\nimpl<B, M, G> Ring<B>\nwhere\n    B: ReborrowMut<Target = M>,\n    M: AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    // LINT: This convention is specifically used for interior reborrows and is consistent with\n    //       `to_ref`.\n    #[expect(clippy::wrong_self_convention)]\n    fn to_mut_unchecked(&mut self) -> Ring<&mut M> {\n        self.arc.to_mut_unchecked().into_ring()\n    }\n}\n\nimpl<'a, B, M, G> Ring<B>\nwhere\n    B: ReborrowInto<'a, Target = M>,\n    M: AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn into_ref(self) -> Ring<&'a M> {\n        self.arc.into_ref().into_ring()\n    }\n}\n\nimpl<B, M, G> Ring<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    /// Converts the ring into its leading arc.\n    pub fn into_arc(self) -> ArcView<B> {\n        self.arc\n    }\n\n    /// Gets the leading arc of the ring.\n    pub fn arc(&self) -> ArcView<&M> {\n        self.arc.to_ref()\n    }\n}\n\nimpl<B, M, G> Ring<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn into_path(self) -> Path<'static, B> {\n        self.into()\n    }\n\n    pub fn path(&self) -> Path<'static, &M> {\n        self.to_ref().into_path()\n    }\n\n    /// Gets the shortest logical metric between vertices within the ring.\n    ///\n    /// The _logical metric_ assigns the unit weight (one) to every arc and\n    /// effectively counts the number of arcs between vertices. In a closed path\n    /// like a ring, there are two sub-paths between any two vertices. This\n    /// function computes the metric of the shortest sub-path. This may be the\n    /// null path with a zero metric.\n    pub fn shortest_logical_metric(\n        &self,\n        from: impl Into<Selector<VertexKey>>,\n        to: impl Into<Selector<VertexKey>>,\n    ) -> Result<usize, GraphError> {\n        let arity = self.arity();\n        let index = |selector: Selector<_>| match selector {\n            Selector::ByKey(key) => self\n                .vertices()\n                .keys()\n                .enumerate()\n                .find(|(_, a)| *a == key)\n                .map(|(index, _)| index)\n                .ok_or(GraphError::TopologyNotFound),\n            Selector::ByIndex(index) => {\n                if index >= arity {\n                    Err(GraphError::TopologyNotFound)\n                }\n                else {\n                    Ok(index)\n                }\n            }\n        };\n        let from = index(from.into())?;\n        let to = index(to.into())?;\n        let metric = cmp::max(from, to) - cmp::min(from, to);\n        Ok(cmp::min(metric, arity - metric))\n    }\n}\n\nimpl<B, M, G> Ring<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Face<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    /// Converts the ring into its face.\n    ///\n    /// If the path has no associated face, then `None` is returned.\n    pub fn into_face(self) -> Option<FaceView<B>> {\n        let arc = self.into_arc();\n        let key = arc.face;\n        key.map(|key| arc.rebind(key).expect_consistent())\n    }\n\n    /// Gets the face of the ring.\n    ///\n    /// If the path has no associated face, then `None` is returned.\n    pub fn face(&self) -> Option<FaceView<&M>> {\n        self.to_ref().into_face()\n    }\n}\n\nimpl<'a, B, M, G> Ring<B>\nwhere\n    B: ReborrowInto<'a, Target = M>,\n    M: 'a + AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn into_arcs(self) -> impl Clone + Iterator<Item = ArcView<&'a M>> {\n        ArcCirculator::from(self.into_ref())\n    }\n}\n\nimpl<B, G> Ring<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    /// Gets an iterator of views over the arcs within the ring.\n    pub fn arcs(&self) -> impl Clone + Iterator<Item = ArcView<&B::Target>> {\n        self.to_ref().into_arcs()\n    }\n}\n\nimpl<'a, B, M, G> Ring<B>\nwhere\n    B: ReborrowInto<'a, Target = M>,\n    M: 'a + AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn into_vertices(self) -> impl Clone + Iterator<Item = VertexView<&'a M>> {\n        VertexCirculator::from(ArcCirculator::from(self.into_ref()))\n    }\n}\n\nimpl<B, G> Ring<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    /// Gets an iterator of views over the vertices within the ring.\n    pub fn vertices(&self) -> impl Clone + Iterator<Item = VertexView<&B::Target>> {\n        self.to_ref().into_vertices()\n    }\n}\n\nimpl<'a, M> Ring<&'a mut M>\nwhere\n    M: AsStorageMut<Arc<M::Data>> + Consistent + Parametric,\n{\n    pub fn into_arc_orphans(self) -> impl Iterator<Item = ArcOrphan<'a, M::Data>> {\n        ArcCirculator::from(self)\n    }\n}\n\nimpl<B> Ring<B>\nwhere\n    B: ReborrowMut,\n    B::Target: AsStorageMut<Arc<Data<B>>> + Consistent + Parametric,\n{\n    /// Gets an iterator of orphan views over the arcs in the ring.\n    pub fn arc_orphans(&mut self) -> impl Iterator<Item = ArcOrphan<Data<B>>> {\n        self.to_mut_unchecked().into_arc_orphans()\n    }\n}\n\nimpl<'a, M> Ring<&'a mut M>\nwhere\n    M: AsStorage<Arc<M::Data>> + AsStorageMut<Vertex<M::Data>> + Consistent + Parametric,\n{\n    pub fn into_vertex_orphans(self) -> impl Iterator<Item = VertexOrphan<'a, M::Data>> {\n        VertexCirculator::from(ArcCirculator::from(self))\n    }\n}\n\nimpl<B> Ring<B>\nwhere\n    B: ReborrowMut,\n    B::Target: AsStorage<Arc<Data<B>>> + AsStorageMut<Vertex<Data<B>>> + Consistent + Parametric,\n{\n    /// Gets an iterator of views over the vertices within the ring.\n    pub fn vertex_orphans(&mut self) -> impl Iterator<Item = VertexOrphan<Data<B>>> {\n        self.to_mut_unchecked().into_vertex_orphans()\n    }\n}\n\nimpl<'a, M, G> Ring<&'a mut M>\nwhere\n    M: AsStorage<Vertex<G>> + AsStorage<Arc<G>> + AsStorage<Face<G>> + Default + Mutable<Data = G>,\n    G: GraphData,\n{\n    /// Gets the face of the ring or inserts a face if one does not already\n    /// exist.\n    ///\n    /// Returns the existing or inserted face.\n    pub fn get_or_insert_face(self) -> FaceView<&'a mut M> {\n        self.get_or_insert_face_with(Default::default)\n    }\n\n    /// Gets the face of the ring or inserts a face if one does not already\n    /// exist.\n    ///\n    /// If a face is inserted, then the given function is used to get the data\n    /// for the face.\n    ///\n    /// Returns the existing or inserted face.\n    pub fn get_or_insert_face_with<F>(self, f: F) -> FaceView<&'a mut M>\n    where\n        F: FnOnce() -> G::Face,\n    {\n        let key = self.arc.face;\n        if let Some(key) = key {\n            self.arc.rebind(key).expect_consistent()\n        }\n        else {\n            // This should never fail here.\n            let cache = FaceInsertCache::from_ring(self.to_ref()).expect_consistent();\n            let (storage, _) = self.arc.unbind();\n            Mutation::take(storage)\n                .bypass_or_commit_with(|mutation| {\n                    face::insert_with(mutation, cache, || (Default::default(), f()))\n                })\n                .map(|(storage, face)| Bind::bind(storage, face).expect_consistent())\n                .map_err(|(_, error)| error)\n                .expect_consistent()\n        }\n    }\n}\n\nimpl<B, M, G> DynamicArity for Ring<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Dynamic = usize;\n\n    /// Gets the arity of the ring. This is the number of arcs that form the\n    /// path.\n    fn arity(&self) -> Self::Dynamic {\n        self.arcs().count()\n    }\n}\n\nimpl<B, M, G> From<ArcView<B>> for Ring<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn from(arc: ArcView<B>) -> Self {\n        Ring { arc }\n    }\n}\n\nimpl<B, M, G> PartialEq for Ring<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn eq(&self, other: &Self) -> bool {\n        let keys = |ring: &Self| ring.arcs().keys().collect::<HashSet<_>>();\n        keys(self) == keys(other)\n    }\n}\n\nimpl<B, M, G> StaticArity for Ring<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Static = <MeshGraph<G> as StaticArity>::Static;\n\n    const ARITY: Self::Static = MeshGraph::<G>::ARITY;\n}\n\nimpl<B, M, G> ToRing<B> for Ring<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn into_ring(self) -> Ring<B> {\n        self\n    }\n\n    fn ring(&self) -> Ring<&M> {\n        self.to_ref()\n    }\n}\n\npub struct VertexCirculator<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Arc<Data<B>>> + Consistent + Parametric,\n{\n    inner: ArcCirculator<B>,\n}\n\nimpl<B, M, G> Circulator<B> for VertexCirculator<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Entity = Vertex<G>;\n\n    fn next(&mut self) -> Option<<Self::Entity as Entity>::Key> {\n        let ab = self.inner.next();\n        ab.map(|ab| {\n            let (_, b) = ab.into();\n            b\n        })\n    }\n}\n\nimpl<B, M, G> Clone for VertexCirculator<B>\nwhere\n    B: Clone + Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn clone(&self) -> Self {\n        VertexCirculator {\n            inner: self.inner.clone(),\n        }\n    }\n}\n\nimpl<B, M, G> From<ArcCirculator<B>> for VertexCirculator<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn from(inner: ArcCirculator<B>) -> Self {\n        VertexCirculator { inner }\n    }\n}\n\nimpl<'a, M, G> Iterator for VertexCirculator<&'a M>\nwhere\n    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Item = VertexView<&'a M>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        self.bind_next_view()\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        // This requires consistency, because an inconsistent graph may not\n        // produce the expected minimum of three vertices.\n        (3, None)\n    }\n}\n\nimpl<'a, M> Iterator for VertexCirculator<&'a mut M>\nwhere\n    M: AsStorage<Arc<M::Data>> + AsStorageMut<Vertex<M::Data>> + Consistent + Parametric,\n{\n    type Item = VertexOrphan<'a, M::Data>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        unsafe { self.bind_next_orphan() }\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        // This requires consistency, because an inconsistent graph may not\n        // produce the expected minimum of three vertices.\n        (3, None)\n    }\n}\n\nimpl<'a, M> OrphanCirculator<'a, M> for VertexCirculator<&'a mut M>\nwhere\n    M: AsStorage<Arc<M::Data>> + AsStorageMut<Vertex<M::Data>> + Consistent + Parametric,\n{\n    fn target(&mut self) -> &mut M {\n        self.inner.storage\n    }\n}\n\nimpl<'a, M> ViewCirculator<'a, M> for VertexCirculator<&'a M>\nwhere\n    M: AsStorage<Arc<M::Data>> + AsStorage<Vertex<M::Data>> + Consistent + Parametric,\n{\n    fn target(&self) -> &'a M {\n        self.inner.storage\n    }\n}\n\npub struct ArcCirculator<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Arc<Data<B>>> + Consistent + Parametric,\n{\n    storage: B,\n    arc: Option<ArcKey>,\n    trace: TraceFirst<ArcKey>,\n}\n\nimpl<B, M, G> Circulator<B> for ArcCirculator<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Entity = Arc<G>;\n\n    fn next(&mut self) -> Option<<Self::Entity as Entity>::Key> {\n        self.arc\n            .and_then(|arc| self.trace.insert(arc).then_some(arc))\n            .inspect(|arc| {\n                self.arc = self\n                    .storage\n                    .reborrow()\n                    .as_storage()\n                    .get(arc)\n                    .and_then(|arc| arc.next);\n            })\n    }\n}\n\nimpl<B, M, G> Clone for ArcCirculator<B>\nwhere\n    B: Clone + Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn clone(&self) -> Self {\n        ArcCirculator {\n            storage: self.storage.clone(),\n            arc: self.arc,\n            trace: self.trace,\n        }\n    }\n}\n\nimpl<B, M, G> From<Ring<B>> for ArcCirculator<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn from(ring: Ring<B>) -> Self {\n        let (storage, key) = ring.into_arc().unbind();\n        ArcCirculator {\n            storage,\n            arc: Some(key),\n            trace: Default::default(),\n        }\n    }\n}\n\nimpl<'a, M, G> Iterator for ArcCirculator<&'a M>\nwhere\n    M: AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Item = ArcView<&'a M>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        self.bind_next_view()\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        // This requires consistency, because an inconsistent graph may not\n        // produce the expected minimum of three arcs.\n        (3, None)\n    }\n}\n\nimpl<'a, M> Iterator for ArcCirculator<&'a mut M>\nwhere\n    M: AsStorageMut<Arc<M::Data>> + Consistent + Parametric,\n{\n    type Item = ArcOrphan<'a, M::Data>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        unsafe { self.bind_next_orphan() }\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        // This requires consistency, because an inconsistent graph may not\n        // produce the expected minimum of three arcs.\n        (3, None)\n    }\n}\n\nimpl<'a, M> OrphanCirculator<'a, M> for ArcCirculator<&'a mut M>\nwhere\n    M: AsStorageMut<Arc<M::Data>> + Consistent + Parametric,\n{\n    fn target(&mut self) -> &mut M {\n        self.storage\n    }\n}\n\nimpl<'a, M, G> ViewCirculator<'a, M> for ArcCirculator<&'a M>\nwhere\n    M: AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn target(&self) -> &'a M {\n        self.storage\n    }\n}\n\npub struct FaceCirculator<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Arc<Data<B>>> + Consistent + Parametric,\n{\n    inner: ArcCirculator<B>,\n}\n\nimpl<B, M, G> Circulator<B> for FaceCirculator<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Face<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Entity = Face<G>;\n\n    fn next(&mut self) -> Option<<Self::Entity as Entity>::Key> {\n        while let Some(ba) = self.inner.next().map(|ab| ab.into_opposite()) {\n            if let Some(abc) = self\n                .inner\n                .storage\n                .reborrow()\n                .as_storage_of::<Arc<_>>()\n                .get(&ba)\n                .and_then(|opposite| opposite.face)\n            {\n                return Some(abc);\n            }\n            else {\n                // Skip arcs with no opposing face. This can occur within\n                // non-enclosed meshes.\n                continue;\n            }\n        }\n        None\n    }\n}\n\nimpl<B, M, G> Clone for FaceCirculator<B>\nwhere\n    B: Clone + Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn clone(&self) -> Self {\n        FaceCirculator {\n            inner: self.inner.clone(),\n        }\n    }\n}\n\nimpl<B, M, G> From<ArcCirculator<B>> for FaceCirculator<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn from(inner: ArcCirculator<B>) -> Self {\n        FaceCirculator { inner }\n    }\n}\n\nimpl<'a, M, G> Iterator for FaceCirculator<&'a M>\nwhere\n    M: AsStorage<Arc<G>> + AsStorage<Face<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Item = FaceView<&'a M>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        self.bind_next_view()\n    }\n}\n\nimpl<'a, M> Iterator for FaceCirculator<&'a mut M>\nwhere\n    M: AsStorage<Arc<M::Data>> + AsStorageMut<Face<M::Data>> + Consistent + Parametric,\n{\n    type Item = FaceOrphan<'a, M::Data>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        unsafe { self.bind_next_orphan() }\n    }\n}\n\nimpl<'a, M> OrphanCirculator<'a, M> for FaceCirculator<&'a mut M>\nwhere\n    M: AsStorage<Arc<M::Data>> + AsStorageMut<Face<M::Data>> + Consistent + Parametric,\n{\n    fn target(&mut self) -> &mut M {\n        self.inner.storage\n    }\n}\n\nimpl<'a, M, G> ViewCirculator<'a, M> for FaceCirculator<&'a M>\nwhere\n    M: AsStorage<Arc<G>> + AsStorage<Face<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn target(&self) -> &'a M {\n        self.inner.storage\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use decorum::R64;\n    use nalgebra::{Point2, Point3};\n\n    use crate::graph::MeshGraph;\n    use crate::index::HashIndexer;\n    use crate::prelude::*;\n    use crate::primitive::cube::Cube;\n    use crate::primitive::generate::Position;\n    use crate::primitive::sphere::UvSphere;\n    use crate::primitive::Tetragon;\n\n    type E2 = Point2<R64>;\n    type E3 = Point3<R64>;\n\n    #[test]\n    fn circulate_over_arcs() {\n        let graph: MeshGraph<E3> = UvSphere::new(3, 2)\n            .polygons::<Position<E3>>() // 6 triangles, 18 vertices.\n            .collect();\n        let face = graph.faces().next().unwrap();\n\n        // All faces should be triangles and should have three edges.\n        assert_eq!(3, face.adjacent_arcs().count());\n    }\n\n    #[test]\n    fn circulate_over_faces() {\n        let graph: MeshGraph<E3> = UvSphere::new(3, 2)\n            .polygons::<Position<E3>>() // 6 triangles, 18 vertices.\n            .collect();\n        let face = graph.faces().next().unwrap();\n\n        // No matter which face is selected, it should have three adjacent\n        // faces.\n        assert_eq!(3, face.adjacent_faces().count());\n    }\n\n    #[test]\n    fn remove_face() {\n        let mut graph: MeshGraph<E3> = UvSphere::new(3, 2)\n            .polygons::<Position<E3>>() // 6 triangles, 18 vertices.\n            .collect();\n\n        // The graph should begin with 6 faces.\n        assert_eq!(6, graph.face_count());\n\n        // Remove a face from the graph.\n        let abc = graph.faces().next().unwrap().key();\n        {\n            let face = graph.face_mut(abc).unwrap();\n            assert_eq!(3, face.arity()); // The face should be triangular.\n\n            let path = face.remove().unwrap().into_ref();\n            assert_eq!(3, path.arity()); // The path should also be triangular.\n        }\n\n        // After the removal, the graph should have only 5 faces.\n        assert_eq!(5, graph.face_count());\n    }\n\n    #[test]\n    fn split_face() {\n        let mut graph = MeshGraph::<E2>::from_raw_buffers_with_arity(\n            vec![0u32, 1, 2, 3],\n            vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)],\n            4,\n        )\n        .unwrap();\n        let abc = graph.faces().next().unwrap().key();\n        let arc = graph\n            .face_mut(abc)\n            .unwrap()\n            .split(ByIndex(0), ByIndex(2))\n            .unwrap()\n            .into_ref();\n\n        assert!(arc.face().is_some());\n        assert!(arc.opposite_arc().face().is_some());\n        assert_eq!(4, graph.vertex_count());\n        assert_eq!(10, graph.arc_count());\n        assert_eq!(2, graph.face_count());\n    }\n\n    #[test]\n    fn extrude_face() {\n        let mut graph: MeshGraph<E3> = UvSphere::new(3, 2)\n            .polygons::<Position<E3>>() // 6 triangles, 18 vertices.\n            .collect();\n        {\n            let key = graph.faces().next().unwrap().key();\n            let face = graph\n                .face_mut(key)\n                .unwrap()\n                .extrude_with_offset(R64::assert(1.0))\n                .unwrap()\n                .into_ref();\n\n            // The extruded face, being a triangle, should have three adjacent\n            // faces.\n            assert_eq!(3, face.adjacent_faces().count());\n        }\n\n        assert_eq!(8, graph.vertex_count());\n        // The mesh begins with 18 arcs. The extrusion adds three quadrilaterals\n        // with four interior arcs each, so there are `18 + (3 * 4)` arcs.\n        assert_eq!(30, graph.arc_count());\n        // All faces are triangles and the mesh begins with six such faces. The\n        // extruded face remains, in addition to three connective faces, each of\n        // which is constructed from quadrilaterals.\n        assert_eq!(9, graph.face_count());\n    }\n\n    // LINT: In this test, adjacent `nth` calls are used over `0` and `1` and are arguably more\n    //       consistent and therefore a bit easier to read.\n    #[expect(clippy::iter_nth_zero)]\n    #[test]\n    fn merge_faces() {\n        // Construct a graph with two connected quadrilaterals.\n        let mut graph = MeshGraph::<E2>::from_raw_buffers_with_arity(\n            vec![0u32, 1, 2, 3, 0, 3, 4, 5],\n            vec![\n                (0.0, 0.0),  // 0\n                (1.0, 0.0),  // 1\n                (1.0, 1.0),  // 2\n                (0.0, 1.0),  // 3\n                (-1.0, 1.0), // 4\n                (-1.0, 0.0), // 5\n            ],\n            4,\n        )\n        .unwrap();\n\n        // The graph should begin with 2 faces.\n        assert_eq!(2, graph.face_count());\n\n        // Get the keys for the two faces and join them.\n        let abc = graph.faces().nth(0).unwrap().key();\n        let def = graph.faces().nth(1).unwrap().key();\n        graph.face_mut(abc).unwrap().merge(def).unwrap();\n\n        // After the removal, the graph should have 1 face.\n        assert_eq!(1, graph.face_count());\n        assert_eq!(6, graph.faces().next().unwrap().arity());\n    }\n\n    #[test]\n    fn poke_face() {\n        let mut graph: MeshGraph<E3> = Cube::new()\n            .polygons::<Position<E3>>() // 6 quadrilaterals, 24 vertices.\n            .collect();\n        let key = graph.faces().next().unwrap().key();\n        let vertex = graph.face_mut(key).unwrap().poke_at_centroid();\n\n        // Diverging a quadrilateral yields a tetrahedron.\n        assert_eq!(4, vertex.adjacent_faces().count());\n\n        // Traverse to one of the triangles in the tetrahedron.\n        let face = vertex.into_outgoing_arc().into_face().unwrap();\n\n        assert_eq!(3, face.arity());\n\n        // Diverge the triangle.\n        let vertex = face.poke_at_centroid();\n\n        assert_eq!(3, vertex.adjacent_faces().count());\n    }\n\n    #[test]\n    fn triangulate_mesh() {\n        let (indices, vertices) = Cube::new()\n            .polygons::<Position<E3>>() // 6 quadrilaterals, 24 vertices.\n            .index_vertices::<Tetragon<usize>, _>(HashIndexer::default());\n        let mut graph = MeshGraph::<E3>::from_raw_buffers(indices, vertices).unwrap();\n        graph.triangulate();\n\n        assert_eq!(8, graph.vertex_count());\n        assert_eq!(36, graph.arc_count());\n        assert_eq!(18, graph.edge_count());\n        // Each quadrilateral becomes 2 triangles, so 6 quadrilaterals become\n        // 12 triangles.\n        assert_eq!(12, graph.face_count());\n    }\n\n    #[test]\n    fn logical_metrics() {\n        let graph = MeshGraph::<Point2<f32>>::from_raw_buffers_with_arity(\n            vec![0u32, 1, 2, 3],\n            vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)],\n            4,\n        )\n        .unwrap();\n        let face = graph.faces().next().unwrap();\n        let keys = face\n            .adjacent_vertices()\n            .map(|vertex| vertex.key())\n            .collect::<Vec<_>>();\n        let ring = face.into_ring();\n        assert_eq!(2, ring.shortest_logical_metric(keys[0], keys[2]).unwrap());\n        assert_eq!(1, ring.shortest_logical_metric(keys[0], keys[3]).unwrap());\n        assert_eq!(0, ring.shortest_logical_metric(keys[0], keys[0]).unwrap());\n    }\n}\n"
  },
  {
    "path": "plexus/src/graph/geometry.rs",
    "content": "//! Geometric graph traits.\n\n// Geometric traits like `FaceNormal` and `EdgeMidpoint` are defined in such a\n// way to reduce the contraints necessary for writing generic user code. With\n// few exceptions, these traits only depend on `AsPosition` being implemented by\n// the `Vertex` type in their definition. If a more complex implementation is\n// necessary, constraints are specified there so that they do not pollute user\n// code.\n\nuse theon::ops::{Cross, Interpolate, Project};\nuse theon::query::Plane;\nuse theon::space::{EuclideanSpace, FiniteDimensional, InnerSpace, Vector, VectorSpace};\nuse theon::{AsPosition, Position};\nuse typenum::U3;\n\nuse crate::entity::borrow::Reborrow;\nuse crate::entity::storage::AsStorage;\nuse crate::graph::data::{GraphData, Parametric};\nuse crate::graph::edge::{Arc, ArcView, Edge, ToArc};\nuse crate::graph::face::{Face, ToRing};\nuse crate::graph::mutation::Consistent;\nuse crate::graph::vertex::{Vertex, VertexView};\nuse crate::graph::{GraphError, OptionExt as _, ResultExt as _};\nuse crate::IteratorExt as _;\n\npub type VertexPosition<G> = Position<<G as GraphData>::Vertex>;\n\npub trait VertexCentroid: GraphData\nwhere\n    Self::Vertex: AsPosition,\n{\n    fn centroid<B>(vertex: VertexView<B>) -> Result<VertexPosition<Self>, GraphError>\n    where\n        B: Reborrow,\n        B::Target:\n            AsStorage<Arc<Self>> + AsStorage<Vertex<Self>> + Consistent + Parametric<Data = Self>;\n}\n\nimpl<G> VertexCentroid for G\nwhere\n    G: GraphData,\n    G::Vertex: AsPosition,\n{\n    fn centroid<B>(vertex: VertexView<B>) -> Result<VertexPosition<Self>, GraphError>\n    where\n        B: Reborrow,\n        B::Target:\n            AsStorage<Arc<Self>> + AsStorage<Vertex<Self>> + Consistent + Parametric<Data = Self>,\n    {\n        Ok(VertexPosition::<Self>::centroid(\n            vertex\n                .adjacent_vertices()\n                .map(|vertex| *vertex.data.as_position()),\n        )\n        .expect_consistent())\n    }\n}\n\npub trait VertexNormal: FaceNormal\nwhere\n    Self::Vertex: AsPosition,\n{\n    fn normal<B>(vertex: VertexView<B>) -> Result<Vector<VertexPosition<Self>>, GraphError>\n    where\n        B: Reborrow,\n        B::Target: AsStorage<Arc<Self>>\n            + AsStorage<Face<Self>>\n            + AsStorage<Vertex<Self>>\n            + Consistent\n            + Parametric<Data = Self>;\n}\n\nimpl<G> VertexNormal for G\nwhere\n    G: FaceNormal,\n    G::Vertex: AsPosition,\n{\n    fn normal<B>(vertex: VertexView<B>) -> Result<Vector<VertexPosition<Self>>, GraphError>\n    where\n        B: Reborrow,\n        B::Target: AsStorage<Arc<Self>>\n            + AsStorage<Face<Self>>\n            + AsStorage<Vertex<Self>>\n            + Consistent\n            + Parametric<Data = Self>,\n    {\n        Vector::<VertexPosition<Self>>::mean(\n            vertex\n                .adjacent_faces()\n                .map(<Self as FaceNormal>::normal)\n                .collect::<Result<Vec<_>, _>>()?,\n        )\n        .expect_consistent()\n        .normalize()\n        .ok_or(GraphError::Geometry)\n    }\n}\n\npub trait ArcNormal: GraphData\nwhere\n    Self::Vertex: AsPosition,\n{\n    fn normal<B>(arc: ArcView<B>) -> Result<Vector<VertexPosition<Self>>, GraphError>\n    where\n        B: Reborrow,\n        B::Target:\n            AsStorage<Arc<Self>> + AsStorage<Vertex<Self>> + Consistent + Parametric<Data = Self>;\n}\n\nimpl<G> ArcNormal for G\nwhere\n    G: GraphData,\n    G::Vertex: AsPosition,\n    VertexPosition<G>: EuclideanSpace,\n    Vector<VertexPosition<G>>: Project<Output = Vector<VertexPosition<G>>>,\n{\n    fn normal<B>(arc: ArcView<B>) -> Result<Vector<VertexPosition<Self>>, GraphError>\n    where\n        B: Reborrow,\n        B::Target:\n            AsStorage<Arc<Self>> + AsStorage<Vertex<Self>> + Consistent + Parametric<Data = Self>,\n    {\n        let (a, b) = arc\n            .adjacent_vertices()\n            .map(|vertex| *vertex.position())\n            .try_collect()\n            .expect_consistent();\n        let c = *arc.next_arc().destination_vertex().position();\n        let ab = a - b;\n        let cb = c - b;\n        let p = b + ab.project(cb);\n        (p - c).normalize().ok_or(GraphError::Geometry)\n    }\n}\n\npub trait EdgeMidpoint: GraphData\nwhere\n    Self::Vertex: AsPosition,\n{\n    fn midpoint<B, T>(edge: T) -> Result<VertexPosition<Self>, GraphError>\n    where\n        B: Reborrow,\n        B::Target: AsStorage<Arc<Self>>\n            + AsStorage<Edge<Self>>\n            + AsStorage<Vertex<Self>>\n            + Consistent\n            + Parametric<Data = Self>,\n        T: ToArc<B>;\n}\n\nimpl<G> EdgeMidpoint for G\nwhere\n    G: GraphData,\n    G::Vertex: AsPosition,\n    VertexPosition<G>: Interpolate<Output = VertexPosition<G>>,\n{\n    fn midpoint<B, T>(edge: T) -> Result<VertexPosition<Self>, GraphError>\n    where\n        B: Reborrow,\n        B::Target: AsStorage<Arc<Self>>\n            + AsStorage<Edge<Self>>\n            + AsStorage<Vertex<Self>>\n            + Consistent\n            + Parametric<Data = Self>,\n        T: ToArc<B>,\n    {\n        let arc = edge.into_arc();\n        let (a, b) = arc\n            .adjacent_vertices()\n            .map(|vertex| *vertex.position())\n            .try_collect()\n            .expect_consistent();\n        Ok(a.midpoint(b))\n    }\n}\n\npub trait FaceCentroid: GraphData\nwhere\n    Self::Vertex: AsPosition,\n{\n    fn centroid<B, T>(ring: T) -> Result<VertexPosition<Self>, GraphError>\n    where\n        B: Reborrow,\n        B::Target:\n            AsStorage<Arc<Self>> + AsStorage<Vertex<Self>> + Consistent + Parametric<Data = Self>,\n        T: ToRing<B>;\n}\n\nimpl<G> FaceCentroid for G\nwhere\n    G: GraphData,\n    G::Vertex: AsPosition,\n{\n    fn centroid<B, T>(ring: T) -> Result<VertexPosition<Self>, GraphError>\n    where\n        B: Reborrow,\n        B::Target:\n            AsStorage<Arc<Self>> + AsStorage<Vertex<Self>> + Consistent + Parametric<Data = Self>,\n        T: ToRing<B>,\n    {\n        let ring = ring.into_ring();\n        Ok(\n            VertexPosition::<Self>::centroid(ring.vertices().map(|vertex| *vertex.position()))\n                .expect_consistent(),\n        )\n    }\n}\n\npub trait FaceNormal: GraphData\nwhere\n    Self::Vertex: AsPosition,\n{\n    fn normal<B, T>(ring: T) -> Result<Vector<VertexPosition<Self>>, GraphError>\n    where\n        B: Reborrow,\n        B::Target:\n            AsStorage<Arc<Self>> + AsStorage<Vertex<Self>> + Consistent + Parametric<Data = Self>,\n        T: ToRing<B>;\n}\n\nimpl<G> FaceNormal for G\nwhere\n    G: FaceCentroid + GraphData,\n    G::Vertex: AsPosition,\n    Vector<VertexPosition<G>>: Cross<Output = Vector<VertexPosition<G>>>,\n    VertexPosition<G>: EuclideanSpace,\n{\n    fn normal<B, T>(ring: T) -> Result<Vector<VertexPosition<Self>>, GraphError>\n    where\n        B: Reborrow,\n        B::Target:\n            AsStorage<Arc<Self>> + AsStorage<Vertex<Self>> + Consistent + Parametric<Data = Self>,\n        T: ToRing<B>,\n    {\n        let ring = ring.into_ring();\n        let (a, b) = ring\n            .vertices()\n            .take(2)\n            .map(|vertex| *vertex.position())\n            .try_collect()\n            .expect_consistent();\n        let c = G::centroid(ring)?;\n        let ab = a - b;\n        let bc = b - c;\n        ab.cross(bc).normalize().ok_or(GraphError::Geometry)\n    }\n}\n\npub trait FacePlane: GraphData\nwhere\n    Self::Vertex: AsPosition,\n    VertexPosition<Self>: FiniteDimensional<N = U3>,\n{\n    fn plane<B, T>(ring: T) -> Result<Plane<VertexPosition<Self>>, GraphError>\n    where\n        B: Reborrow,\n        B::Target:\n            AsStorage<Arc<Self>> + AsStorage<Vertex<Self>> + Consistent + Parametric<Data = Self>,\n        T: ToRing<B>;\n}\n\n// TODO: The `lapack` feature depends on `ndarray-linalg` and Intel MKL. MKL is\n//       dynamically linked, but the linkage fails during doctests and may fail\n//       when launching a binary. The `lapack` feature and this implementation\n//       have been disabled until an upstream fix is available. See\n//       https://github.com/olson-sean-k/plexus/issues/58 and\n//       https://github.com/rust-ndarray/ndarray-linalg/issues/229\n// TODO: The `lapack` feature only supports Linux. See\n//       https://github.com/olson-sean-k/theon/issues/1\n//\n//#[cfg(target_os = \"linux\")]\n//mod lapack {\n//    use super::*;\n//\n//    use smallvec::SmallVec;\n//    use theon::adjunct::{FromItems, IntoItems};\n//    use theon::lapack::Lapack;\n//    use theon::space::Scalar;\n//\n//    impl<G> FacePlane for G\n//    where\n//        G: GraphData,\n//        G::Vertex: AsPosition,\n//        VertexPosition<G>: EuclideanSpace + FiniteDimensional<N = U3>,\n//        Scalar<VertexPosition<G>>: Lapack,\n//        Vector<VertexPosition<G>>: FromItems + IntoItems,\n//    {\n//        fn plane<B, T>(ring: T) -> Result<Plane<VertexPosition<G>>, GraphError>\n//        where\n//            B: Reborrow,\n//            B::Target: AsStorage<Arc<Self>>\n//                + AsStorage<Vertex<Self>>\n//                + Consistent\n//                + Parametric<Data = Self>,\n//            T: ToRing<B>,\n//        {\n//            let ring = ring.into_ring();\n//            let points = ring\n//                .vertices()\n//                .map(|vertex| *vertex.data.as_position())\n//                .collect::<SmallVec<[_; 4]>>();\n//            Plane::from_points(points).ok_or(GraphError::Geometry)\n//        }\n//    }\n//}\n"
  },
  {
    "path": "plexus/src/graph/mod.rs",
    "content": "//! Half-edge graph representation of polygonal meshes.\n//!\n//! This module provides a flexible representation of polygonal meshes as a\n//! [half-edge graph][dcel]. Plexus refers to _Half-edges_ and _edges_ as _arcs_\n//! and _edges_, respectively. Graphs can store arbitrary data associated with\n//! any topological entity (vertices, arcs, edges, and faces).\n//!\n//! Graph APIs support geometric operations if vertex data implements the\n//! [`AsPosition`] trait.\n//!\n//! See the [user guide][guide-graphs] for more details and examples.\n//!\n//! # Representation\n//!\n//! A [`MeshGraph`] is fundamentally composed of four entities: _vertices_,\n//! _arcs_, _edges_, and _faces_. The figure below summarizes the connectivity\n//! of these entities.\n//!\n//! ![Half-Edge Graph Figure](https://plexus.rs/img/heg.svg)\n//!\n//! Arcs are directed and connect vertices. An arc that is directed toward a\n//! vertex $A$ is an _incoming arc_ with respect to $A$. Similarly, an arc\n//! directed away from such a vertex is an _outgoing arc_. Every vertex is\n//! associated with exactly one _leading arc_, which is always an outgoing arc.\n//! The vertex toward which an arc is directed is the arc's _destination vertex_\n//! and the other is its _source vertex_.\n//!\n//! Every arc is paired with an _opposite arc_ with an opposing direction.\n//! Given an arc from a vertex $A$ to a vertex $B$, that arc will have an\n//! opposite arc from $B$ to $A$. Such arcs are notated $\\overrightarrow{AB}$\n//! and $\\overrightarrow{BA}$. Together, these arcs form an _edge_, which is not\n//! directed. An edge and its two arcs are together called a _composite edge_.\n//!\n//! Arcs are connected to their adjacent arcs, known as _next_ and _previous\n//! arcs_. A traversal along a series of arcs is a _path_. The path formed by\n//! traversing from an arc to its next arc and so on is a _ring_. When a face is\n//! present within an ring, the arcs will refer to that face and the face will\n//! refer to exactly one of the arcs in the ring (this is the leading arc of the\n//! face). An arc with no associated face is known as a _boundary arc_.  If\n//! either of an edge's arcs is a boundary arc, then that edge is a _boundary\n//! edge_.\n//!\n//! A path that terminates is _open_ and a path that forms a loop is _closed_.\n//! Rings are always closed. Paths may be notated using _sequence_ or _set\n//! notation_ and both forms are used to describe rings and faces.\n//!\n//! Sequence notation is formed from the ordered sequence of vertices that a\n//! path traverses, including the source vertex of the first arc and the\n//! destination vertex of the last arc. Set notation is similar, but is\n//! implicitly closed and only includes the ordered and unique set of vertices\n//! traversed by the path. An open path over vertices $A$, $B$, and $C$ is\n//! notated as a sequence $\\overrightarrow{(A,B,C)}$. A closed path over\n//! vertices $A$, $B$, and $C$ includes the arc $\\overrightarrow{CA}$ and is\n//! notated as a sequence $\\overrightarrow{(A,B,C,A)}$ or a set\n//! $\\overrightarrow{\\\\{A,B,C\\\\}}$.\n//!\n//! Together with vertices and faces, the connectivity of arcs allows for\n//! effecient traversals. For example, it becomes trivial to find adjacent\n//! entities, such as the faces that share a given vertex or the adjacent faces\n//! of a given face.\n//!\n//! [`MeshGraph`]s store entities using associative data structures with\n//! strongly typed and opaque keys. These keys are used to refer entities in a\n//! graph. Note that paths and rings are **not** entities and are not explicitly\n//! stored in graphs.\n//!\n//! # Views\n//!\n//! [`MeshGraph`]s expose _views_ over their entities (vertices, arcs, edges,\n//! and faces). Views are a type of _smart pointer_ and bind entity storage with\n//! a key for a specific entity. They extend entities with rich behaviors and\n//! expose their associated data via `get` and `get_mut` functions.\n//!\n//! Views provide the primary API for interacting with a [`MeshGraph`]'s\n//! topology and data. There are three types of views summarized below:\n//!\n//! | Type      | Traversal | Exclusive | Data      | Topology  |\n//! |-----------|-----------|-----------|-----------|-----------|\n//! | Immutable | Yes       | No        | Immutable | Immutable |\n//! | Mutable   | Yes       | Yes       | Mutable   | Mutable   |\n//! | Orphan    | No        | No        | Mutable   | N/A       |\n//!\n//! _Immutable_ and _mutable views_ behave similarly to Rust's `&` and `&mut`\n//! references: immutable views cannot mutate a graph and are not exclusive\n//! while mutable views may mutate both the data and topology of a graph but are\n//! exclusive.\n//!\n//! _Orphan views_ (simply referred to as _orphans_ in APIs) may mutate the data\n//! of a graph, but they cannot access the topology of a graph and cannot\n//! traverse a graph in any way. This is only useful for modifying the data in a\n//! graph, but unlike mutable views, orphan views are not exclusive.\n//!\n//! Views perform _interior reborrows_, which reborrow the reference to storage\n//! to construct other views. Immutable reborrows can be performed explicitly\n//! using the conversions described below:\n//!\n//! | Function   | Receiver    | Borrow | Output    |\n//! |------------|-------------|--------|-----------|\n//! | `to_ref`   | `&self`     | `&_`   | Immutable |\n//! | `into_ref` | `self`      | `&*_`  | Immutable |\n//!\n//! It is not possible to explicitly perform a mutable interior reborrow. Such a\n//! reborrow could invalidate the source view by performing a topological\n//! mutation. Mutable reborrows are performed beneath safe APIs, such as those\n//! exposing iterators over orphan views.\n//!\n//! # Geometric Traits\n//!\n//! The [`GraphData`] trait is used to specify the types of data stored in\n//! entities in a [`MeshGraph`]. If the `Vertex` data implements the\n//! [`AsPosition`] trait and the positional data implements the appropriate\n//! geometric traits, then geometric APIs like\n//! [`split_at_midpoint`][`ArcView::split_at_midpoint`] and\n//! [`poke_with_offset`][`FaceView::poke_with_offset`] can be used. Abstracting\n//! this in generic code involves various traits from [`theon`].\n//!\n//! This module provides geometric traits that describe supported geometric\n//! operations without the need to express complicated relationships between\n//! types representing a [Euclidean space][`EuclideanSpace`]. These traits\n//! express the geometric capabilites of [`GraphData`]. For example, the\n//! following generic function requires [`EdgeMidpoint`] and subdivides faces in\n//! a graph by splitting edges at their midpoints:\n//!\n//! ```rust\n//! # extern crate plexus;\n//! # extern crate smallvec;\n//! #\n//! use plexus::geometry::AsPositionMut;\n//! use plexus::graph::{EdgeMidpoint, FaceView, GraphData, MeshGraph};\n//! use plexus::prelude::*;\n//! use smallvec::SmallVec;\n//!\n//! // Requires `EdgeMidpoint` for `split_at_midpoint`.\n//! pub fn ambo<G>(face: FaceView<&mut MeshGraph<G>>) -> FaceView<&mut MeshGraph<G>>\n//! where\n//!     G: EdgeMidpoint + GraphData,\n//!     G::Vertex: AsPositionMut,\n//! {\n//!     let arity = face.arity();\n//!     let mut arc = face.into_arc();\n//!     let mut splits = SmallVec::<[_; 4]>::with_capacity(arity);\n//!     for _ in 0..arity {\n//!         let vertex = arc.split_at_midpoint();\n//!         splits.push(vertex.key());\n//!         arc = vertex.into_outgoing_arc().into_next_arc();\n//!     }\n//!     let mut face = arc.into_face().unwrap();\n//!     for (a, b) in splits.into_iter().perimeter() {\n//!         face = face.split(a, b).unwrap().into_face().unwrap();\n//!     }\n//!     face\n//! }\n//! ```\n//!\n//! # Examples\n//!\n//! Generating a [`MeshGraph`] from a [$uv$-sphere][`UvSphere`]:\n//!\n//! ```rust\n//! # extern crate decorum;\n//! # extern crate nalgebra;\n//! # extern crate plexus;\n//! #\n//! use decorum::R64;\n//! use nalgebra::Point3;\n//! use plexus::graph::MeshGraph;\n//! use plexus::prelude::*;\n//! use plexus::primitive::generate::Position;\n//! use plexus::primitive::sphere::UvSphere;\n//!\n//! type E3 = Point3<R64>;\n//!\n//! let mut graph: MeshGraph<E3> = UvSphere::default().polygons::<Position<E3>>().collect();\n//! ```\n//!\n//! Extruding a face in a [`MeshGraph`]:\n//!\n//! ```rust\n//! # extern crate decorum;\n//! # extern crate nalgebra;\n//! # extern crate plexus;\n//! #\n//! use decorum::R64;\n//! use nalgebra::Point3;\n//! use plexus::graph::MeshGraph;\n//! use plexus::prelude::*;\n//! use plexus::primitive::generate::Position;\n//! use plexus::primitive::sphere::UvSphere;\n//!\n//! type E3 = Point3<R64>;\n//!\n//! let mut graph: MeshGraph<E3> = UvSphere::new(8, 8).polygons::<Position<E3>>().collect();\n//! // Get the key of the first face and then extrude it.\n//! let key = graph.faces().next().unwrap().key();\n//! let face = graph\n//!     .face_mut(key)\n//!     .unwrap()\n//!     .extrude_with_offset(R64::assert(1.0))\n//!     .unwrap();\n//! ```\n//!\n//! Traversing and circulating over a [`MeshGraph`]:\n//!\n//! ```rust\n//! # extern crate nalgebra;\n//! # extern crate plexus;\n//! #\n//! use nalgebra::Point2;\n//! use plexus::graph::MeshGraph;\n//! use plexus::prelude::*;\n//! use plexus::primitive::Tetragon;\n//!\n//! let mut graph = MeshGraph::<Point2<f64>>::from_raw_buffers(\n//!     vec![Tetragon::new(0u32, 1, 2, 3)],\n//!     vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)],\n//! )\n//! .unwrap();\n//! graph.triangulate();\n//!\n//! // Traverse an arc and use a circulator to get the faces of a nearby vertex.\n//! let key = graph.arcs().next().unwrap().key();\n//! let mut vertex = graph\n//!     .arc_mut(key)\n//!     .unwrap()\n//!     .into_opposite_arc()\n//!     .into_next_arc()\n//!     .into_destination_vertex();\n//! for mut face in vertex.adjacent_face_orphans() {\n//!     // `face.get_mut()` provides a mutable reference to face data.\n//! }\n//! ```\n//!\n//! [dcel]: https://en.wikipedia.org/wiki/doubly_connected_edge_list\n//! [guide-graphs]: https://plexus.rs/user-guide/graphs\n//!\n//! [`theon`]: https://crates.io/crates/theon\n//!\n//! [`Deref`]: std::ops::Deref\n//! [`EuclideanSpace`]: theon::space::EuclideanSpace\n//! [`AsPosition`]: crate::geometry::AsPosition\n//! [`ArcView::split_at_midpoint`]: crate::graph::ArcView::split_at_midpoint\n//! [`EdgeMidpoint`]: crate::graph::EdgeMidpoint\n//! [`FaceView::poke_with_offset`]: crate::graph::FaceView::poke_with_offset\n//! [`GraphData`]: crate::graph::GraphData\n//! [`MeshGraph`]: crate::graph::MeshGraph\n//! [`UvSphere`]: crate::primitive::sphere::UvSphere\n\nmod builder;\nmod core;\nmod data;\nmod edge;\nmod face;\nmod geometry;\nmod mutation;\nmod path;\nmod vertex;\n\nuse decorum::cmp::EmptyOrd;\nuse decorum::R64;\nuse num::{Integer, NumCast, ToPrimitive, Unsigned};\nuse smallvec::SmallVec;\nuse std::borrow::Borrow;\nuse std::collections::{HashMap, HashSet};\nuse std::convert::TryFrom;\nuse std::fmt::Debug;\nuse std::hash::Hash;\nuse std::iter::FromIterator;\nuse std::mem;\nuse std::vec;\nuse theon::adjunct::Map;\nuse theon::query::Aabb;\nuse theon::space::{EuclideanSpace, Scalar};\nuse theon::{AsPosition, AsPositionMut};\nuse thiserror::Error;\nuse typenum::NonZero;\n\nuse crate::buffer::{BufferError, FromRawBuffers, FromRawBuffersWithArity, MeshBuffer};\nuse crate::builder::{Buildable, FacetBuilder, MeshBuilder, SurfaceBuilder};\nuse crate::constant::{Constant, ToType, TypeOf};\nuse crate::encoding::{FaceDecoder, FromEncoding, VertexDecoder};\nuse crate::entity::borrow::Reborrow;\nuse crate::entity::storage::prelude::*;\nuse crate::entity::storage::{AsStorage, AsStorageMut, AsStorageOf, Key, StorageTarget};\nuse crate::entity::view::{Bind, Orphan, View};\nuse crate::entity::{Entity, EntityError, Payload};\nuse crate::geometry::{FromGeometry, IntoGeometry};\nuse crate::graph::builder::GraphBuilder;\nuse crate::graph::core::{Core, OwnedCore};\nuse crate::graph::data::Parametric;\nuse crate::graph::edge::{Arc, Edge};\nuse crate::graph::face::Face;\nuse crate::graph::mutation::face::FaceInsertCache;\nuse crate::graph::mutation::{Consistent, Immediate};\nuse crate::graph::vertex::Vertex;\nuse crate::index::{Flat, FromIndexer, Grouping, HashIndexer, IndexBuffer, IndexVertices, Indexer};\nuse crate::primitive::decompose::IntoVertices;\nuse crate::primitive::{IntoPolygons, Polygonal, UnboundedPolygon};\nuse crate::transact::Transact;\nuse crate::{DynamicArity, MeshArity, StaticArity};\n\npub use crate::entity::view::{ClosedView, Rebind};\npub use crate::graph::data::GraphData;\npub use crate::graph::edge::{ArcKey, ArcOrphan, ArcView, EdgeKey, EdgeOrphan, EdgeView, ToArc};\npub use crate::graph::face::{FaceKey, FaceOrphan, FaceView, Ring, ToRing};\npub use crate::graph::geometry::{\n    ArcNormal, EdgeMidpoint, FaceCentroid, FaceNormal, FacePlane, VertexCentroid, VertexNormal,\n    VertexPosition,\n};\npub use crate::graph::path::Path;\npub use crate::graph::vertex::{VertexKey, VertexOrphan, VertexView};\n\npub use Selector::ByIndex;\npub use Selector::ByKey;\n\ntype Mutation<M> = mutation::Mutation<Immediate<M>>;\n\n/// Errors concerning [`MeshGraph`]s.\n///\n/// [`MeshGraph`]: crate::graph::MeshGraph\n#[derive(Debug, Eq, Error, PartialEq)]\npub enum GraphError {\n    #[error(\"required topology not found\")]\n    TopologyNotFound,\n    #[error(\"conflicting topology found\")]\n    TopologyConflict,\n    #[error(\"topology malformed\")]\n    TopologyMalformed,\n    #[error(\"topology unreachable\")]\n    TopologyUnreachable,\n    #[error(\"arity is non-polygonal\")]\n    ArityNonPolygonal,\n    /// The arity of a [`MeshGraph`] or other data structure is not compatible\n    /// with an operation.\n    #[error(\"conflicting arity; expected {expected}, but got {actual}\")]\n    ArityConflict {\n        /// The expected arity.\n        expected: usize,\n        /// The incompatible arity that was encountered.\n        actual: usize,\n    },\n    /// The compound arity of a [`MeshGraph`] or other data structure is not\n    /// uniform.\n    ///\n    /// This error occurs when an operation requires a uniform arity but a graph\n    /// or other data structure is non-uniform. See [`MeshArity`].\n    ///\n    /// [`MeshArity`]: crate::MeshArity\n    #[error(\"arity is non-uniform\")]\n    ArityNonUniform,\n    /// Geometry is incompatible or cannot be computed.\n    #[error(\"geometric operation failed\")]\n    Geometry,\n    /// A graph or other data structure is not compatible with an encoding.\n    #[error(\"encoding operation failed\")]\n    EncodingIncompatible,\n}\n\n// TODO: How should buffer errors be handled? Is this sufficient?\nimpl From<BufferError> for GraphError {\n    fn from(error: BufferError) -> Self {\n        match error {\n            BufferError::ArityConflict { expected, actual } => {\n                GraphError::ArityConflict { expected, actual }\n            }\n            _ => GraphError::EncodingIncompatible,\n        }\n    }\n}\n\nimpl From<EntityError> for GraphError {\n    fn from(error: EntityError) -> Self {\n        match error {\n            EntityError::EntityNotFound => GraphError::TopologyNotFound,\n            EntityError::Data => GraphError::Geometry,\n        }\n    }\n}\n\ntrait OptionExt<T> {\n    fn expect_consistent(self) -> T;\n}\n\nimpl<T> OptionExt<T> for Option<T> {\n    fn expect_consistent(self) -> T {\n        self.expect(\"internal error: graph consistency violated\")\n    }\n}\n\ntrait ResultExt<T, E> {\n    fn expect_consistent(self) -> T\n    where\n        E: Debug;\n}\n\nimpl<T, E> ResultExt<T, E> for Result<T, E> {\n    fn expect_consistent(self) -> T\n    where\n        E: Debug,\n    {\n        self.expect(\"internal error: graph consistency violated\")\n    }\n}\n\ntrait Circulator<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Self::Entity>,\n{\n    type Entity: Payload;\n\n    fn next(&mut self) -> Option<<Self::Entity as Entity>::Key>;\n}\n\ntrait ViewCirculator<'a, M>: Circulator<&'a M>\nwhere\n    M: 'a + AsStorage<Self::Entity>,\n{\n    fn target(&self) -> &'a M;\n\n    fn bind_next_view<T>(&mut self) -> Option<T>\n    where\n        T: From<View<&'a M, Self::Entity>>,\n    {\n        self.next()\n            .and_then(|key| View::bind(self.target(), key).map(T::from))\n    }\n}\n\ntrait OrphanCirculator<'a, M>: Circulator<&'a mut M>\nwhere\n    M: 'a + AsStorageMut<Self::Entity>,\n{\n    fn target(&mut self) -> &mut M;\n\n    /// Advances the circulator and binds the next key into an orphan view.\n    ///\n    /// # Safety\n    ///\n    /// For the lifetime of the circulator `Self`, this function **must not**\n    /// access a particular key in the target storage more than **once**. Such\n    /// an access may mutably alias, which is undefined behavior. Moreover, the\n    /// storage implementation must only expose disjoint data between distinct\n    /// keys. Put another way, distinct keys must not allow mutable access to\n    /// the same data.\n    ///\n    /// Note that the uniqueness of keys depends on the correctness of the graph\n    /// implementation, graph consistency, and the implementation of\n    /// [`Circulator::next`]. For example, assuming that the graph\n    /// implementation is correct, this function is safe if the `next`\n    /// implementation uses [`TraceAny`] to detect and reject keys previously\n    /// seen over the lifetime of the circulator.\n    ///\n    /// [`Circulator::next`]: crate::graph::Circulator::next\n    /// [`TraceAny`]: crate::entity::traverse::TraceAny\n    unsafe fn bind_next_orphan<T>(&mut self) -> Option<T>\n    where\n        <Self::Entity as Payload>::Data: 'a,\n        T: 'a + From<Orphan<'a, Self::Entity>>,\n    {\n        self.next().and_then(|key| {\n            let entity = self.target().as_storage_mut().get_mut(&key);\n            entity.map(|entity| {\n                let data = entity.get_mut();\n                let data = mem::transmute::<\n                    &'_ mut <Self::Entity as Payload>::Data,\n                    &'a mut <Self::Entity as Payload>::Data,\n                >(data);\n                Orphan::bind_unchecked(data, key).into()\n            })\n        })\n    }\n}\n\n/// Entity selector.\n///\n/// Identifies an entity by key or index. Keys behave as an absolute selector\n/// and uniquely identify a single entity within a [`MeshGraph`]. Indices behave\n/// as a relative selector and identify an entity relative to some other entity.\n/// `Selector` is used by operations that support both of these selection\n/// mechanisms.\n///\n/// An index is typically used to select an adjacent entity or contained (and\n/// ordered) entity, such as an adjacent face.\n///\n/// # Examples\n///\n/// Splitting a face by index (of its contained vertices):\n///\n/// ```rust\n/// # extern crate decorum;\n/// # extern crate nalgebra;\n/// # extern crate plexus;\n/// #\n/// use decorum::R64;\n/// use nalgebra::Point3;\n/// use plexus::graph::MeshGraph;\n/// use plexus::prelude::*;\n/// use plexus::primitive::cube::Cube;\n/// use plexus::primitive::generate::Position;\n///\n/// type E3 = Point3<R64>;\n///\n/// let mut graph: MeshGraph<E3> = Cube::new().polygons::<Position<E3>>().collect();\n/// let key = graph.faces().next().unwrap().key();\n/// graph\n///     .face_mut(key)\n///     .unwrap()\n///     .split(ByIndex(0), ByIndex(2))\n///     .unwrap();\n/// ```\n///\n/// [`MeshGraph`]: crate::graph::MeshGraph\n#[derive(Clone, Copy, Debug, Eq, PartialEq)]\npub enum Selector<K> {\n    ByKey(K),\n    ByIndex(usize),\n}\n\nimpl<K> Selector<K> {\n    /// Gets the selector's key or passes its index to a function to resolve\n    /// the key.\n    pub fn key_or_else<E, F>(self, f: F) -> Result<K, GraphError>\n    where\n        E: Into<GraphError>,\n        F: Fn(usize) -> Result<K, E>,\n    {\n        match self {\n            Selector::ByKey(key) => Ok(key),\n            Selector::ByIndex(index) => f(index).map_err(|error| error.into()),\n        }\n    }\n\n    /// Gets the selector's index or passes its key to a function to resolve\n    /// the index.\n    pub fn index_or_else<E, F>(self, f: F) -> Result<usize, GraphError>\n    where\n        E: Into<GraphError>,\n        F: Fn(K) -> Result<usize, E>,\n    {\n        match self {\n            Selector::ByKey(key) => f(key).map_err(|error| error.into()),\n            Selector::ByIndex(index) => Ok(index),\n        }\n    }\n}\n\nimpl<K> From<K> for Selector<K>\nwhere\n    K: Key,\n{\n    fn from(key: K) -> Self {\n        Selector::ByKey(key)\n    }\n}\n\nimpl<K> From<usize> for Selector<K> {\n    fn from(index: usize) -> Self {\n        Selector::ByIndex(index)\n    }\n}\n\n#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]\npub enum GraphKey {\n    Vertex(VertexKey),\n    Arc(ArcKey),\n    Edge(EdgeKey),\n    Face(FaceKey),\n}\n\nimpl From<VertexKey> for GraphKey {\n    fn from(key: VertexKey) -> Self {\n        GraphKey::Vertex(key)\n    }\n}\n\nimpl From<ArcKey> for GraphKey {\n    fn from(key: ArcKey) -> Self {\n        GraphKey::Arc(key)\n    }\n}\n\nimpl From<EdgeKey> for GraphKey {\n    fn from(key: EdgeKey) -> Self {\n        GraphKey::Edge(key)\n    }\n}\n\nimpl From<FaceKey> for GraphKey {\n    fn from(key: FaceKey) -> Self {\n        GraphKey::Face(key)\n    }\n}\n\n/// [Half-edge graph][dcel] representation of a polygonal mesh.\n///\n/// `MeshGraph`s form a polygonal mesh from four interconnected entities:\n/// vertices, arcs, edges, and faces. These entities are exposed by view and\n/// orphan types as well as types that represent rings and paths in a graph.\n/// Entities can be associated with arbitrary data, including no data at all.\n/// See the [`GraphData`] trait.\n///\n/// This flexible representation supports fast traversals and searches and can\n/// be used to manipulate both the data and topology of a mesh.\n///\n/// See the [`graph`] module documentation and [user guide][guide-graphs] for\n/// more details.\n///\n/// [dcel]: https://en.wikipedia.org/wiki/doubly_connected_edge_list\n/// [guide-graphs]: https://plexus.rs/user-guide/graphs\n///\n/// [`GraphData`]: crate::graph::GraphData\n/// [`graph`]: crate::graph\npub struct MeshGraph<G = (R64, R64, R64)>\nwhere\n    G: GraphData,\n{\n    core: OwnedCore<G>,\n}\n\nimpl<G> MeshGraph<G>\nwhere\n    G: GraphData,\n{\n    /// Creates an empty `MeshGraph`.\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// use plexus::graph::MeshGraph;\n    ///\n    /// let mut graph = MeshGraph::<()>::new();\n    /// ```\n    pub fn new() -> Self {\n        MeshGraph::from(Core::default())\n    }\n\n    /// Gets the number of vertices in the graph.\n    pub fn vertex_count(&self) -> usize {\n        self.core.vertices.len()\n    }\n\n    /// Gets an immutable view of the vertex with the given key.\n    pub fn vertex(&self, key: VertexKey) -> Option<VertexView<&Self>> {\n        Bind::bind(self, key)\n    }\n\n    /// Gets a mutable view of the vertex with the given key.\n    pub fn vertex_mut(&mut self, key: VertexKey) -> Option<VertexView<&mut Self>> {\n        Bind::bind(self, key)\n    }\n\n    // TODO: Return `Clone + Iterator`.\n    /// Gets an iterator of immutable views over the vertices in the graph.\n    pub fn vertices(&self) -> impl Iterator<Item = VertexView<&Self>> {\n        self.core\n            .vertices\n            .iter()\n            .map(|(key, _)| key)\n            .map(move |key| View::bind_unchecked(self, key))\n            .map(From::from)\n    }\n\n    /// Gets an iterator of orphan views over the vertices in the graph.\n    pub fn vertex_orphans(&mut self) -> impl Iterator<Item = VertexOrphan<G>> {\n        self.core\n            .vertices\n            .iter_mut()\n            .map(|(key, data)| Orphan::bind_unchecked(data, key))\n            .map(From::from)\n    }\n\n    /// Gets the number of arcs in the graph.\n    pub fn arc_count(&self) -> usize {\n        self.core.arcs.len()\n    }\n\n    /// Gets an immutable view of the arc with the given key.\n    pub fn arc(&self, key: ArcKey) -> Option<ArcView<&Self>> {\n        Bind::bind(self, key)\n    }\n\n    /// Gets a mutable view of the arc with the given key.\n    pub fn arc_mut(&mut self, key: ArcKey) -> Option<ArcView<&mut Self>> {\n        Bind::bind(self, key)\n    }\n\n    // TODO: Return `Clone + Iterator`.\n    /// Gets an iterator of immutable views over the arcs in the graph.\n    pub fn arcs(&self) -> impl Iterator<Item = ArcView<&Self>> {\n        self.core\n            .arcs\n            .iter()\n            .map(|(key, _)| key)\n            .map(move |key| View::bind_unchecked(self, key))\n            .map(From::from)\n    }\n\n    /// Gets an iterator of orphan views over the arcs in the graph.\n    pub fn arc_orphans(&mut self) -> impl Iterator<Item = ArcOrphan<G>> {\n        self.core\n            .arcs\n            .iter_mut()\n            .map(|(key, data)| Orphan::bind_unchecked(data, key))\n            .map(From::from)\n    }\n\n    /// Gets the number of edges in the graph.\n    pub fn edge_count(&self) -> usize {\n        self.core.edges.len()\n    }\n\n    /// Gets an immutable view of the edge with the given key.\n    pub fn edge(&self, key: EdgeKey) -> Option<EdgeView<&Self>> {\n        Bind::bind(self, key)\n    }\n\n    /// Gets a mutable view of the edge with the given key.\n    pub fn edge_mut(&mut self, key: EdgeKey) -> Option<EdgeView<&mut Self>> {\n        Bind::bind(self, key)\n    }\n\n    // TODO: Return `Clone + Iterator`.\n    /// Gets an iterator of immutable views over the edges in the graph.\n    pub fn edges(&self) -> impl Iterator<Item = EdgeView<&Self>> {\n        self.core\n            .edges\n            .iter()\n            .map(|(key, _)| key)\n            .map(move |key| View::bind_unchecked(self, key))\n            .map(From::from)\n    }\n\n    /// Gets an iterator of orphan views over the edges in the graph.\n    pub fn edge_orphans(&mut self) -> impl Iterator<Item = EdgeOrphan<G>> {\n        self.core\n            .edges\n            .iter_mut()\n            .map(|(key, data)| Orphan::bind_unchecked(data, key))\n            .map(From::from)\n    }\n\n    /// Gets the number of faces in the graph.\n    pub fn face_count(&self) -> usize {\n        self.core.faces.len()\n    }\n\n    /// Gets an immutable view of the face with the given key.\n    pub fn face(&self, key: FaceKey) -> Option<FaceView<&Self>> {\n        Bind::bind(self, key)\n    }\n\n    /// Gets a mutable view of the face with the given key.\n    pub fn face_mut(&mut self, key: FaceKey) -> Option<FaceView<&mut Self>> {\n        Bind::bind(self, key)\n    }\n\n    // TODO: Return `Clone + Iterator`.\n    /// Gets an iterator of immutable views over the faces in the graph.\n    pub fn faces(&self) -> impl Iterator<Item = FaceView<&Self>> {\n        self.core\n            .faces\n            .iter()\n            .map(|(key, _)| key)\n            .map(move |key| View::bind_unchecked(self, key))\n            .map(From::from)\n    }\n\n    /// Gets an iterator of orphan views over the faces in the graph.\n    pub fn face_orphans(&mut self) -> impl Iterator<Item = FaceOrphan<G>> {\n        self.core\n            .faces\n            .iter_mut()\n            .map(|(key, data)| Orphan::bind_unchecked(data, key))\n            .map(From::from)\n    }\n\n    /// Gets an immutable path over the given sequence of vertex keys.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if a vertex is not found or the path is malformed.\n    pub fn path<I>(&self, keys: I) -> Result<Path<'static, &Self>, GraphError>\n    where\n        I: IntoIterator,\n        I::Item: Borrow<VertexKey>,\n    {\n        Path::bind(self, keys)\n    }\n\n    /// Gets a mutable path over the given sequence of vertex keys.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if a vertex is not found or the path is malformed.\n    pub fn path_mut<I>(&mut self, keys: I) -> Result<Path<'static, &mut Self>, GraphError>\n    where\n        I: IntoIterator,\n        I::Item: Borrow<VertexKey>,\n    {\n        Path::bind(self, keys)\n    }\n\n    /// Gets an axis-aligned bounding box that encloses the graph.\n    pub fn aabb(&self) -> Aabb<VertexPosition<G>>\n    where\n        G::Vertex: AsPosition,\n        VertexPosition<G>: EuclideanSpace,\n        Scalar<VertexPosition<G>>: EmptyOrd,\n    {\n        Aabb::from_points(self.vertices().map(|vertex| *vertex.position()))\n    }\n\n    // TODO: This triangulation does not consider geometry and exhibits some\n    //       bad behavior in certain situations. Triangulation needs to be\n    //       reworked and may need to expose a bit more complexity. A geometric\n    //       triangulation algorithm would be a useful addition and could\n    //       detect concave faces and provide more optimal splits. See comments\n    //       on `FaceView::triangulate`.\n    /// Triangulates the graph, tessellating all faces into triangles.\n    pub fn triangulate(&mut self) {\n        // TODO: This implementation is a bit fragile and depends on the\n        //       semantics of `TopologyConflict` in this context. It also panics\n        //       if no valid split is found given all offsets or if some other\n        //       error is encountered while splitting. Can this code assume that\n        //       any of these conditions aren't possible? This should work a bit\n        //       better than using `FaceView::triangulate` until triangulation\n        //       is reworked.\n        let keys = self\n            .core\n            .faces\n            .iter()\n            .map(|(key, _)| key)\n            .collect::<Vec<_>>();\n        for key in keys {\n            let mut face = self.face_mut(key).unwrap();\n            let mut offset = 0;\n            while face.arity() > 3 {\n                match face.split(ByIndex(offset), ByIndex(offset + 2)) {\n                    Ok(next) => {\n                        face = next.into_face().expect_consistent();\n                        offset = 0;\n                    }\n                    Err(GraphError::TopologyConflict) => {\n                        // Retry if the split intersected another face. See\n                        // `FaceSplitCache::from_face`.\n                        face = self.face_mut(key).unwrap();\n                        offset += 1;\n                        if offset >= face.arity() {\n                            panic!()\n                        }\n                    }\n                    _ => panic!(),\n                }\n            }\n        }\n    }\n\n    /// Smooths the positions of vertices in the graph.\n    ///\n    /// Each position is translated by its offset from its centroid scaled by\n    /// the given factor. The centroid of a vertex position is the mean of the\n    /// positions of its adjacent vertices. That is, given a factor $k$ and a\n    /// vertex with position $P$ and centroid $Q$, its position becomes\n    /// $P+k(Q-P)$.\n    pub fn smooth<T>(&mut self, factor: T)\n    where\n        T: Into<Scalar<VertexPosition<G>>>,\n        G: VertexCentroid,\n        G::Vertex: AsPositionMut,\n        VertexPosition<G>: EuclideanSpace,\n    {\n        let factor = factor.into();\n        let mut positions = HashMap::with_capacity(self.vertex_count());\n        for vertex in self.vertices() {\n            let position = *vertex.position();\n            positions.insert(\n                vertex.key(),\n                position + ((vertex.centroid() - position) * factor),\n            );\n        }\n        for mut vertex in self.vertex_orphans() {\n            *vertex.get_mut().as_position_mut() = positions.remove(&vertex.key()).unwrap();\n        }\n    }\n\n    /// Splits the graph along a path.\n    ///\n    /// Splitting a graph creates boundaries along the given path and copies any\n    /// necessary vertex, arc, and edge data.\n    ///\n    /// If the path bisects the graph, then splitting will result in disjointed\n    /// sub-graphs.\n    ///\n    /// # Examples\n    ///\n    /// ```rust,no_run\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use nalgebra::Point2;\n    /// use plexus::graph::MeshGraph;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::Trigon;\n    ///\n    /// type E2 = Point2<f64>;\n    ///\n    /// // Create a graph from two triangles.\n    /// let mut graph = MeshGraph::<E2>::from_raw_buffers(\n    ///     vec![Trigon::new(0usize, 1, 2), Trigon::new(2, 1, 3)],\n    ///     vec![(-1.0, 0.0), (0.0, -1.0), (0.0, 1.0), (1.0, 0.0)],\n    /// )\n    /// .unwrap();\n    ///\n    /// // Find the shared edge that bisects the triangles and then construct a path\n    /// // along the edge and split the graph.\n    /// let key = graph\n    ///     .edges()\n    ///     .find(|edge| !edge.is_boundary_edge())\n    ///     .map(|edge| edge.into_arc().key())\n    ///     .unwrap();\n    /// let mut path = graph.arc_mut(key).unwrap().into_path();\n    /// MeshGraph::split_at_path(path).unwrap();\n    /// ```\n    pub fn split_at_path(path: Path<&mut Self>) -> Result<(), GraphError> {\n        let _ = path;\n        unimplemented!()\n    }\n\n    /// Gets an iterator over a vertex within each disjoint sub-graph.\n    ///\n    /// Traverses the graph and returns an arbitrary vertex within each\n    /// _disjoint sub-graph_. A sub-graph is _disjoint_ if it cannot be reached\n    /// from all other topology in the graph.\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use nalgebra::Point2;\n    /// use plexus::graph::MeshGraph;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::Trigon;\n    ///\n    /// type E2 = Point2<f64>;\n    ///\n    /// // Create a graph from two disjoint triangles.\n    /// let graph = MeshGraph::<E2>::from_raw_buffers(\n    ///     vec![Trigon::new(0u32, 1, 2), Trigon::new(3, 4, 5)],\n    ///     vec![\n    ///         (-2.0, 0.0),\n    ///         (-1.0, 0.0),\n    ///         (-1.0, 1.0),\n    ///         (1.0, 0.0),\n    ///         (2.0, 0.0),\n    ///         (1.0, 1.0),\n    ///     ],\n    /// )\n    /// .unwrap();\n    ///\n    /// // A vertex from each disjoint triangle is returned.\n    /// for vertex in graph.disjoint_subgraph_vertices() {\n    ///     // ...\n    /// }\n    /// ```\n    pub fn disjoint_subgraph_vertices(&self) -> impl ExactSizeIterator<Item = VertexView<&Self>> {\n        let keys = self\n            .core\n            .vertices\n            .iter()\n            .map(|(key, _)| key)\n            .collect::<HashSet<_>>();\n        let mut subkeys = HashSet::with_capacity(self.vertex_count());\n        let mut vertices = SmallVec::<[VertexView<_>; 4]>::new();\n        while let Some(key) = keys.difference(&subkeys).next() {\n            let vertex = VertexView::from(View::bind_unchecked(self, *key));\n            vertices.push(vertex);\n            subkeys.extend(vertex.traverse_by_depth().map(|vertex| vertex.key()));\n        }\n        vertices.into_iter()\n    }\n\n    /// Moves disjoint sub-graphs into separate graphs.\n    pub fn into_disjoint_subgraphs(self) -> Vec<Self> {\n        unimplemented!()\n    }\n\n    /// Shrinks the capacity of the graph's underlying storage as much as\n    /// possible.\n    pub fn shrink_to_fit(&mut self) {\n        self.core.vertices.shrink_to_fit();\n        self.core.arcs.shrink_to_fit();\n        self.core.edges.shrink_to_fit();\n        self.core.faces.shrink_to_fit();\n    }\n\n    /// Creates a [`Buildable`] mesh data structure from the graph.\n    ///\n    /// The output is created from each unique vertex in the graph. No face data\n    /// is used, and the `Facet` type is always the unit type `()`.\n    ///\n    /// # Examples\n    ///\n    /// Creating a [`MeshBuffer`] from a [`MeshGraph`] used to modify a cube:\n    ///\n    /// ```rust\n    /// # extern crate decorum;\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use decorum::Total;\n    /// use nalgebra::Point3;\n    /// use plexus::buffer::MeshBufferN;\n    /// use plexus::graph::MeshGraph;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::cube::Cube;\n    /// use plexus::primitive::generate::Position;\n    ///\n    /// type E3 = Point3<Total<f32>>;\n    ///\n    /// let mut graph: MeshGraph<E3> = Cube::new().polygons::<Position<E3>>().collect();\n    /// let key = graph.faces().next().unwrap().key();\n    /// graph\n    ///     .face_mut(key)\n    ///     .unwrap()\n    ///     .extrude_with_offset(1.0)\n    ///     .unwrap();\n    ///\n    /// let buffer: MeshBufferN<usize, E3> = graph.to_mesh_by_vertex().unwrap();\n    /// ```\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the graph does not have constant arity that is\n    /// compatible with the index buffer. Typically, a graph is triangulated\n    /// before being converted to a buffer.\n    ///\n    /// [`MeshBuffer`]: crate::buffer::MeshBuffer\n    /// [`Buildable`]: crate::builder::Buildable\n    /// [`MeshGraph`]: crate::graph::MeshGraph\n    pub fn to_mesh_by_vertex<B>(&self) -> Result<B, B::Error>\n    where\n        B: Buildable<Facet = ()>,\n        B::Vertex: FromGeometry<G::Vertex>,\n    {\n        self.to_mesh_by_vertex_with(|vertex| vertex.get().clone().into_geometry())\n    }\n\n    /// Creates a [`Buildable`] mesh data structure from the graph.\n    ///\n    /// The output is created from each unique vertex in the graph, which is\n    /// converted by the given function. No face data is used, and the `Facet`\n    /// type is always the unit type `()`.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the vertex data cannot be inserted into the output,\n    /// there are arity conflicts, or the output does not support topology found\n    /// in the graph.\n    ///\n    /// [`Buildable`]: crate::builder::Buildable\n    pub fn to_mesh_by_vertex_with<B, F>(&self, mut f: F) -> Result<B, B::Error>\n    where\n        B: Buildable<Facet = ()>,\n        F: FnMut(VertexView<&Self>) -> B::Vertex,\n    {\n        let mut builder = B::builder();\n        builder.surface_with(|builder| {\n            let mut keys = HashMap::with_capacity(self.vertex_count());\n            for vertex in self.vertices() {\n                keys.insert(vertex.key(), builder.insert_vertex(f(vertex))?);\n            }\n            builder.facets_with(|builder| {\n                for face in self.faces() {\n                    let indices = face\n                        .adjacent_vertices()\n                        .map(|vertex| keys[&vertex.key()])\n                        .collect::<SmallVec<[_; 8]>>();\n                    builder.insert_facet(indices.as_slice(), ())?;\n                }\n                Ok(())\n            })\n        })?;\n        builder.build()\n    }\n\n    /// Creates a [`Buildable`] mesh data structure from the graph.\n    ///\n    /// The output is created from each face in the graph. For each face, the\n    /// face data and data for each of its vertices is inserted into the mesh\n    /// via [`FromGeometry`]. This means that a vertex is inserted for each of\n    /// its adjacent faces.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the vertex data cannot be inserted into the output,\n    /// there are arity conflicts, or the output does not support topology found\n    /// in the graph.\n    ///\n    /// [`Buildable`]: crate::builder::Buildable\n    /// [`FromGeometry`]: crate::geometry::FromGeometry\n    pub fn to_mesh_by_face<B>(&self) -> Result<B, B::Error>\n    where\n        B: Buildable,\n        B::Vertex: FromGeometry<G::Vertex>,\n        B::Facet: FromGeometry<G::Face>,\n    {\n        self.to_mesh_by_face_with(|_, vertex| vertex.get().clone().into_geometry())\n    }\n\n    /// Creates a [`Buildable`] mesh data structure from the graph.\n    ///\n    /// The output is created from each face in the graph. For each face, the\n    /// face data and data for each of its vertices is converted into the output\n    /// vertex data by the given function. This means that a vertex is inserted\n    /// for each of its adjacent faces. The data of each face is is inserted\n    /// into the output via [`FromGeometry`].\n    ///\n    /// # Examples\n    ///\n    /// Creating a [`MeshBuffer`] from a [`MeshGraph`] used to compute normals:\n    ///\n    /// ```rust\n    /// # extern crate decorum;\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use decorum::R64;\n    /// use nalgebra::Point3;\n    /// use plexus::buffer::MeshBuffer;\n    /// use plexus::geometry::Vector;\n    /// use plexus::graph::MeshGraph;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::cube::Cube;\n    /// use plexus::primitive::generate::Position;\n    /// use plexus::primitive::BoundedPolygon;\n    ///\n    /// type E3 = Point3<R64>;\n    ///\n    /// pub struct Vertex {\n    ///     pub position: E3,\n    ///     pub normal: Vector<E3>,\n    /// }\n    ///\n    /// let graph: MeshGraph<E3> = Cube::new().polygons::<Position<E3>>().collect();\n    ///\n    /// let buffer: MeshBuffer<BoundedPolygon<usize>, _> = graph\n    ///     .to_mesh_by_face_with(|face, vertex| Vertex {\n    ///         position: *vertex.position(),\n    ///         normal: face.normal().unwrap(),\n    ///     })\n    ///     .unwrap();\n    /// ```\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the vertex data cannot be inserted into the output,\n    /// there are arity conflicts, or the output does not support topology found\n    /// in the graph.\n    ///\n    /// [`MeshBuffer`]: crate::buffer::MeshBuffer\n    /// [`Buildable`]: crate::builder::Buildable\n    /// [`FromGeometry`]: crate::geometry::FromGeometry\n    /// [`MeshGraph`]: crate::graph::MeshGraph\n    pub fn to_mesh_by_face_with<B, F>(&self, mut f: F) -> Result<B, B::Error>\n    where\n        B: Buildable,\n        B::Facet: FromGeometry<G::Face>,\n        F: FnMut(FaceView<&Self>, VertexView<&Self>) -> B::Vertex,\n    {\n        let mut builder = B::builder();\n        builder.surface_with(|builder| {\n            for face in self.faces() {\n                let indices = face\n                    .adjacent_vertices()\n                    .map(|vertex| builder.insert_vertex(f(face, vertex)))\n                    .collect::<Result<SmallVec<[_; 8]>, _>>()?;\n                builder.facets_with(|builder| {\n                    builder.insert_facet(indices.as_slice(), face.get().clone())\n                })?;\n            }\n            Ok(())\n        })?;\n        builder.build()\n    }\n}\n\nimpl<G> AsStorage<Vertex<G>> for MeshGraph<G>\nwhere\n    G: GraphData,\n{\n    fn as_storage(&self) -> &StorageTarget<Vertex<G>> {\n        self.core.as_storage_of::<Vertex<_>>()\n    }\n}\n\nimpl<G> AsStorage<Arc<G>> for MeshGraph<G>\nwhere\n    G: GraphData,\n{\n    fn as_storage(&self) -> &StorageTarget<Arc<G>> {\n        self.core.as_storage_of::<Arc<_>>()\n    }\n}\n\nimpl<G> AsStorage<Edge<G>> for MeshGraph<G>\nwhere\n    G: GraphData,\n{\n    fn as_storage(&self) -> &StorageTarget<Edge<G>> {\n        self.core.as_storage_of::<Edge<_>>()\n    }\n}\n\nimpl<G> AsStorage<Face<G>> for MeshGraph<G>\nwhere\n    G: GraphData,\n{\n    fn as_storage(&self) -> &StorageTarget<Face<G>> {\n        self.core.as_storage_of::<Face<_>>()\n    }\n}\n\nimpl<G> AsStorageMut<Vertex<G>> for MeshGraph<G>\nwhere\n    G: GraphData,\n{\n    fn as_storage_mut(&mut self) -> &mut StorageTarget<Vertex<G>> {\n        self.core.as_storage_mut_of::<Vertex<_>>()\n    }\n}\n\nimpl<G> AsStorageMut<Arc<G>> for MeshGraph<G>\nwhere\n    G: GraphData,\n{\n    fn as_storage_mut(&mut self) -> &mut StorageTarget<Arc<G>> {\n        self.core.as_storage_mut_of::<Arc<_>>()\n    }\n}\n\nimpl<G> AsStorageMut<Edge<G>> for MeshGraph<G>\nwhere\n    G: GraphData,\n{\n    fn as_storage_mut(&mut self) -> &mut StorageTarget<Edge<G>> {\n        self.core.as_storage_mut_of::<Edge<_>>()\n    }\n}\n\nimpl<G> AsStorageMut<Face<G>> for MeshGraph<G>\nwhere\n    G: GraphData,\n{\n    fn as_storage_mut(&mut self) -> &mut StorageTarget<Face<G>> {\n        self.core.as_storage_mut_of::<Face<_>>()\n    }\n}\n\n/// Exposes a [`MeshBuilder`] that can be used to construct a [`MeshGraph`]\n/// incrementally from _surfaces_ and _facets_.\n///\n/// See the [`builder`] module documentation for more.\n///\n/// # Examples\n///\n/// Creating a [`MeshGraph`] from a triangle:\n///\n/// ```rust\n/// # extern crate nalgebra;\n/// # extern crate plexus;\n/// #\n/// use nalgebra::Point2;\n/// use plexus::builder::Buildable;\n/// use plexus::graph::MeshGraph;\n/// use plexus::prelude::*;\n///\n/// let mut builder = MeshGraph::<Point2<f64>>::builder();\n/// let graph = builder\n///     .surface_with(|builder| {\n///         let a = builder.insert_vertex((0.0, 0.0))?;\n///         let b = builder.insert_vertex((1.0, 0.0))?;\n///         let c = builder.insert_vertex((0.0, 1.0))?;\n///         builder.facets_with(|builder| builder.insert_facet(&[a, b, c], ()))\n///     })\n///     .and_then(|_| builder.build())\n///     .unwrap();\n/// ```\n///\n/// [`MeshBuilder`]: crate::builder::MeshBuilder\n/// [`builder`]: crate::builder\n/// [`MeshGraph`]: crate::graph::MeshGraph\nimpl<G> Buildable for MeshGraph<G>\nwhere\n    G: GraphData,\n{\n    type Builder = GraphBuilder<G>;\n    type Error = GraphError;\n\n    type Vertex = G::Vertex;\n    type Facet = G::Face;\n\n    fn builder() -> Self::Builder {\n        Default::default()\n    }\n}\n\nimpl<G> Consistent for MeshGraph<G> where G: GraphData {}\n\nimpl<G> Default for MeshGraph<G>\nwhere\n    G: GraphData,\n{\n    fn default() -> Self {\n        MeshGraph::new()\n    }\n}\n\nimpl<G> DynamicArity for MeshGraph<G>\nwhere\n    G: GraphData,\n{\n    type Dynamic = MeshArity;\n\n    fn arity(&self) -> Self::Dynamic {\n        MeshArity::from_components::<FaceView<_>, _>(self.faces())\n    }\n}\n\nimpl<P, G> From<P> for MeshGraph<G>\nwhere\n    P: Polygonal,\n    G: GraphData,\n    G::Vertex: FromGeometry<P::Vertex>,\n{\n    fn from(polygon: P) -> Self {\n        let arity = polygon.arity();\n        MeshGraph::from_raw_buffers_with_arity(0..arity, polygon, arity)\n            .expect(\"inconsistent polygon\")\n    }\n}\n\nimpl<G> From<OwnedCore<G>> for MeshGraph<G>\nwhere\n    G: GraphData,\n{\n    fn from(core: OwnedCore<G>) -> Self {\n        MeshGraph { core }\n    }\n}\n\nimpl<G> From<MeshGraph<G>> for OwnedCore<G>\nwhere\n    G: GraphData,\n{\n    fn from(graph: MeshGraph<G>) -> Self {\n        let MeshGraph { core, .. } = graph;\n        core\n    }\n}\n\nimpl<E, G> FromEncoding<E> for MeshGraph<G>\nwhere\n    E: FaceDecoder + VertexDecoder,\n    G: GraphData,\n    G::Face: FromGeometry<E::Face>,\n    G::Vertex: FromGeometry<E::Vertex>,\n{\n    type Error = GraphError;\n\n    fn from_encoding(\n        vertices: <E as VertexDecoder>::Output,\n        faces: <E as FaceDecoder>::Output,\n    ) -> Result<Self, Self::Error> {\n        let mut mutation = Mutation::from(MeshGraph::new());\n        let keys = vertices\n            .into_iter()\n            .map(|data| mutation::vertex::insert(&mut mutation, data.into_geometry()))\n            .collect::<Vec<_>>();\n        for (perimeter, data) in faces {\n            let perimeter = perimeter\n                .into_iter()\n                .map(|index| keys[index])\n                .collect::<SmallVec<[_; 4]>>();\n            let cache = FaceInsertCache::from_storage(&mutation, perimeter.as_slice())?;\n            let data = data.into_geometry();\n            mutation::face::insert_with(&mut mutation, cache, || (Default::default(), data))?;\n        }\n        mutation.commit().map_err(|(_, error)| error)\n    }\n}\n\nimpl<G, P> FromIndexer<P, P> for MeshGraph<G>\nwhere\n    G: GraphData,\n    G::Vertex: FromGeometry<P::Vertex>,\n    P: Map<usize> + Polygonal,\n    P::Output: Grouping<Group = P::Output> + IntoVertices + Polygonal<Vertex = usize>,\n    Vec<P::Output>: IndexBuffer<P::Output, Index = usize>,\n{\n    type Error = GraphError;\n\n    fn from_indexer<I, N>(input: I, indexer: N) -> Result<Self, Self::Error>\n    where\n        I: IntoIterator<Item = P>,\n        N: Indexer<P, P::Vertex>,\n    {\n        let mut mutation = Mutation::from(MeshGraph::new());\n        let (indices, vertices) = input.into_iter().index_vertices(indexer);\n        let vertices = vertices\n            .into_iter()\n            .map(|vertex| mutation::vertex::insert(&mut mutation, vertex.into_geometry()))\n            .collect::<Vec<_>>();\n        for face in indices {\n            let perimeter = face\n                .into_vertices()\n                .into_iter()\n                .map(|index| vertices[index])\n                .collect::<SmallVec<[_; 4]>>();\n            let cache = FaceInsertCache::from_storage(&mutation, &perimeter)?;\n            mutation::face::insert_with(&mut mutation, cache, Default::default)?;\n        }\n        mutation.commit().map_err(|(_, error)| error)\n    }\n}\n\nimpl<G, P> FromIterator<P> for MeshGraph<G>\nwhere\n    G: GraphData,\n    G::Vertex: FromGeometry<P::Vertex>,\n    P: Polygonal,\n    P::Vertex: Clone + Eq + Hash,\n    Self: FromIndexer<P, P>,\n{\n    fn from_iter<I>(input: I) -> Self\n    where\n        I: IntoIterator<Item = P>,\n    {\n        Self::from_indexer(input, HashIndexer::default()).unwrap_or_else(|_| Self::default())\n    }\n}\n\nimpl<P, G, H> FromRawBuffers<P, H> for MeshGraph<G>\nwhere\n    P: IntoVertices + Polygonal,\n    P::Vertex: Integer + ToPrimitive + Unsigned,\n    G: GraphData,\n    G::Vertex: FromGeometry<H>,\n{\n    type Error = GraphError;\n\n    fn from_raw_buffers<I, J>(indices: I, vertices: J) -> Result<Self, Self::Error>\n    where\n        I: IntoIterator<Item = P>,\n        J: IntoIterator<Item = H>,\n    {\n        let mut mutation = Mutation::from(MeshGraph::new());\n        let vertices = vertices\n            .into_iter()\n            .map(|vertex| mutation::vertex::insert(&mut mutation, vertex.into_geometry()))\n            .collect::<Vec<_>>();\n        for face in indices {\n            let mut perimeter = SmallVec::<[_; 4]>::with_capacity(face.arity());\n            for index in face.into_vertices() {\n                let index = <usize as NumCast>::from(index).unwrap();\n                perimeter.push(*vertices.get(index).ok_or(GraphError::TopologyNotFound)?);\n            }\n            let cache = FaceInsertCache::from_storage(&mutation, &perimeter)?;\n            mutation::face::insert_with(&mut mutation, cache, Default::default)?;\n        }\n        mutation.commit().map_err(|(_, error)| error)\n    }\n}\n\nimpl<N, G, H> FromRawBuffersWithArity<N, H> for MeshGraph<G>\nwhere\n    N: Integer + ToPrimitive + Unsigned,\n    G: GraphData,\n    G::Vertex: FromGeometry<H>,\n{\n    type Error = GraphError;\n\n    /// Creates a [`MeshGraph`] from [raw buffers][`buffer`]. The arity of the\n    /// polygons in the index buffer must be given and constant.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the arity of the index buffer is not constant, any\n    /// index is out of bounds, or there is an error inserting topology into the\n    /// graph.\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use nalgebra::Point3;\n    /// use plexus::graph::MeshGraph;\n    /// use plexus::index::{Flat3, LruIndexer};\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::generate::Position;\n    /// use plexus::primitive::sphere::UvSphere;\n    ///\n    /// type E3 = Point3<f64>;\n    ///\n    /// let (indices, positions) = UvSphere::new(16, 16)\n    ///     .polygons::<Position<E3>>()\n    ///     .triangulate()\n    ///     .index_vertices::<Flat3, _>(LruIndexer::with_capacity(256));\n    /// let mut graph = MeshGraph::<E3>::from_raw_buffers_with_arity(indices, positions, 3).unwrap();\n    /// ```\n    ///\n    /// [`buffer`]: crate::buffer\n    /// [`MeshGraph`]: crate::graph::MeshGraph\n    fn from_raw_buffers_with_arity<I, J>(\n        indices: I,\n        vertices: J,\n        arity: usize,\n    ) -> Result<Self, Self::Error>\n    where\n        I: IntoIterator<Item = N>,\n        J: IntoIterator<Item = H>,\n    {\n        use itertools::Itertools;\n\n        if arity < 3 {\n            return Err(GraphError::ArityNonPolygonal);\n        }\n        let mut mutation = Mutation::from(MeshGraph::new());\n        let vertices = vertices\n            .into_iter()\n            .map(|vertex| mutation::vertex::insert(&mut mutation, vertex.into_geometry()))\n            .collect::<Vec<_>>();\n        for face in &indices\n            .into_iter()\n            .map(|index| <usize as NumCast>::from(index).unwrap())\n            .chunks(arity)\n        {\n            let face = face.collect::<Vec<_>>();\n            if face.len() != arity {\n                // Index buffer length is not a multiple of arity.\n                return Err(GraphError::ArityConflict {\n                    expected: arity,\n                    actual: face.len(),\n                });\n            }\n            let mut perimeter = SmallVec::<[_; 4]>::with_capacity(arity);\n            for index in face {\n                perimeter.push(*vertices.get(index).ok_or(GraphError::TopologyNotFound)?);\n            }\n            let cache = FaceInsertCache::from_storage(&mutation, &perimeter)?;\n            mutation::face::insert_with(&mut mutation, cache, Default::default)?;\n        }\n        mutation.commit().map_err(|(_, error)| error)\n    }\n}\n\nimpl<G> IntoPolygons for MeshGraph<G>\nwhere\n    G: GraphData,\n{\n    type Output = vec::IntoIter<Self::Polygon>;\n    type Polygon = UnboundedPolygon<G::Vertex>;\n\n    fn into_polygons(self) -> Self::Output {\n        use crate::IteratorExt as _;\n\n        self.faces()\n            .map(|face| {\n                // The arity of a face in a graph must be polygonal (three or\n                // higher) so this should never fail.\n                face.adjacent_vertices()\n                    .map(|vertex| vertex.get().clone())\n                    .try_collect()\n                    .expect_consistent()\n            })\n            .collect::<Vec<_>>()\n            .into_iter()\n    }\n}\n\nimpl<G> Parametric for MeshGraph<G>\nwhere\n    G: GraphData,\n{\n    type Data = G;\n}\n\nimpl<G> StaticArity for MeshGraph<G>\nwhere\n    G: GraphData,\n{\n    type Static = (usize, Option<usize>);\n\n    const ARITY: Self::Static = (3, None);\n}\n\nimpl<T, H, G, const A: usize> TryFrom<MeshBuffer<Flat<T, A>, H>> for MeshGraph<G>\nwhere\n    Constant<A>: ToType,\n    TypeOf<A>: NonZero,\n    T: Copy + Integer + NumCast + Unsigned,\n    H: Clone,\n    G: GraphData,\n    G::Vertex: FromGeometry<H>,\n{\n    type Error = GraphError;\n\n    /// Creates a [`MeshGraph`] from a flat [`MeshBuffer`]. The arity of the\n    /// polygons in the index buffer must be known and constant.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if a [`MeshGraph`] cannot represent the topology in the\n    /// [`MeshBuffer`].\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use nalgebra::Point2;\n    /// use plexus::buffer::MeshBuffer;\n    /// use plexus::graph::MeshGraph;\n    /// use plexus::index::Flat4;\n    /// use plexus::prelude::*;\n    /// use std::convert::TryFrom;\n    ///\n    /// type E2 = Point2<f64>;\n    ///\n    /// let buffer = MeshBuffer::<Flat4, E2>::from_raw_buffers(\n    ///     vec![0u64, 1, 2, 3],\n    ///     vec![(0.0f64, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)],\n    /// )\n    /// .unwrap();\n    /// let mut graph = MeshGraph::<E2>::try_from(buffer).unwrap();\n    /// ```\n    ///\n    /// [`MeshBuffer`]: crate::buffer::MeshBuffer\n    /// [`MeshGraph`]: crate::graph::MeshGraph\n    fn try_from(buffer: MeshBuffer<Flat<T, A>, H>) -> Result<Self, Self::Error> {\n        let arity = buffer.arity();\n        let (indices, vertices) = buffer.into_raw_buffers();\n        MeshGraph::from_raw_buffers_with_arity(indices, vertices, arity)\n    }\n}\n\nimpl<P, H, G> TryFrom<MeshBuffer<P, H>> for MeshGraph<G>\nwhere\n    P: Grouping<Group = P> + IntoVertices + Polygonal,\n    P::Vertex: Copy + Integer + NumCast + Unsigned,\n    H: Clone,\n    G: GraphData,\n    G::Vertex: FromGeometry<H>,\n{\n    type Error = GraphError;\n\n    /// Creates a [`MeshGraph`] from a structured [`MeshBuffer`].\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if a [`MeshGraph`] cannot represent the topology in the\n    /// [`MeshBuffer`].\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use nalgebra::Point2;\n    /// use plexus::buffer::MeshBuffer;\n    /// use plexus::graph::MeshGraph;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::Tetragon;\n    /// use std::convert::TryFrom;\n    ///\n    /// type E2 = Point2<f64>;\n    ///\n    /// let buffer = MeshBuffer::<Tetragon<u64>, E2>::from_raw_buffers(\n    ///     vec![Tetragon::new(0u64, 1, 2, 3)],\n    ///     vec![(0.0f64, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)],\n    /// )\n    /// .unwrap();\n    /// let mut graph = MeshGraph::<E2>::try_from(buffer).unwrap();\n    /// ```\n    ///\n    /// [`MeshBuffer`]: crate::buffer::MeshBuffer\n    /// [`MeshGraph`]: crate::graph::MeshGraph\n    fn try_from(buffer: MeshBuffer<P, H>) -> Result<Self, Self::Error> {\n        let (indices, vertices) = buffer.into_raw_buffers();\n        MeshGraph::from_raw_buffers(indices, vertices)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use decorum::R64;\n    use nalgebra::{Point2, Point3, Vector3};\n    use num::Zero;\n\n    use crate::buffer::MeshBuffer3;\n    use crate::graph::{GraphData, GraphError, MeshGraph};\n    use crate::prelude::*;\n    use crate::primitive::generate::Position;\n    use crate::primitive::sphere::UvSphere;\n    use crate::primitive::NGon;\n\n    type E2 = Point2<R64>;\n    type E3 = Point3<R64>;\n\n    #[test]\n    fn collect() {\n        let graph: MeshGraph<Point3<f64>> = UvSphere::new(3, 2)\n            .polygons::<Position<E3>>() // 6 triangles, 18 vertices.\n            .collect();\n\n        assert_eq!(5, graph.vertex_count());\n        assert_eq!(18, graph.arc_count());\n        assert_eq!(6, graph.face_count());\n    }\n\n    #[test]\n    fn iterate() {\n        let mut graph: MeshGraph<Point3<f64>> = UvSphere::new(4, 2)\n            .polygons::<Position<E3>>() // 8 triangles, 24 vertices.\n            .collect();\n\n        assert_eq!(6, graph.vertices().count());\n        assert_eq!(24, graph.arcs().count());\n        assert_eq!(8, graph.faces().count());\n        for vertex in graph.vertices() {\n            // Every vertex is connected to 4 triangles with 4 (incoming) arcs.\n            // Traversal of topology should be possible.\n            assert_eq!(4, vertex.incoming_arcs().count());\n        }\n        for mut vertex in graph.vertex_orphans() {\n            // Data should be mutable.\n            *vertex.get_mut() += Vector3::zero();\n        }\n    }\n\n    #[test]\n    fn isolate_disjoint_subgraphs() {\n        // Construct a graph from a quadrilateral.\n        let graph = MeshGraph::<E2>::from_raw_buffers(\n            vec![NGon([0u32, 1, 2, 3])],\n            vec![(1.0, 0.0), (2.0, 0.0), (2.0, 1.0), (1.0, 1.0)],\n        )\n        .unwrap();\n\n        assert_eq!(1, graph.disjoint_subgraph_vertices().count());\n\n        // Construct a graph with two disjoint quadrilaterals.\n        let graph = MeshGraph::<E2>::from_raw_buffers(\n            vec![NGon([0u32, 1, 2, 3]), NGon([4, 5, 6, 7])],\n            vec![\n                (-2.0, 0.0),\n                (-1.0, 0.0),\n                (-1.0, 1.0),\n                (-2.0, 1.0),\n                (1.0, 0.0),\n                (2.0, 0.0),\n                (2.0, 1.0),\n                (1.0, 1.0),\n            ],\n        )\n        .unwrap();\n\n        assert_eq!(2, graph.disjoint_subgraph_vertices().count());\n    }\n\n    #[test]\n    fn non_manifold_error_deferred() {\n        let graph: MeshGraph<E3> = UvSphere::new(32, 32)\n            .polygons::<Position<E3>>()\n            .triangulate()\n            .collect();\n        // This conversion will join faces by a single vertex, but ultimately\n        // creates a manifold.\n        let _: MeshBuffer3<usize, E3> = graph.to_mesh_by_face().unwrap();\n    }\n\n    #[test]\n    fn error_on_non_manifold() {\n        // Construct a graph with a \"fan\" of three triangles sharing the same\n        // edge along the Z-axis. The edge would have three associated faces,\n        // which should not be possible.\n        let graph = MeshGraph::<Point3<i32>>::from_raw_buffers(\n            vec![NGon([0u32, 1, 2]), NGon([0, 1, 3]), NGon([0, 1, 4])],\n            vec![(0, 0, 1), (0, 0, -1), (1, 0, 0), (0, 1, 0), (1, 1, 0)],\n        );\n\n        assert_eq!(graph.err().unwrap(), GraphError::TopologyConflict);\n    }\n\n    // This test is a sanity check for circulators over orphan views and the\n    // unsafe transmutations used to coerce lifetimes. It is a good target for\n    // Miri, which can detect certain memory safety issues.\n    #[test]\n    fn read_write_mutable_circulator() {\n        const WEIGHT: u64 = 123_456_789;\n\n        enum FaceWeight {}\n\n        impl GraphData for FaceWeight {\n            type Vertex = [i32; 2];\n            type Arc = ();\n            type Edge = ();\n            type Face = u64;\n        }\n\n        // Construct a graph resembling the following diagram.\n        //\n        //   0---1---2\n        //   |\\ B|C /|\n        //   | \\ | / |\n        //   |A \\|/ D|\n        //   3---4---5\n        //   |E /|\\ H|\n        //   | / | \\ |\n        //   |/ F|G \\|\n        //   6---7---8\n        let mut graph = MeshGraph::<FaceWeight>::from_raw_buffers(\n            [\n                NGon([0usize, 3, 4]),\n                NGon([4, 1, 0]),\n                NGon([1, 4, 2]),\n                NGon([2, 4, 5]),\n                NGon([4, 3, 6]),\n                NGon([6, 7, 4]),\n                NGon([4, 7, 8]),\n                NGon([8, 5, 4]),\n            ],\n            [\n                [0i32, 0],\n                [1, 0],\n                [2, 0],\n                [0, 1],\n                [1, 1],\n                [2, 1],\n                [0, 2],\n                [1, 2],\n                [2, 2],\n            ],\n        )\n        .unwrap();\n        // Get the center vertex (4).\n        let mut vertex = {\n            let key = graph\n                .vertices()\n                .find(|vertex| vertex.valence() == 8)\n                .map(|vertex| vertex.key())\n                .unwrap();\n            graph.vertex_mut(key).unwrap()\n        };\n        // Write and then read each face via circulators.\n        for mut face in vertex.adjacent_face_orphans() {\n            *face.get_mut() = WEIGHT;\n        }\n        for face in vertex.adjacent_faces() {\n            assert_eq!(WEIGHT, *face.get());\n        }\n    }\n}\n"
  },
  {
    "path": "plexus/src/graph/mutation/edge.rs",
    "content": "use std::ops::{Deref, DerefMut};\n\nuse crate::entity::borrow::Reborrow;\nuse crate::entity::storage::prelude::*;\nuse crate::entity::storage::{AsStorage, AsStorageMut, Fuse, StorageTarget};\nuse crate::entity::view::{Bind, ClosedView, Rebind};\nuse crate::graph::core::Core;\nuse crate::graph::data::{Data, GraphData, Parametric};\nuse crate::graph::edge::{Arc, ArcKey, ArcView, Edge, EdgeKey};\nuse crate::graph::face::{Face, FaceKey};\nuse crate::graph::mutation::face::{self, FaceInsertCache, FaceRemoveCache};\nuse crate::graph::mutation::vertex::{self, VertexMutation};\nuse crate::graph::mutation::{Consistent, Immediate, Mode, Mutable, Mutation};\nuse crate::graph::vertex::{Vertex, VertexKey, VertexView};\nuse crate::graph::GraphError;\nuse crate::transact::{Bypass, Transact};\nuse crate::IteratorExt as _;\n\npub type CompositeEdge<G> = (Edge<G>, (Arc<G>, Arc<G>));\npub type CompositeEdgeData<G> = (\n    <G as GraphData>::Edge,\n    (<G as GraphData>::Arc, <G as GraphData>::Arc),\n);\npub type CompositeEdgeKey = (EdgeKey, (ArcKey, ArcKey));\n\ntype ModalCore<P> = Core<\n    Data<<P as Mode>::Graph>,\n    <P as Mode>::VertexStorage,\n    <P as Mode>::ArcStorage,\n    <P as Mode>::EdgeStorage,\n    (),\n>;\ntype RefCore<'a, G> = Core<\n    G,\n    &'a StorageTarget<'a, Vertex<G>>,\n    &'a StorageTarget<'a, Arc<G>>,\n    &'a StorageTarget<'a, Edge<G>>,\n    (),\n>;\n\npub struct EdgeMutation<P>\nwhere\n    P: Mode,\n{\n    inner: VertexMutation<P>,\n    // TODO: Split this into two fields.\n    storage: (P::ArcStorage, P::EdgeStorage),\n}\n\nimpl<P> EdgeMutation<P>\nwhere\n    P: Mode,\n{\n    pub fn to_ref_core(&self) -> RefCore<Data<P::Graph>> {\n        self.inner\n            .to_ref_core()\n            .fuse(self.storage.0.as_storage())\n            .fuse(self.storage.1.as_storage())\n    }\n\n    pub fn connect_adjacent_arcs(&mut self, ab: ArcKey, bc: ArcKey) -> Result<(), GraphError> {\n        self.with_arc_mut(ab, |arc| arc.next = Some(bc))?;\n        self.with_arc_mut(bc, |arc| arc.previous = Some(ab))?;\n        Ok(())\n    }\n\n    pub fn disconnect_next_arc(&mut self, ab: ArcKey) -> Result<Option<ArcKey>, GraphError> {\n        let bx = self.with_arc_mut(ab, |arc| arc.next.take())?;\n        if let Some(bx) = bx.as_ref() {\n            self.with_arc_mut(*bx, |arc| arc.previous.take())\n                .map_err(|_| GraphError::TopologyMalformed)?;\n        }\n        Ok(bx)\n    }\n\n    pub fn disconnect_previous_arc(&mut self, ab: ArcKey) -> Result<Option<ArcKey>, GraphError> {\n        let xa = self.with_arc_mut(ab, |arc| arc.previous.take())?;\n        if let Some(xa) = xa.as_ref() {\n            self.with_arc_mut(*xa, |arc| arc.next.take())\n                .map_err(|_| GraphError::TopologyMalformed)?;\n        }\n        Ok(xa)\n    }\n\n    pub fn connect_arc_to_edge(&mut self, ab: ArcKey, ab_ba: EdgeKey) -> Result<(), GraphError> {\n        self.with_arc_mut(ab, |arc| arc.edge = Some(ab_ba))\n    }\n\n    pub fn connect_arc_to_face(&mut self, ab: ArcKey, abc: FaceKey) -> Result<(), GraphError> {\n        self.with_arc_mut(ab, |arc| arc.face = Some(abc))\n    }\n\n    pub fn disconnect_arc_from_face(&mut self, ab: ArcKey) -> Result<Option<FaceKey>, GraphError> {\n        self.with_arc_mut(ab, |arc| arc.face.take())\n    }\n\n    fn with_arc_mut<T, F>(&mut self, ab: ArcKey, mut f: F) -> Result<T, GraphError>\n    where\n        F: FnMut(&mut Arc<Data<P::Graph>>) -> T,\n    {\n        let arc = self\n            .storage\n            .0\n            .as_storage_mut()\n            .get_mut(&ab)\n            .ok_or(GraphError::TopologyNotFound)?;\n        Ok(f(arc))\n    }\n}\n\nimpl<P> AsStorage<Arc<Data<P::Graph>>> for EdgeMutation<P>\nwhere\n    P: Mode,\n{\n    fn as_storage(&self) -> &StorageTarget<Arc<Data<P::Graph>>> {\n        self.storage.0.as_storage()\n    }\n}\n\nimpl<P> AsStorage<Edge<Data<P::Graph>>> for EdgeMutation<P>\nwhere\n    P: Mode,\n{\n    fn as_storage(&self) -> &StorageTarget<Edge<Data<P::Graph>>> {\n        self.storage.1.as_storage()\n    }\n}\n\nimpl<M> Bypass<ModalCore<Immediate<M>>> for EdgeMutation<Immediate<M>>\nwhere\n    M: Parametric,\n{\n    fn bypass(self) -> Self::Commit {\n        let EdgeMutation {\n            inner,\n            storage: (arcs, edges),\n            ..\n        } = self;\n        inner.bypass().fuse(arcs).fuse(edges)\n    }\n}\n\n// TODO: This is a hack. Replace this with delegation.\nimpl<P> Deref for EdgeMutation<P>\nwhere\n    P: Mode,\n{\n    type Target = VertexMutation<P>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.inner\n    }\n}\n\nimpl<P> DerefMut for EdgeMutation<P>\nwhere\n    P: Mode,\n{\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.inner\n    }\n}\n\nimpl<P> From<ModalCore<P>> for EdgeMutation<P>\nwhere\n    P: Mode,\n{\n    fn from(core: ModalCore<P>) -> Self {\n        let (vertices, arcs, edges, ..) = core.unfuse();\n        EdgeMutation {\n            inner: Core::empty().fuse(vertices).into(),\n            storage: (arcs, edges),\n        }\n    }\n}\n\nimpl<M> Transact<ModalCore<Immediate<M>>> for EdgeMutation<Immediate<M>>\nwhere\n    M: Parametric,\n{\n    type Commit = ModalCore<Immediate<M>>;\n    type Abort = ();\n    type Error = GraphError;\n\n    fn commit(self) -> Result<Self::Commit, (Self::Abort, Self::Error)> {\n        let EdgeMutation {\n            inner,\n            storage: (arcs, edges),\n            ..\n        } = self;\n        // In a consistent graph, all arcs must have adjacent arcs and an\n        // associated edge.\n        for (_, arc) in arcs.as_storage().iter() {\n            if arc.next.is_none() || arc.previous.is_none() || arc.edge.is_none() {\n                return Err(((), GraphError::TopologyMalformed));\n            }\n        }\n        inner.commit().map(move |core| core.fuse(arcs).fuse(edges))\n    }\n\n    fn abort(self) -> Self::Abort {}\n}\n\nstruct ArcRemoveCache {\n    ab: ArcKey,\n    xa: Option<ArcKey>,\n    bx: Option<ArcKey>,\n    cache: Option<FaceRemoveCache>,\n}\n\nimpl ArcRemoveCache {\n    pub fn from_arc<B>(arc: ArcView<B>) -> Result<Self, GraphError>\n    where\n        B: Reborrow,\n        B::Target: AsStorage<Arc<Data<B>>>\n            + AsStorage<Face<Data<B>>>\n            + AsStorage<Vertex<Data<B>>>\n            + Consistent\n            + Parametric,\n    {\n        // If the edge has no neighbors, then `xa` and `bx` will refer to the\n        // opposite arc of `ab`. In this case, the vertices `a` and `b` should\n        // have no leading arcs after the removal. The cache will have its `xa`\n        // and `bx` fields set to `None` in this case.\n        let ab = arc.key();\n        let ba = arc.opposite_arc().key();\n        let xa = arc.previous_arc().key();\n        let bx = arc.next_arc().key();\n        let cache = if let Some(face) = arc.face() {\n            Some(FaceRemoveCache::from_face(face)?)\n        }\n        else {\n            None\n        };\n        Ok(ArcRemoveCache {\n            ab,\n            xa: if xa != ba { Some(xa) } else { None },\n            bx: if bx != ba { Some(bx) } else { None },\n            cache,\n        })\n    }\n}\n\npub struct EdgeRemoveCache {\n    a: VertexKey,\n    b: VertexKey,\n    ab_ba: EdgeKey,\n    arc: ArcRemoveCache,\n    opposite: ArcRemoveCache,\n}\n\nimpl EdgeRemoveCache {\n    pub fn from_arc<B>(arc: ArcView<B>) -> Result<Self, GraphError>\n    where\n        B: Reborrow,\n        B::Target: AsStorage<Arc<Data<B>>>\n            + AsStorage<Edge<Data<B>>>\n            + AsStorage<Face<Data<B>>>\n            + AsStorage<Vertex<Data<B>>>\n            + Consistent\n            + Parametric,\n    {\n        let a = arc.source_vertex().key();\n        let b = arc.destination_vertex().key();\n        let ab_ba = arc.edge().key();\n        Ok(EdgeRemoveCache {\n            a,\n            b,\n            ab_ba,\n            arc: ArcRemoveCache::from_arc(arc.to_ref())?,\n            opposite: ArcRemoveCache::from_arc(arc.into_opposite_arc())?,\n        })\n    }\n}\n\npub struct EdgeSplitCache {\n    a: VertexKey,\n    b: VertexKey,\n    ab: ArcKey,\n    ba: ArcKey,\n    ab_ba: EdgeKey,\n}\n\nimpl EdgeSplitCache {\n    pub fn from_arc<B>(arc: ArcView<B>) -> Result<Self, GraphError>\n    where\n        B: Reborrow,\n        B::Target: AsStorage<Arc<Data<B>>>\n            + AsStorage<Edge<Data<B>>>\n            + AsStorage<Vertex<Data<B>>>\n            + Parametric,\n    {\n        let opposite = arc\n            .to_ref()\n            .into_reachable_opposite_arc()\n            .ok_or(GraphError::TopologyMalformed)?;\n        let source = opposite\n            .to_ref()\n            .into_reachable_destination_vertex()\n            .ok_or(GraphError::TopologyMalformed)?;\n        let destination = arc\n            .to_ref()\n            .into_reachable_destination_vertex()\n            .ok_or(GraphError::TopologyMalformed)?;\n        let edge = arc\n            .to_ref()\n            .into_reachable_edge()\n            .ok_or(GraphError::TopologyNotFound)?;\n        Ok(EdgeSplitCache {\n            a: source.key(),\n            b: destination.key(),\n            ab: arc.key(),\n            ba: opposite.key(),\n            ab_ba: edge.key(),\n        })\n    }\n}\n\npub struct ArcBridgeCache {\n    a: VertexKey,\n    b: VertexKey,\n    c: VertexKey,\n    d: VertexKey,\n}\n\nimpl ArcBridgeCache {\n    pub fn from_arc<B>(arc: ArcView<B>, destination: ArcKey) -> Result<Self, GraphError>\n    where\n        B: Reborrow,\n        B::Target: AsStorage<Arc<Data<B>>> + AsStorage<Vertex<Data<B>>> + Parametric,\n    {\n        let destination: ArcView<_> = arc\n            .to_ref()\n            .rebind(destination)\n            .ok_or(GraphError::TopologyNotFound)?;\n        let a = arc\n            .to_ref()\n            .into_reachable_source_vertex()\n            .ok_or(GraphError::TopologyMalformed)?\n            .key();\n        let b = arc\n            .to_ref()\n            .into_reachable_destination_vertex()\n            .ok_or(GraphError::TopologyMalformed)?\n            .key();\n        let c = destination\n            .to_ref()\n            .into_reachable_source_vertex()\n            .ok_or(GraphError::TopologyMalformed)?\n            .key();\n        let d = destination\n            .to_ref()\n            .into_reachable_destination_vertex()\n            .ok_or(GraphError::TopologyMalformed)?\n            .key();\n        // Ensure that existing interior arcs are boundaries.\n        for arc in [a, b, c, d]\n            .iter()\n            .cloned()\n            .perimeter()\n            .flat_map(|ab| -> Option<ArcView<_>> { arc.to_ref().rebind(ab.into()) })\n        {\n            if !arc.is_boundary_arc() {\n                return Err(GraphError::TopologyConflict);\n            }\n        }\n        Ok(ArcBridgeCache { a, b, c, d })\n    }\n\n    pub fn from_storage<B>(\n        storage: B,\n        source: ArcKey,\n        destination: ArcKey,\n    ) -> Result<Self, GraphError>\n    where\n        B: Reborrow,\n        B::Target: AsStorage<Arc<Data<B>>> + AsStorage<Vertex<Data<B>>> + Parametric,\n    {\n        ArcBridgeCache::from_arc(\n            ArcView::bind(storage, source).ok_or(GraphError::TopologyNotFound)?,\n            destination,\n        )\n    }\n}\n\npub struct ArcExtrudeCache {\n    ab: ArcKey,\n}\n\nimpl ArcExtrudeCache {\n    pub fn from_arc<B>(arc: ArcView<B>) -> Result<Self, GraphError>\n    where\n        B: Reborrow,\n        B::Target: AsStorage<Arc<Data<B>>>\n            + AsStorage<Face<Data<B>>>\n            + AsStorage<Vertex<Data<B>>>\n            + Consistent\n            + Parametric,\n    {\n        if !arc.is_boundary_arc() {\n            Err(GraphError::TopologyConflict)\n        }\n        else {\n            Ok(ArcExtrudeCache { ab: arc.key() })\n        }\n    }\n}\n\npub fn get_or_insert_with<N, P, F>(\n    mut mutation: N,\n    endpoints: (VertexKey, VertexKey),\n    f: F,\n) -> Result<CompositeEdgeKey, GraphError>\nwhere\n    N: AsMut<Mutation<P>>,\n    P: Mode,\n    P::Graph: Mutable,\n    F: FnOnce() -> CompositeEdgeData<Data<P::Graph>>,\n{\n    fn get_or_insert_arc<N, P>(\n        mut mutation: N,\n        endpoints: (VertexKey, VertexKey),\n        data: <Data<P::Graph> as GraphData>::Arc,\n    ) -> (Option<EdgeKey>, ArcKey)\n    where\n        N: AsMut<Mutation<P>>,\n        P: Mode,\n        P::Graph: Mutable,\n    {\n        let (a, _) = endpoints;\n        let ab = endpoints.into();\n        if let Some(arc) = mutation.as_mut().storage.0.as_storage().get(&ab) {\n            (arc.edge, ab)\n        }\n        else {\n            mutation\n                .as_mut()\n                .storage\n                .0\n                .as_storage_mut()\n                .insert_with_key(&ab, Arc::new(data));\n            let _ = mutation.as_mut().connect_outgoing_arc(a, ab);\n            (None, ab)\n        }\n    }\n\n    let data = f();\n    let (a, b) = endpoints;\n    let (e1, ab) = get_or_insert_arc(mutation.as_mut(), (a, b), data.1 .0);\n    let (e2, ba) = get_or_insert_arc(mutation.as_mut(), (b, a), data.1 .1);\n    match (e1, e2) {\n        (Some(e1), Some(e2)) if e1 == e2 => Ok((e1, (ab, ba))),\n        (None, None) => {\n            let ab_ba = mutation\n                .as_mut()\n                .storage\n                .1\n                .as_storage_mut()\n                .insert(Edge::new(ab, data.0));\n            mutation.as_mut().connect_arc_to_edge(ab, ab_ba)?;\n            mutation.as_mut().connect_arc_to_edge(ba, ab_ba)?;\n            Ok((ab_ba, (ab, ba)))\n        }\n        // It should not be possible to insert or remove individual arcs and\n        // mutations should not allow arcs to be assigned to edges\n        // independently of their opposite arcs.\n        _ => Err(GraphError::TopologyMalformed),\n    }\n}\n\n// TODO: Removing arcs must also remove disjoint vertices. More importantly, the\n//       leading arc of vertices may be invalidated by this operation and must\n//       be healed. This code does not handle these cases, and so can become\n//       inconsistent.\npub fn remove<N, P>(\n    mut mutation: N,\n    cache: EdgeRemoveCache,\n) -> Result<CompositeEdge<Data<P::Graph>>, GraphError>\nwhere\n    N: AsMut<Mutation<P>>,\n    P: Mode,\n    P::Graph: Mutable,\n{\n    fn remove_arc<N, P>(\n        mut mutation: N,\n        cache: ArcRemoveCache,\n    ) -> Result<Arc<Data<P::Graph>>, GraphError>\n    where\n        N: AsMut<Mutation<P>>,\n        P: Mode,\n        P::Graph: Mutable,\n    {\n        let ArcRemoveCache { ab, cache, .. } = cache;\n        if let Some(cache) = cache {\n            face::remove(mutation.as_mut(), cache)?;\n        }\n        mutation\n            .as_mut()\n            .storage\n            .0\n            .as_storage_mut()\n            .remove(&ab)\n            .ok_or(GraphError::TopologyNotFound)\n    }\n\n    let EdgeRemoveCache {\n        a,\n        b,\n        ab_ba,\n        arc,\n        opposite,\n    } = cache;\n    // Connect each vertex to a remaining outgoing edge.\n    if let Some(ax) = opposite.bx {\n        mutation.as_mut().connect_outgoing_arc(a, ax)?;\n    }\n    if let Some(bx) = arc.bx {\n        mutation.as_mut().connect_outgoing_arc(b, bx)?;\n    }\n    // Connect previous and next arcs across the edge to be removed.\n    if let (Some(xa), Some(ax)) = (arc.xa, opposite.bx) {\n        mutation.as_mut().connect_adjacent_arcs(xa, ax)?;\n    }\n    if let (Some(xb), Some(bx)) = (opposite.xa, arc.bx) {\n        mutation.as_mut().connect_adjacent_arcs(xb, bx)?;\n    }\n    let edge = mutation\n        .as_mut()\n        .storage\n        .1\n        .as_storage_mut()\n        .remove(&ab_ba)\n        .ok_or(GraphError::TopologyNotFound)?;\n    Ok((\n        edge,\n        (\n            remove_arc(mutation.as_mut(), arc)?,\n            remove_arc(mutation.as_mut(), opposite)?,\n        ),\n    ))\n}\n\npub fn split_with<N, P, F>(\n    mut mutation: N,\n    cache: EdgeSplitCache,\n    f: F,\n) -> Result<VertexKey, GraphError>\nwhere\n    N: AsMut<Mutation<P>>,\n    P: Mode,\n    P::Graph: Mutable,\n    F: FnOnce() -> <Data<P::Graph> as GraphData>::Vertex,\n{\n    fn remove<N, P>(mut mutation: N, ab: ArcKey) -> Result<Arc<Data<P::Graph>>, GraphError>\n    where\n        N: AsMut<Mutation<P>>,\n        P: Mode,\n        P::Graph: Mutable,\n    {\n        // TODO: Is is probably more correct to disconnect the source vertex\n        //       from its leading arc. However, this interacts poorly with\n        //       `split_at_vertex`, and on the second pass will orphan the\n        //       vertex B.\n        //\n        // let (a, _) = ab.into();\n        // mutation.as_mut().disconnect_outgoing_arc(a)?;\n        let xa = mutation.as_mut().disconnect_previous_arc(ab)?;\n        let bx = mutation.as_mut().disconnect_next_arc(ab)?;\n        let mut arc = mutation\n            .as_mut()\n            .storage\n            .0\n            .as_storage_mut()\n            .remove(&ab)\n            .unwrap();\n        // Restore the connectivity of the arc. The mutations will clear this\n        // data, because it is still a part of the mesh at that point.\n        arc.previous = xa;\n        arc.next = bx;\n        Ok(arc)\n    }\n\n    fn split_at_vertex<N, P>(\n        mut mutation: N,\n        a: VertexKey,\n        b: VertexKey,\n        m: VertexKey,\n        ab: ArcKey,\n        edge_data: <Data<P::Graph> as GraphData>::Edge,\n    ) -> Result<(ArcKey, ArcKey), GraphError>\n    where\n        N: AsMut<Mutation<P>>,\n        P: Mode,\n        P::Graph: Mutable,\n    {\n        // Remove the arc and insert two truncated arcs in its place.\n        let Arc {\n            next,\n            previous,\n            face,\n            data: arc_data,\n            ..\n        } = remove(mutation.as_mut(), ab)?;\n        let data = (edge_data, (arc_data.clone(), arc_data));\n        let am = get_or_insert_with(mutation.as_mut(), (a, m), || data.clone())\n            .map(|(_, (am, _))| am)?;\n        let mb = get_or_insert_with(mutation.as_mut(), (m, b), || data).map(|(_, (mb, _))| mb)?;\n        // Connect the new arcs to each other and their leading arcs.\n        mutation.as_mut().connect_adjacent_arcs(am, mb)?;\n        if let Some(xa) = previous {\n            mutation.as_mut().connect_adjacent_arcs(xa, am)?;\n        }\n        if let Some(bx) = next {\n            mutation.as_mut().connect_adjacent_arcs(mb, bx)?;\n        }\n        // Update the associated face, if any, because it may refer to the\n        // removed arc.\n        if let Some(abc) = face {\n            mutation.as_mut().connect_face_to_arc(am, abc)?;\n            mutation.as_mut().connect_arc_to_face(am, abc)?;\n            mutation.as_mut().connect_arc_to_face(mb, abc)?;\n        }\n        Ok((am, mb))\n    }\n\n    let EdgeSplitCache {\n        a,\n        b,\n        ab,\n        ba,\n        ab_ba,\n    } = cache;\n    let m = vertex::insert(mutation.as_mut(), f());\n    // Remove the edge.\n    let Edge { data, .. } = mutation\n        .as_mut()\n        .storage\n        .1\n        .as_storage_mut()\n        .remove(&ab_ba)\n        .ok_or(GraphError::TopologyMalformed)?;\n    // Split the arcs.\n    split_at_vertex(mutation.as_mut(), a, b, m, ab, data.clone())?;\n    split_at_vertex(mutation.as_mut(), b, a, m, ba, data)?;\n    Ok(m)\n}\n\npub fn bridge<N, P>(mut mutation: N, cache: ArcBridgeCache) -> Result<FaceKey, GraphError>\nwhere\n    N: AsMut<Mutation<P>>,\n    P: Mode,\n    P::Graph: Mutable,\n{\n    let ArcBridgeCache { a, b, c, d } = cache;\n    let cache = FaceInsertCache::from_storage(mutation.as_mut(), &[a, b, c, d])?;\n    face::insert_with(mutation.as_mut(), cache, Default::default)\n}\n\n// LINT: These names follow a convention, mainly concerning vertices.\n#[expect(clippy::many_single_char_names)]\npub fn extrude_with<N, P, F>(\n    mut mutation: N,\n    cache: ArcExtrudeCache,\n    f: F,\n) -> Result<ArcKey, GraphError>\nwhere\n    N: AsMut<Mutation<P>>,\n    P: Mode,\n    P::Graph: Mutable,\n    F: Fn(<Data<P::Graph> as GraphData>::Vertex) -> <Data<P::Graph> as GraphData>::Vertex,\n{\n    let ArcExtrudeCache { ab } = cache;\n    let (c, d) = {\n        let (a, b) = ab.into();\n        let c = VertexView::bind(mutation.as_mut(), b)\n            .ok_or(GraphError::TopologyNotFound)?\n            .get()\n            .clone();\n        let d = VertexView::bind(mutation.as_mut(), a)\n            .ok_or(GraphError::TopologyNotFound)?\n            .get()\n            .clone();\n        (f(c), f(d))\n    };\n    let c = vertex::insert(mutation.as_mut(), c);\n    let d = vertex::insert(mutation.as_mut(), d);\n    let cd =\n        get_or_insert_with(mutation.as_mut(), (c, d), Default::default).map(|(_, (cd, _))| cd)?;\n    let cache = ArcBridgeCache::from_storage(mutation.as_mut(), ab, cd)?;\n    bridge(mutation, cache).map(|_| cd)\n}\n"
  },
  {
    "path": "plexus/src/graph/mutation/face.rs",
    "content": "use smallvec::SmallVec;\nuse std::borrow::Borrow;\nuse std::collections::{HashMap, HashSet};\nuse std::ops::{Deref, DerefMut};\n\nuse crate::entity::borrow::Reborrow;\nuse crate::entity::storage::prelude::*;\nuse crate::entity::storage::{AsStorage, AsStorageMut, Fuse, StorageTarget};\nuse crate::entity::view::{Bind, ClosedView, Rebind, Unbind};\nuse crate::graph::core::Core;\nuse crate::graph::data::{Data, GraphData, Parametric};\nuse crate::graph::edge::{Arc, ArcKey, ArcView, Edge};\nuse crate::graph::face::{Face, FaceKey, FaceView, ToRing};\nuse crate::graph::mutation::edge::{self, ArcBridgeCache, EdgeMutation};\nuse crate::graph::mutation::{vertex, Consistent, Immediate, Mode, Mutable, Mutation};\nuse crate::graph::vertex::{Vertex, VertexKey, VertexView};\nuse crate::graph::GraphError;\nuse crate::transact::{Bypass, Transact};\nuse crate::{DynamicArity, IteratorExt as _};\n\ntype ModalCore<P> = Core<\n    Data<<P as Mode>::Graph>,\n    <P as Mode>::VertexStorage,\n    <P as Mode>::ArcStorage,\n    <P as Mode>::EdgeStorage,\n    <P as Mode>::FaceStorage,\n>;\npub type RefCore<'a, G> = Core<\n    G,\n    &'a StorageTarget<'a, Vertex<G>>,\n    &'a StorageTarget<'a, Arc<G>>,\n    &'a StorageTarget<'a, Edge<G>>,\n    &'a StorageTarget<'a, Face<G>>,\n>;\n\npub struct FaceMutation<P>\nwhere\n    P: Mode,\n{\n    inner: EdgeMutation<P>,\n    storage: P::FaceStorage,\n}\n\nimpl<P> FaceMutation<P>\nwhere\n    P: Mode,\n{\n    pub fn to_ref_core(&self) -> RefCore<Data<P::Graph>> {\n        self.inner.to_ref_core().fuse(self.storage.as_storage())\n    }\n\n    // TODO: Should there be a distinction between `connect_face_to_arc` and\n    //       `connect_arc_to_face`?\n    pub fn connect_face_to_arc(&mut self, ab: ArcKey, abc: FaceKey) -> Result<(), GraphError> {\n        self.with_face_mut(abc, |face| face.arc = ab)\n    }\n\n    fn connect_face_interior(&mut self, arcs: &[ArcKey], face: FaceKey) -> Result<(), GraphError> {\n        for (ab, bc) in arcs.iter().cloned().perimeter() {\n            self.connect_adjacent_arcs(ab, bc)?;\n            self.connect_arc_to_face(ab, face)?;\n        }\n        Ok(())\n    }\n\n    fn disconnect_face_interior(&mut self, arcs: &[ArcKey]) -> Result<(), GraphError> {\n        for ab in arcs {\n            self.disconnect_arc_from_face(*ab)?;\n        }\n        Ok(())\n    }\n\n    fn connect_face_exterior(\n        &mut self,\n        arcs: &[ArcKey],\n        connectivity: (\n            HashMap<VertexKey, Vec<ArcKey>>,\n            HashMap<VertexKey, Vec<ArcKey>>,\n        ),\n    ) -> Result<(), GraphError> {\n        let (incoming, outgoing) = connectivity;\n        for ab in arcs.iter().cloned() {\n            let (a, b) = ab.into();\n            let ba = ab.into_opposite();\n            let adjacent = {\n                let core = &self.to_ref_core();\n                if ArcView::bind(core, ba)\n                    .ok_or(GraphError::TopologyMalformed)?\n                    .is_boundary_arc()\n                {\n                    // The next arc of BA is the outgoing arc of the destination\n                    // vertex A that is also a boundary arc or, if there is no\n                    // such outgoing arc, the next exterior arc of the face. The\n                    // previous arc is similar.\n                    let ax = outgoing[&a]\n                        .iter()\n                        .cloned()\n                        .flat_map(|ax| ArcView::bind(core, ax))\n                        .find(|next| next.is_boundary_arc())\n                        .or_else(|| {\n                            ArcView::bind(core, ab)\n                                .and_then(|arc| arc.into_reachable_previous_arc())\n                                .and_then(|previous| previous.into_reachable_opposite_arc())\n                        })\n                        .map(|next| next.key());\n                    let xb = incoming[&b]\n                        .iter()\n                        .cloned()\n                        .flat_map(|xb| ArcView::bind(core, xb))\n                        .find(|previous| previous.is_boundary_arc())\n                        .or_else(|| {\n                            ArcView::bind(core, ab)\n                                .and_then(|arc| arc.into_reachable_next_arc())\n                                .and_then(|next| next.into_reachable_opposite_arc())\n                        })\n                        .map(|previous| previous.key());\n                    ax.into_iter().zip(xb.into_iter()).next()\n                }\n                else {\n                    None\n                }\n            };\n            if let Some((ax, xb)) = adjacent {\n                self.connect_adjacent_arcs(ba, ax)?;\n                self.connect_adjacent_arcs(xb, ba)?;\n            }\n        }\n        Ok(())\n    }\n\n    fn with_face_mut<T, F>(&mut self, abc: FaceKey, mut f: F) -> Result<T, GraphError>\n    where\n        F: FnMut(&mut Face<Data<P::Graph>>) -> T,\n    {\n        let face = self\n            .storage\n            .as_storage_mut()\n            .get_mut(&abc)\n            .ok_or(GraphError::TopologyNotFound)?;\n        Ok(f(face))\n    }\n}\n\nimpl<P> AsStorage<Face<Data<P::Graph>>> for FaceMutation<P>\nwhere\n    P: Mode,\n{\n    fn as_storage(&self) -> &StorageTarget<Face<Data<P::Graph>>> {\n        self.storage.as_storage()\n    }\n}\n\nimpl<M> Bypass<ModalCore<Immediate<M>>> for FaceMutation<Immediate<M>>\nwhere\n    M: Parametric,\n{\n    fn bypass(self) -> Self::Commit {\n        let FaceMutation {\n            inner,\n            storage: faces,\n            ..\n        } = self;\n        inner.bypass().fuse(faces)\n    }\n}\n\n// TODO: This is a hack. Replace this with delegation.\nimpl<P> Deref for FaceMutation<P>\nwhere\n    P: Mode,\n{\n    type Target = EdgeMutation<P>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.inner\n    }\n}\n\nimpl<P> DerefMut for FaceMutation<P>\nwhere\n    P: Mode,\n{\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.inner\n    }\n}\n\nimpl<P> From<ModalCore<P>> for FaceMutation<P>\nwhere\n    P: Mode,\n{\n    fn from(core: ModalCore<P>) -> Self {\n        let (vertices, arcs, edges, faces) = core.unfuse();\n        FaceMutation {\n            storage: faces,\n            inner: Core::empty().fuse(vertices).fuse(arcs).fuse(edges).into(),\n        }\n    }\n}\n\nimpl<M> Transact<ModalCore<Immediate<M>>> for FaceMutation<Immediate<M>>\nwhere\n    M: Parametric,\n{\n    type Commit = ModalCore<Immediate<M>>;\n    type Abort = ();\n    type Error = GraphError;\n\n    // TODO: Ensure that faces are in a consistent state.\n    fn commit(self) -> Result<Self::Commit, (Self::Abort, Self::Error)> {\n        let FaceMutation {\n            inner,\n            storage: faces,\n            ..\n        } = self;\n        inner.commit().map(move |core| core.fuse(faces))\n    }\n\n    fn abort(self) -> Self::Abort {}\n}\n\npub struct FaceInsertCache {\n    perimeter: SmallVec<[VertexKey; 4]>,\n    connectivity: (\n        HashMap<VertexKey, Vec<ArcKey>>,\n        HashMap<VertexKey, Vec<ArcKey>>,\n    ),\n}\n\nimpl FaceInsertCache {\n    pub fn from_ring<B, T>(ring: T) -> Result<Self, GraphError>\n    where\n        B: Reborrow,\n        B::Target: AsStorage<Arc<Data<B>>>\n            + AsStorage<Face<Data<B>>>\n            + AsStorage<Vertex<Data<B>>>\n            + Consistent\n            + Parametric,\n        T: ToRing<B>,\n    {\n        let ring = ring.into_ring();\n        let (storage, _) = ring.arc().unbind();\n        FaceInsertCache::from_storage(storage, ring.vertices().keys())\n    }\n\n    pub fn from_storage<B, K>(storage: B, perimeter: K) -> Result<Self, GraphError>\n    where\n        B: Reborrow,\n        B::Target: AsStorage<Arc<Data<B>>>\n            + AsStorage<Face<Data<B>>>\n            + AsStorage<Vertex<Data<B>>>\n            + Parametric,\n        K: IntoIterator,\n        K::Item: Borrow<VertexKey>,\n    {\n        let perimeter = perimeter\n            .into_iter()\n            .map(|key| *key.borrow())\n            .collect::<SmallVec<_>>();\n        let arity = perimeter.len();\n        let set = perimeter.iter().cloned().collect::<HashSet<_>>();\n        if set.len() != arity {\n            // Vertex keys are not unique.\n            return Err(GraphError::TopologyMalformed);\n        }\n\n        let storage = storage.reborrow();\n        let vertices = perimeter\n            .iter()\n            .cloned()\n            .map(|key| VertexView::bind(storage, key).ok_or(GraphError::TopologyNotFound))\n            .collect::<Result<SmallVec<[_; 4]>, _>>()?;\n        for (previous, next) in perimeter\n            .iter()\n            .cloned()\n            .perimeter()\n            .map(|keys| ArcView::bind(storage, keys.into()))\n            .perimeter()\n        {\n            if let Some(previous) = previous {\n                if previous.face.is_some() {\n                    // A face already occupies an interior arc.\n                    return Err(GraphError::TopologyConflict);\n                }\n                // Let the previous arc be AB and the next arc be BC. The\n                // vertices A, B, and C lie within the implied ring in order.\n                //\n                // If BC does not exist and AB is adjacent to some arc BX, then\n                // X must not lie within the implied ring (the ordered set of\n                // vertices given to this function). If X is within the path,\n                // then BX must bisect the implied ring (because X cannot be C).\n                if next.is_none() {\n                    if let Some(next) = previous.into_reachable_next_arc() {\n                        let (_, destination) = next.key().into();\n                        if set.contains(&destination) {\n                            return Err(GraphError::TopologyConflict);\n                        }\n                    }\n                }\n            }\n        }\n\n        let mut incoming = HashMap::with_capacity(arity);\n        let mut outgoing = HashMap::with_capacity(arity);\n        for vertex in vertices {\n            let key = vertex.key();\n            incoming.insert(key, vertex.reachable_incoming_arcs().keys().collect());\n            outgoing.insert(key, vertex.reachable_outgoing_arcs().keys().collect());\n        }\n        Ok(FaceInsertCache {\n            perimeter,\n            connectivity: (incoming, outgoing),\n        })\n    }\n}\n\npub struct FaceRemoveCache {\n    abc: FaceKey,\n    arcs: Vec<ArcKey>,\n}\n\nimpl FaceRemoveCache {\n    // TODO: Should this require consistency?\n    pub fn from_face<B>(face: FaceView<B>) -> Result<Self, GraphError>\n    where\n        B: Reborrow,\n        B::Target: AsStorage<Arc<Data<B>>>\n            + AsStorage<Face<Data<B>>>\n            + AsStorage<Vertex<Data<B>>>\n            + Consistent\n            + Parametric,\n    {\n        let arcs = face.adjacent_arcs().keys().collect();\n        Ok(FaceRemoveCache {\n            abc: face.key(),\n            arcs,\n        })\n    }\n}\n\npub struct FaceSplitCache {\n    cache: FaceRemoveCache,\n    left: Vec<VertexKey>,\n    right: Vec<VertexKey>,\n}\n\nimpl FaceSplitCache {\n    pub fn from_face<B>(\n        face: FaceView<B>,\n        source: VertexKey,\n        destination: VertexKey,\n    ) -> Result<Self, GraphError>\n    where\n        B: Reborrow,\n        B::Target: AsStorage<Arc<Data<B>>>\n            + AsStorage<Face<Data<B>>>\n            + AsStorage<Vertex<Data<B>>>\n            + Consistent\n            + Parametric,\n    {\n        let perimeter = |face: FaceView<_>| {\n            face.adjacent_vertices()\n                .keys()\n                .collect::<Vec<_>>()\n                .into_iter()\n                .cycle()\n        };\n        // This closure determines if any arcs in the given perimeter are\n        // connected to a face other than the face initiating the split. This\n        // may occur if an adjacent face shares two or more edges with the\n        // initiating face and the source and destination vertices of the split\n        // lie along that boundary.\n        let is_intersecting = |perimeter: &[_]| {\n            for (a, b) in perimeter.iter().cloned().perimeter() {\n                let ab = (a, b).into();\n                if let Some(arc) = Rebind::<_, ArcView<_>>::rebind(face.to_ref(), ab) {\n                    if let Some(key) = arc.face().map(|face| face.key()) {\n                        if key != face.key() {\n                            return true;\n                        }\n                    }\n                }\n            }\n            false\n        };\n        face.ring()\n            .shortest_logical_metric(source, destination)\n            .and_then(|metric| {\n                if metric <= 1 {\n                    Err(GraphError::TopologyMalformed)\n                }\n                else {\n                    Ok(())\n                }\n            })?;\n        // Note that the winding of the perimeters must be relatively oriented.\n        let left = perimeter(face.to_ref())\n            .perimeter()\n            .skip_while(|(_, b)| *b != source)\n            .take_while(|(a, _)| *a != destination)\n            .map(|(_, b)| b)\n            .collect::<Vec<_>>();\n        let right = perimeter(face.to_ref())\n            .perimeter()\n            .skip_while(|(_, b)| *b != destination)\n            .take_while(|(a, _)| *a != source)\n            .map(|(_, b)| b)\n            .collect::<Vec<_>>();\n        if is_intersecting(&left) || is_intersecting(&right) {\n            return Err(GraphError::TopologyConflict);\n        }\n        Ok(FaceSplitCache {\n            cache: FaceRemoveCache::from_face(face)?,\n            left,\n            right,\n        })\n    }\n}\n\npub struct FacePokeCache {\n    vertices: Vec<VertexKey>,\n    cache: FaceRemoveCache,\n}\n\nimpl FacePokeCache {\n    pub fn from_face<B>(face: FaceView<B>) -> Result<Self, GraphError>\n    where\n        B: Reborrow,\n        B::Target: AsStorage<Arc<Data<B>>>\n            + AsStorage<Face<Data<B>>>\n            + AsStorage<Vertex<Data<B>>>\n            + Consistent\n            + Parametric,\n    {\n        let vertices = face.adjacent_vertices().keys().collect();\n        Ok(FacePokeCache {\n            vertices,\n            cache: FaceRemoveCache::from_face(face)?,\n        })\n    }\n}\n\npub struct FaceBridgeCache {\n    source: SmallVec<[ArcKey; 4]>,\n    destination: SmallVec<[ArcKey; 4]>,\n    cache: (FaceRemoveCache, FaceRemoveCache),\n}\n\nimpl FaceBridgeCache {\n    pub fn from_face<B>(face: FaceView<B>, destination: FaceKey) -> Result<Self, GraphError>\n    where\n        B: Reborrow,\n        B::Target: AsStorage<Arc<Data<B>>>\n            + AsStorage<Face<Data<B>>>\n            + AsStorage<Vertex<Data<B>>>\n            + Consistent\n            + Parametric,\n    {\n        let destination: FaceView<_> = face\n            .to_ref()\n            .rebind(destination)\n            .ok_or(GraphError::TopologyNotFound)?;\n        let cache = (\n            FaceRemoveCache::from_face(face.to_ref())?,\n            FaceRemoveCache::from_face(destination.to_ref())?,\n        );\n        // Ensure that the opposite face exists and has the same arity.\n        if face.arity() != destination.arity() {\n            return Err(GraphError::ArityNonUniform);\n        }\n        Ok(FaceBridgeCache {\n            source: face.adjacent_arcs().keys().collect(),\n            destination: destination.adjacent_arcs().keys().collect(),\n            cache,\n        })\n    }\n}\n\npub struct FaceExtrudeCache {\n    sources: Vec<VertexKey>,\n    cache: FaceRemoveCache,\n}\n\nimpl FaceExtrudeCache {\n    pub fn from_face<B>(face: FaceView<B>) -> Result<Self, GraphError>\n    where\n        B: Reborrow,\n        B::Target: AsStorage<Arc<Data<B>>>\n            + AsStorage<Face<Data<B>>>\n            + AsStorage<Vertex<Data<B>>>\n            + Consistent\n            + Parametric,\n    {\n        let sources = face.adjacent_vertices().keys().collect();\n        let cache = FaceRemoveCache::from_face(face)?;\n        Ok(FaceExtrudeCache { sources, cache })\n    }\n}\n\n// TODO: Should this accept arc data at all?\npub fn insert_with<N, P, F>(\n    mut mutation: N,\n    cache: FaceInsertCache,\n    f: F,\n) -> Result<FaceKey, GraphError>\nwhere\n    N: AsMut<Mutation<P>>,\n    P: Mode,\n    P::Graph: Mutable,\n    F: FnOnce() -> (\n        <Data<P::Graph> as GraphData>::Arc,\n        <Data<P::Graph> as GraphData>::Face,\n    ),\n{\n    let FaceInsertCache {\n        perimeter,\n        connectivity,\n    } = cache;\n    let data = f();\n    // Insert edges and collect the interior arcs.\n    let arcs = perimeter\n        .iter()\n        .cloned()\n        .perimeter()\n        .map(|(a, b)| {\n            edge::get_or_insert_with(mutation.as_mut(), (a, b), || {\n                (Default::default(), (data.0.clone(), data.0.clone()))\n            })\n            .map(|(_, (ab, _))| ab)\n        })\n        .collect::<Result<Vec<_>, _>>()?;\n    // Insert the face.\n    let face = mutation\n        .as_mut()\n        .storage\n        .as_storage_mut()\n        .insert(Face::new(arcs[0], data.1));\n    mutation.as_mut().connect_face_interior(&arcs, face)?;\n    mutation\n        .as_mut()\n        .connect_face_exterior(&arcs, connectivity)?;\n    Ok(face)\n}\n\n// TODO: Does this require a cache (or consistency)?\n// TODO: This may need to be more destructive to maintain consistency. Edges,\n//       arcs, and vertices may also need to be removed.\npub fn remove<N, P>(\n    mut mutation: N,\n    cache: FaceRemoveCache,\n) -> Result<Face<Data<P::Graph>>, GraphError>\nwhere\n    N: AsMut<Mutation<P>>,\n    P: Mode,\n    P::Graph: Mutable,\n{\n    let FaceRemoveCache { abc, arcs } = cache;\n    mutation.as_mut().disconnect_face_interior(&arcs)?;\n    let face = mutation\n        .as_mut()\n        .storage\n        .as_storage_mut()\n        .remove(&abc)\n        .ok_or(GraphError::TopologyNotFound)?;\n    Ok(face)\n}\n\npub fn split<N, P>(mut mutation: N, cache: FaceSplitCache) -> Result<ArcKey, GraphError>\nwhere\n    N: AsMut<Mutation<P>>,\n    P: Mode,\n    P::Graph: Mutable,\n{\n    let FaceSplitCache { cache, left, right } = cache;\n    remove(mutation.as_mut(), cache)?;\n    let ab = (left[0], right[0]).into();\n    let left = FaceInsertCache::from_storage(mutation.as_mut(), left)?;\n    let right = FaceInsertCache::from_storage(mutation.as_mut(), right)?;\n    insert_with(mutation.as_mut(), left, Default::default)?;\n    insert_with(mutation.as_mut(), right, Default::default)?;\n    Ok(ab)\n}\n\npub fn poke_with<N, P, F>(\n    mut mutation: N,\n    cache: FacePokeCache,\n    f: F,\n) -> Result<VertexKey, GraphError>\nwhere\n    N: AsMut<Mutation<P>>,\n    P: Mode,\n    P::Graph: Mutable,\n    F: FnOnce() -> <Data<P::Graph> as GraphData>::Vertex,\n{\n    let FacePokeCache { vertices, cache } = cache;\n    let face = remove(mutation.as_mut(), cache)?;\n    let c = vertex::insert(mutation.as_mut(), f());\n    for (a, b) in vertices.into_iter().perimeter() {\n        let cache = FaceInsertCache::from_storage(mutation.as_mut(), &[a, b, c])?;\n        insert_with(mutation.as_mut(), cache, || {\n            (Default::default(), face.data.clone())\n        })?;\n    }\n    Ok(c)\n}\n\npub fn bridge<N, P>(mut mutation: N, cache: FaceBridgeCache) -> Result<(), GraphError>\nwhere\n    N: AsMut<Mutation<P>>,\n    P: Mode,\n    P::Graph: Mutable,\n{\n    let FaceBridgeCache {\n        source,\n        destination,\n        cache,\n    } = cache;\n    // Remove the source and destination faces. Pair the topology with edge\n    // data for the source face.\n    remove(mutation.as_mut(), cache.0)?;\n    remove(mutation.as_mut(), cache.1)?;\n    // TODO: Is it always correct to reverse the order of the opposite face's\n    //       arcs?\n    // Re-insert the arcs of the faces and bridge the mutual arcs.\n    for (ab, cd) in source.into_iter().zip(destination.into_iter().rev()) {\n        let cache = ArcBridgeCache::from_storage(mutation.as_mut(), ab, cd)?;\n        edge::bridge(mutation.as_mut(), cache)?;\n    }\n    // TODO: Is there any reasonable entity this can return?\n    Ok(())\n}\n\npub fn extrude_with<N, P, F>(\n    mut mutation: N,\n    cache: FaceExtrudeCache,\n    f: F,\n) -> Result<FaceKey, GraphError>\nwhere\n    N: AsMut<Mutation<P>>,\n    P: Mode,\n    P::Graph: Mutable,\n    F: Fn(&<Data<P::Graph> as GraphData>::Vertex) -> <Data<P::Graph> as GraphData>::Vertex,\n{\n    let FaceExtrudeCache { sources, cache } = cache;\n    remove(mutation.as_mut(), cache)?;\n    let destinations = {\n        let mutation = &*mutation.as_mut();\n        sources\n            .iter()\n            .cloned()\n            .flat_map(|a| VertexView::bind(mutation, a))\n            .map(|source| f(source.get()))\n            .collect::<Vec<_>>()\n    };\n    if sources.len() != destinations.len() {\n        return Err(GraphError::TopologyNotFound);\n    }\n    let destinations = destinations\n        .into_iter()\n        .map(|data| vertex::insert(mutation.as_mut(), data))\n        .collect::<Vec<_>>();\n    // Use the keys for the existing vertices and the translated geometries to\n    // construct the extruded face and its connective faces.\n    let cache = FaceInsertCache::from_storage(mutation.as_mut(), &destinations)?;\n    let extrusion = insert_with(mutation.as_mut(), cache, Default::default)?;\n    for ((a, c), (b, d)) in sources\n        .into_iter()\n        .zip(destinations.into_iter())\n        .perimeter()\n    {\n        let cache = FaceInsertCache::from_storage(mutation.as_mut(), &[a, b, d, c])?;\n        // TODO: Split these faces to form triangles.\n        insert_with(mutation.as_mut(), cache, Default::default)?;\n    }\n    Ok(extrusion)\n}\n"
  },
  {
    "path": "plexus/src/graph/mutation/mod.rs",
    "content": "pub mod edge;\npub mod face;\npub mod path;\npub mod vertex;\n\nuse std::marker::PhantomData;\nuse std::ops::{Deref, DerefMut};\n\nuse crate::entity::storage::{AsStorage, AsStorageMut, StorageTarget};\nuse crate::entity::Entity;\nuse crate::graph::core::OwnedCore;\nuse crate::graph::data::{Data, Parametric};\nuse crate::graph::edge::{Arc, Edge};\nuse crate::graph::face::Face;\nuse crate::graph::mutation::face::FaceMutation;\nuse crate::graph::vertex::Vertex;\nuse crate::graph::{GraphData, GraphError};\nuse crate::transact::{Bypass, Transact};\n\n// TODO: The stable toolchain does not allow a type parameter `G` to be\n//       introduced and bound to the associated type `Mode::Graph::Data`. The\n//       compiler does not seem to consider the types equal, and requires\n//       redundant type bounds on `Mode`'s associated storage types at each\n//       usage. The nightly toolchain already supports this. Reintroduce a\n//       `G: GraphData` type parameter in implementation blocks when this is\n//       fixed. For now, this code uses `Data<P::Graph>`. See the following\n//       related issues:\n//\n//       https://github.com/rust-lang/rust/issues/58231\n//       https://github.com/rust-lang/rust/issues/70703\n//       https://github.com/rust-lang/rust/issues/47897\n\n/// Marker trait for graph representations that promise to be in a consistent\n/// state.\n///\n/// This trait is only implemented by representations that ensure that their\n/// storage is only ever mutated via the mutation API (and therefore is\n/// consistent). Note that `Core` does not implement this trait and instead acts\n/// as a raw container for topological storage that can be freely manipulated.\n///\n/// This trait allows code to make assumptions about the data it operates\n/// against. For example, views expose an API to user code that assumes that\n/// topologies are present and therefore unwraps values.\npub trait Consistent {}\n\nimpl<T> Consistent for &'_ T where T: Consistent {}\n\nimpl<T> Consistent for &'_ mut T where T: Consistent {}\n\npub trait Mode {\n    type Graph: Parametric;\n    type VertexStorage: AsStorageMut<Vertex<Data<Self::Graph>>>;\n    type ArcStorage: AsStorageMut<Arc<Data<Self::Graph>>>;\n    type EdgeStorage: AsStorageMut<Edge<Data<Self::Graph>>>;\n    type FaceStorage: AsStorageMut<Face<Data<Self::Graph>>>;\n}\n\npub struct Immediate<M>\nwhere\n    M: Parametric,\n{\n    phantom: PhantomData<fn() -> M>,\n}\n\nimpl<M> Mode for Immediate<M>\nwhere\n    M: Parametric,\n{\n    type Graph = M;\n    type VertexStorage = <Vertex<Data<M>> as Entity>::Storage;\n    type ArcStorage = <Arc<Data<M>> as Entity>::Storage;\n    type EdgeStorage = <Edge<Data<M>> as Entity>::Storage;\n    type FaceStorage = <Face<Data<M>> as Entity>::Storage;\n}\n\n/// Graph mutation.\npub struct Mutation<P>\nwhere\n    P: Mode,\n    P::Graph: Consistent + From<OwnedCore<Data<P::Graph>>> + Into<OwnedCore<Data<P::Graph>>>,\n{\n    inner: FaceMutation<P>,\n}\n\nimpl<P> AsRef<Self> for Mutation<P>\nwhere\n    P: Mode,\n    P::Graph: Consistent + From<OwnedCore<Data<P::Graph>>> + Into<OwnedCore<Data<P::Graph>>>,\n{\n    fn as_ref(&self) -> &Self {\n        self\n    }\n}\n\nimpl<P> AsMut<Self> for Mutation<P>\nwhere\n    P: Mode,\n    P::Graph: Consistent + From<OwnedCore<Data<P::Graph>>> + Into<OwnedCore<Data<P::Graph>>>,\n{\n    fn as_mut(&mut self) -> &mut Self {\n        self\n    }\n}\n\nimpl<P> AsStorage<Arc<Data<P::Graph>>> for Mutation<P>\nwhere\n    P: Mode,\n    P::Graph: Consistent + From<OwnedCore<Data<P::Graph>>> + Into<OwnedCore<Data<P::Graph>>>,\n{\n    fn as_storage(&self) -> &StorageTarget<Arc<Data<P::Graph>>> {\n        self.inner.to_ref_core().unfuse().1\n    }\n}\n\nimpl<P> AsStorage<Edge<Data<P::Graph>>> for Mutation<P>\nwhere\n    P: Mode,\n    P::Graph: Consistent + From<OwnedCore<Data<P::Graph>>> + Into<OwnedCore<Data<P::Graph>>>,\n{\n    fn as_storage(&self) -> &StorageTarget<Edge<Data<P::Graph>>> {\n        self.inner.to_ref_core().unfuse().2\n    }\n}\n\nimpl<P> AsStorage<Face<Data<P::Graph>>> for Mutation<P>\nwhere\n    P: Mode,\n    P::Graph: Consistent + From<OwnedCore<Data<P::Graph>>> + Into<OwnedCore<Data<P::Graph>>>,\n{\n    fn as_storage(&self) -> &StorageTarget<Face<Data<P::Graph>>> {\n        self.inner.to_ref_core().unfuse().3\n    }\n}\n\nimpl<P> AsStorage<Vertex<Data<P::Graph>>> for Mutation<P>\nwhere\n    P: Mode,\n    P::Graph: Consistent + From<OwnedCore<Data<P::Graph>>> + Into<OwnedCore<Data<P::Graph>>>,\n{\n    fn as_storage(&self) -> &StorageTarget<Vertex<Data<P::Graph>>> {\n        self.inner.to_ref_core().unfuse().0\n    }\n}\n\nimpl<M> Bypass<M> for Mutation<Immediate<M>>\nwhere\n    M: Consistent + From<OwnedCore<Data<M>>> + Parametric + Into<OwnedCore<Data<M>>>,\n{\n    fn bypass(self) -> Self::Commit {\n        self.inner.bypass().into()\n    }\n}\n\n// TODO: This is a hack. Replace this with delegation.\nimpl<P> Deref for Mutation<P>\nwhere\n    P: Mode,\n    P::Graph: Consistent + From<OwnedCore<Data<P::Graph>>> + Into<OwnedCore<Data<P::Graph>>>,\n{\n    type Target = FaceMutation<P>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.inner\n    }\n}\n\nimpl<P> DerefMut for Mutation<P>\nwhere\n    P: Mode,\n    P::Graph: Consistent + From<OwnedCore<Data<P::Graph>>> + Into<OwnedCore<Data<P::Graph>>>,\n{\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.inner\n    }\n}\n\nimpl<M> From<M> for Mutation<Immediate<M>>\nwhere\n    M: Consistent + From<OwnedCore<Data<M>>> + Parametric + Into<OwnedCore<Data<M>>>,\n{\n    fn from(graph: M) -> Self {\n        Mutation {\n            inner: graph.into().into(),\n        }\n    }\n}\n\nimpl<P> Parametric for Mutation<P>\nwhere\n    P: Mode,\n    P::Graph: Consistent + From<OwnedCore<Data<P::Graph>>> + Into<OwnedCore<Data<P::Graph>>>,\n{\n    type Data = Data<P::Graph>;\n}\n\nimpl<M> Transact<M> for Mutation<Immediate<M>>\nwhere\n    M: Consistent + From<OwnedCore<Data<M>>> + Parametric + Into<OwnedCore<Data<M>>>,\n{\n    type Commit = M;\n    type Abort = ();\n    type Error = GraphError;\n\n    fn commit(self) -> Result<Self::Commit, (Self::Abort, Self::Error)> {\n        self.inner.commit().map(|core| core.into())\n    }\n\n    fn abort(self) -> Self::Abort {}\n}\n\npub trait Mutable:\n    Consistent + From<OwnedCore<Data<Self>>> + Parametric + Into<OwnedCore<Data<Self>>>\n{\n}\n\nimpl<M, G> Mutable for M\nwhere\n    M: Consistent + From<OwnedCore<G>> + Parametric<Data = G> + Into<OwnedCore<G>>,\n    G: GraphData,\n{\n}\n"
  },
  {
    "path": "plexus/src/graph/mutation/path.rs",
    "content": "use smallvec::SmallVec;\n\nuse crate::entity::borrow::Reborrow;\nuse crate::entity::storage::AsStorage;\nuse crate::entity::view::Bind;\nuse crate::graph::data::{Data, GraphData, Parametric};\nuse crate::graph::edge::Arc;\nuse crate::graph::face::{Face, FaceKey};\nuse crate::graph::mutation::face::{self, FaceInsertCache};\nuse crate::graph::mutation::vertex;\nuse crate::graph::mutation::{Consistent, Mode, Mutable, Mutation};\nuse crate::graph::path::Path;\nuse crate::graph::vertex::{Vertex, VertexKey, VertexView};\nuse crate::graph::GraphError;\nuse crate::IteratorExt as _;\n\npub struct PathExtrudeCache {\n    // Avoid allocations for single arc extrusions.\n    sources: SmallVec<[VertexKey; 2]>,\n}\n\nimpl PathExtrudeCache {\n    pub fn from_path<B>(path: Path<B>) -> Result<Self, GraphError>\n    where\n        B: Reborrow,\n        B::Target: AsStorage<Arc<Data<B>>>\n            + AsStorage<Face<Data<B>>>\n            + AsStorage<Vertex<Data<B>>>\n            + Consistent\n            + Parametric,\n    {\n        if path.arcs().any(|arc| !arc.is_boundary_arc()) {\n            Err(GraphError::TopologyMalformed)\n        }\n        else {\n            Ok(PathExtrudeCache {\n                sources: path.vertices().keys().collect(),\n            })\n        }\n    }\n}\n\npub fn extrude_contour_with<N, P, F>(\n    mut mutation: N,\n    cache: PathExtrudeCache,\n    f: F,\n) -> Result<FaceKey, GraphError>\nwhere\n    N: AsMut<Mutation<P>>,\n    P: Mode,\n    P::Graph: Mutable,\n    F: Fn(&<Data<P::Graph> as GraphData>::Vertex) -> <Data<P::Graph> as GraphData>::Vertex,\n{\n    let PathExtrudeCache { sources } = cache;\n    let destinations: SmallVec<[_; 2]> = sources\n        .iter()\n        .cloned()\n        .rev()\n        .map(|source| -> Result<_, GraphError> {\n            let vertex =\n                VertexView::bind(mutation.as_mut(), source).ok_or(GraphError::TopologyNotFound)?;\n            let data = f(vertex.get());\n            Ok(vertex::insert(mutation.as_mut(), data))\n        })\n        .collect::<Result<_, _>>()?;\n    let cache =\n        FaceInsertCache::from_storage(mutation.as_mut(), sources.into_iter().chain(destinations))?;\n    face::insert_with(mutation.as_mut(), cache, Default::default)\n}\n"
  },
  {
    "path": "plexus/src/graph/mutation/vertex.rs",
    "content": "use crate::entity::borrow::Reborrow;\nuse crate::entity::storage::prelude::*;\nuse crate::entity::storage::{AsStorage, AsStorageMut, Fuse, StorageTarget};\nuse crate::graph::core::Core;\nuse crate::graph::data::{Data, GraphData, Parametric};\nuse crate::graph::edge::ArcKey;\nuse crate::graph::mutation::edge::{self, EdgeRemoveCache};\nuse crate::graph::mutation::{Consistent, Immediate, Mode, Mutable, Mutation};\nuse crate::graph::vertex::{Vertex, VertexKey, VertexView};\nuse crate::graph::GraphError;\nuse crate::transact::{Bypass, Transact};\n\ntype ModalCore<P> = Core<Data<<P as Mode>::Graph>, <P as Mode>::VertexStorage, (), (), ()>;\ntype RefCore<'a, G> = Core<G, &'a StorageTarget<'a, Vertex<G>>, (), (), ()>;\n\npub struct VertexMutation<P>\nwhere\n    P: Mode,\n{\n    storage: P::VertexStorage,\n}\n\nimpl<P> VertexMutation<P>\nwhere\n    P: Mode,\n{\n    pub fn to_ref_core(&self) -> RefCore<Data<P::Graph>> {\n        Core::empty().fuse(self.storage.as_storage())\n    }\n\n    pub fn connect_outgoing_arc(&mut self, a: VertexKey, ab: ArcKey) -> Result<(), GraphError> {\n        self.with_vertex_mut(a, |vertex| vertex.arc = Some(ab))\n    }\n\n    pub fn disconnect_outgoing_arc(&mut self, a: VertexKey) -> Result<Option<ArcKey>, GraphError> {\n        self.with_vertex_mut(a, |vertex| vertex.arc.take())\n    }\n\n    fn with_vertex_mut<T, F>(&mut self, a: VertexKey, mut f: F) -> Result<T, GraphError>\n    where\n        F: FnMut(&mut Vertex<Data<P::Graph>>) -> T,\n    {\n        let vertex = self\n            .storage\n            .as_storage_mut()\n            .get_mut(&a)\n            .ok_or(GraphError::TopologyNotFound)?;\n        Ok(f(vertex))\n    }\n}\n\nimpl<P> AsStorage<Vertex<Data<P::Graph>>> for VertexMutation<P>\nwhere\n    P: Mode,\n{\n    fn as_storage(&self) -> &StorageTarget<Vertex<Data<P::Graph>>> {\n        self.storage.as_storage()\n    }\n}\n\nimpl<M> Bypass<ModalCore<Immediate<M>>> for VertexMutation<Immediate<M>>\nwhere\n    M: Parametric,\n{\n    fn bypass(self) -> Self::Commit {\n        let VertexMutation {\n            storage: vertices, ..\n        } = self;\n        Core::empty().fuse(vertices)\n    }\n}\n\nimpl<P> From<ModalCore<P>> for VertexMutation<P>\nwhere\n    P: Mode,\n{\n    fn from(core: ModalCore<P>) -> Self {\n        let (vertices, ..) = core.unfuse();\n        VertexMutation { storage: vertices }\n    }\n}\n\nimpl<M> Transact<ModalCore<Immediate<M>>> for VertexMutation<Immediate<M>>\nwhere\n    M: Parametric,\n{\n    type Commit = ModalCore<Immediate<M>>;\n    type Abort = ();\n    type Error = GraphError;\n\n    fn commit(self) -> Result<Self::Commit, (Self::Abort, Self::Error)> {\n        let VertexMutation {\n            storage: vertices, ..\n        } = self;\n        // In a consistent graph, all vertices must have a leading arc.\n        for (_, vertex) in vertices.as_storage().iter() {\n            if vertex.arc.is_none() {\n                return Err(((), GraphError::TopologyMalformed));\n            }\n        }\n        Ok(Core::empty().fuse(vertices))\n    }\n\n    fn abort(self) -> Self::Abort {}\n}\n\npub struct VertexRemoveCache {\n    cache: Vec<EdgeRemoveCache>,\n}\n\nimpl VertexRemoveCache {\n    pub fn from_vertex<B>(vertex: VertexView<B>) -> Result<Self, GraphError>\n    where\n        B: Reborrow,\n        B::Target: AsStorage<Vertex<Data<B>>> + Consistent + Parametric,\n    {\n        let _ = vertex;\n        unimplemented!()\n    }\n}\n\npub fn insert<N, P>(mut mutation: N, data: <Data<P::Graph> as GraphData>::Vertex) -> VertexKey\nwhere\n    N: AsMut<Mutation<P>>,\n    P: Mode,\n    P::Graph: Mutable,\n{\n    mutation\n        .as_mut()\n        .storage\n        .as_storage_mut()\n        .insert(Vertex::new(data))\n}\n\npub fn remove<N, P>(\n    mut mutation: N,\n    cache: VertexRemoveCache,\n) -> Result<Vertex<Data<P::Graph>>, GraphError>\nwhere\n    N: AsMut<Mutation<P>>,\n    P: Mode,\n    P::Graph: Mutable,\n{\n    let VertexRemoveCache { cache } = cache;\n    for cache in cache {\n        edge::remove(mutation.as_mut(), cache)?;\n    }\n    unimplemented!()\n}\n"
  },
  {
    "path": "plexus/src/graph/path.rs",
    "content": "use itertools::Itertools;\nuse std::borrow::{Borrow, Cow};\nuse std::cmp;\nuse std::collections::{HashSet, VecDeque};\n\nuse crate::entity::borrow::{Reborrow, ReborrowInto};\nuse crate::entity::storage::AsStorage;\nuse crate::entity::view::{Bind, ClosedView, Unbind, View};\nuse crate::geometry::Metric;\nuse crate::graph::data::{Data, GraphData, Parametric};\nuse crate::graph::edge::{Arc, ArcKey, ArcView, Edge};\nuse crate::graph::face::{Face, FaceView, Ring};\nuse crate::graph::mutation::path::{self, PathExtrudeCache};\nuse crate::graph::mutation::{self, Consistent, Immediate, Mutable};\nuse crate::graph::vertex::{Vertex, VertexKey, VertexView};\nuse crate::graph::{GraphError, OptionExt as _, ResultExt as _, Selector};\nuse crate::transact::{BypassOrCommit, Mutate};\nuse crate::IteratorExt as _;\n\ntype Mutation<M> = mutation::Mutation<Immediate<M>>;\n\n/// Non-intersecting path.\n///\n/// A path is an ordered set of vertices that are joined by arcs. Paths are\n/// notated as either sequences or sets. An open path over vertices $A$, $B$,\n/// and $C$ is notated $\\overrightarrow{(A,B,C)}$ and a closed path over the\n/// same vertices is notated $\\overrightarrow{\\\\{A,B,C\\\\}}$.\n///\n/// `Path` represents non-intersecting paths of the form\n/// $\\overrightarrow{(A,\\cdots,B)}$, where $A$ is the _back_ of the path and $B$\n/// is the _front_ of the path. Note that closed paths are always of the form\n/// $\\overrightarrow{(A,\\cdots,A)}$, where the back and front vertices are both\n/// $A$ (the same).\n///\n/// `Path` maintains an ordered set of keys and uses copy-on-write semantics to\n/// avoid allocations and copies.\n#[derive(Clone)]\npub struct Path<'k, B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Arc<Data<B>>> + AsStorage<Vertex<Data<B>>> + Consistent + Parametric,\n{\n    keys: Cow<'k, VecDeque<ArcKey>>,\n    storage: B,\n}\n\nimpl<B, M, G> Path<'static, B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    // Paths bind multiple keys to storage and so do not support view APIs.\n    // This bespoke `bind` function ensures that the path is not empty and that\n    // the topology forms a non-intersecting path.\n    pub(in crate::graph) fn bind<I>(storage: B, keys: I) -> Result<Self, GraphError>\n    where\n        I: IntoIterator,\n        I::Item: Borrow<VertexKey>,\n    {\n        let mut keys = keys.into_iter().map(|key| *key.borrow());\n        let a = keys.next().ok_or(GraphError::TopologyMalformed)?;\n        let b = keys.next().ok_or(GraphError::TopologyMalformed)?;\n        let ab = (a, b).into();\n        ArcView::bind(storage.reborrow(), ab).ok_or(GraphError::TopologyNotFound)?;\n        let mut path = Path {\n            keys: Cow::Owned([ab].into_iter().collect()),\n            storage,\n        };\n        for key in keys {\n            path.push_front(key)?;\n        }\n        Ok(path)\n    }\n\n    fn bind_unchecked<I>(storage: B, keys: I) -> Self\n    where\n        I: IntoIterator,\n        I::Item: Borrow<ArcKey>,\n    {\n        let keys = Cow::Owned(keys.into_iter().map(|key| *key.borrow()).collect());\n        Path { keys, storage }\n    }\n}\n\nimpl<B, M, G> Path<'_, B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn to_ref(&self) -> Path<&M> {\n        Path {\n            storage: self.storage.reborrow(),\n            keys: Cow::Borrowed(&self.keys),\n        }\n    }\n\n    /// Converts the path into its opposite path.\n    pub fn into_opposite_path(self) -> Path<'static, B> {\n        let Path { keys, storage } = self;\n        Path::bind_unchecked(\n            storage,\n            keys.iter().cloned().rev().map(|ab| ab.into_opposite()),\n        )\n    }\n\n    /// Gets the opposite path.\n    pub fn opposite_path(&self) -> Path<'static, &M> {\n        self.to_ref().into_opposite_path()\n    }\n\n    /// Pushes a vertex onto the back of the path.\n    ///\n    /// The back of a path $\\overrightarrow{(A,\\cdots)}$ is the vertex $A$.\n    /// This is the source vertex of the first arc that forms the path.\n    ///\n    /// The given vertex must be a source vertex of an arc formed with the back\n    /// of the path. That is, if the given vertex is $X$, then\n    /// $\\overrightarrow{XA}$ must exist.\n    ///\n    /// Returns the key of the arc $\\overrightarrow{XA}$ inserted into the path\n    /// using the given source vertex $X$.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the path is closed, the given vertex is not found,\n    /// or the given vertex does not form an arc with the back of the path.\n    pub fn push_back(\n        &mut self,\n        destination: impl Into<Selector<VertexKey>>,\n    ) -> Result<ArcKey, GraphError> {\n        if self.is_closed() {\n            return Err(GraphError::TopologyMalformed);\n        }\n        let back = self.back();\n        let xa = match destination.into() {\n            Selector::ByKey(key) => back\n                .incoming_arcs()\n                .find(|arc| arc.into_source_vertex().key() == key)\n                .ok_or(GraphError::TopologyMalformed)?\n                .key(),\n            Selector::ByIndex(index) => {\n                let x = back\n                    .adjacent_vertices()\n                    .keys()\n                    .nth(index)\n                    .ok_or(GraphError::TopologyNotFound)?;\n                (x, back.key()).into()\n            }\n        };\n        let (x, _) = xa.into();\n        // Do not allow intersections unless they form a loop with the first\n        // vertex in the path (this iteration skips the vertex at the front of\n        // the path).\n        let is_intersecting = self\n            .arcs()\n            .map(|arc| arc.into_source_vertex())\n            .keys()\n            .any(|key| key == x);\n        if is_intersecting {\n            Err(GraphError::TopologyMalformed)\n        }\n        else {\n            self.keys.to_mut().push_back(xa);\n            Ok(xa)\n        }\n    }\n\n    /// Pushes the source vertex of the previous arc onto the back of the path.\n    pub fn push_previous_arc(&mut self) -> Result<ArcKey, GraphError> {\n        let key = *self.keys.to_mut().back().expect(\"empty path\");\n        let key = ArcView::from(View::bind_unchecked(self.storage.reborrow(), key))\n            .into_previous_arc()\n            .into_source_vertex()\n            .key();\n        self.push_back(key)\n    }\n\n    /// Pops a vertex from the back of the path.\n    pub fn pop_back(&mut self) -> Option<ArcKey> {\n        // Empty paths are forbidden.\n        if self.keys.len() > 1 {\n            self.keys.to_mut().pop_back()\n        }\n        else {\n            None\n        }\n    }\n\n    /// Pushes a vertex onto the front of the path.\n    ///\n    /// The front of a path $\\overrightarrow{(\\cdots,B)}$ is the vertex $B$.\n    /// This is the destination vertex of the last arc that forms the path.\n    ///\n    /// The given vertex must be a destination vertex of an arc formed with the\n    /// front of the path.  That is, if the given vertex is $X$, then\n    /// $\\overrightarrow{BX}$ must exist.\n    ///\n    /// Returns the key of the arc $\\overrightarrow{BX}$ inserted into the path\n    /// using the given source vertex $X$.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the path is closed, the given vertex is not found,\n    /// or the given vertex does not form an arc with the front of the path.\n    pub fn push_front(\n        &mut self,\n        destination: impl Into<Selector<VertexKey>>,\n    ) -> Result<ArcKey, GraphError> {\n        if self.is_closed() {\n            return Err(GraphError::TopologyMalformed);\n        }\n        let front = self.front();\n        let bx = match destination.into() {\n            Selector::ByKey(key) => front\n                .outgoing_arcs()\n                .find(|arc| arc.into_destination_vertex().key() == key)\n                .ok_or(GraphError::TopologyMalformed)?\n                .key(),\n            Selector::ByIndex(index) => {\n                let x = front\n                    .adjacent_vertices()\n                    .keys()\n                    .nth(index)\n                    .ok_or(GraphError::TopologyNotFound)?;\n                (front.key(), x).into()\n            }\n        };\n        let (_, x) = bx.into();\n        // Do not allow intersections unless they form a loop with the first\n        // vertex in the path (this iteration skips the vertex at the back of\n        // the path).\n        let is_intersecting = self\n            .arcs()\n            .map(|arc| arc.into_destination_vertex())\n            .keys()\n            .any(|key| key == x);\n        if is_intersecting {\n            Err(GraphError::TopologyMalformed)\n        }\n        else {\n            self.keys.to_mut().push_front(bx);\n            Ok(bx)\n        }\n    }\n\n    /// Pushes the destination vertex of the next arc onto the front of the\n    /// path.\n    pub fn push_next_arc(&mut self) -> Result<ArcKey, GraphError> {\n        let key = *self.keys.front().expect(\"empty path\");\n        let key = ArcView::from(View::bind_unchecked(self.storage.reborrow(), key))\n            .into_next_arc()\n            .into_destination_vertex()\n            .key();\n        self.push_front(key)\n    }\n\n    /// Pops a vertex from the front of the path.\n    pub fn pop_front(&mut self) -> Option<ArcKey> {\n        // Empty paths are forbidden.\n        if self.keys.len() > 1 {\n            self.keys.to_mut().pop_front()\n        }\n        else {\n            None\n        }\n    }\n\n    /// Gets the vertex at the back of the path.\n    pub fn back(&self) -> VertexView<&M> {\n        let (key, _) = self.terminals();\n        View::<_, Vertex<_>>::bind_unchecked(self.storage.reborrow(), key).into()\n    }\n\n    /// Gets the vertex at the front of the path.\n    pub fn front(&self) -> VertexView<&M> {\n        let (_, key) = self.terminals();\n        View::<_, Vertex<_>>::bind_unchecked(self.storage.reborrow(), key).into()\n    }\n\n    pub fn shortest_metric_with<Q, F>(\n        &self,\n        from: impl Into<Selector<VertexKey>>,\n        to: impl Into<Selector<VertexKey>>,\n        f: F,\n    ) -> Result<Q, GraphError>\n    where\n        Q: Metric,\n        F: Fn(VertexView<&M>, VertexView<&M>) -> Q,\n    {\n        self.shortest_subpath_terminals(from, to).map(|(from, to)| {\n            // A cycle is needed for closed paths. Note that if the path is\n            // open, then the vertex keys must not wrap over the terminals here.\n            truncate(self.arcs().cycle(), from, to).fold(Q::zero(), |metric, arc| {\n                metric + f(arc.source_vertex(), arc.destination_vertex())\n            })\n        })\n    }\n\n    /// Returns `true` if the path is open.\n    ///\n    /// An _open path_ is a path that terminates and does **not** form a loop.\n    pub fn is_open(&self) -> bool {\n        !self.is_closed()\n    }\n\n    /// Returns `true` if the path is closed.\n    ///\n    /// A _closed path_ is a path that forms a loop by starting and ending at\n    /// the same vertex.\n    pub fn is_closed(&self) -> bool {\n        let (a, b) = self.terminals();\n        a == b\n    }\n\n    fn terminals(&self) -> (VertexKey, VertexKey) {\n        let (a, _) = self.keys.back().cloned().expect(\"empty path\").into();\n        let (_, b) = self.keys.front().cloned().expect(\"empty path\").into();\n        (a, b)\n    }\n\n    fn shortest_subpath_terminals(\n        &self,\n        from: impl Into<Selector<VertexKey>>,\n        to: impl Into<Selector<VertexKey>>,\n    ) -> Result<(VertexKey, VertexKey), GraphError> {\n        let index_key = |selector| {\n            match selector {\n                Selector::ByKey(key) => self\n                    .vertices()\n                    .find_position(|vertex| vertex.key() == key)\n                    .map(|(index, _)| (index, key)),\n                Selector::ByIndex(index) => self\n                    .vertices()\n                    .nth(index)\n                    .map(|vertex| (index, vertex.key())),\n            }\n            .ok_or(GraphError::TopologyNotFound)\n        };\n        let (i, from) = index_key(from.into())?;\n        let (j, to) = index_key(to.into())?;\n        if self.is_open() {\n            // Reorder the vertex keys if they oppose the direction of the open\n            // path.\n            Ok(if i > j { (to, from) } else { (from, to) })\n        }\n        else {\n            // Reorder the vertex keys if they form the longer closed path.\n            let n = self.keys.len() / 2;\n            Ok(if (cmp::max(i, j) - cmp::min(i, j)) > n {\n                (to, from)\n            }\n            else {\n                (from, to)\n            })\n        }\n    }\n}\n\nimpl<'k, 'a, B, M, G> Path<'k, B>\nwhere\n    B: ReborrowInto<'a, Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    /// Converts a mutable view into an immutable view.\n    pub fn into_ref(self) -> Path<'k, &'a M> {\n        let Path { keys, storage, .. } = self;\n        Path {\n            keys,\n            storage: storage.reborrow_into(),\n        }\n    }\n\n    /// Splits the path into two immutable paths at the given vertex.\n    ///\n    /// Given a path $\\overrightarrow{(A,\\cdots,M,\\cdots,B)}$, splitting at the\n    /// vertex $M$ results in the paths $\\overrightarrow{(A,\\cdots,M)}$ and\n    /// $\\overrightarrow{(M,\\cdots,B)}$.\n    ///\n    /// **Splitting a path does not mutate its graph in any way** (unlike\n    /// [`ArcView::split_with`] or [`FaceView::split`], for example). To split a\n    /// graph along a path (and thus mutate the graph) use\n    /// [`MeshGraph::split_at_path`].\n    ///\n    /// It is not possible to split a path at its back or front vertices.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the given vertex cannot be found or the path cannot\n    /// be split at that vertex.\n    ///\n    /// [`ArcView::split_with`]: crate::graph::ArcView::split_with\n    /// [`FaceView::split`]: crate::graph::FaceView::split\n    /// [`MeshGraph::split_at_path`]: crate::graph::MeshGraph::split_at_path\n    pub fn split(\n        self,\n        at: impl Into<Selector<VertexKey>>,\n    ) -> Result<(Path<'static, &'a M>, Path<'static, &'a M>), GraphError> {\n        let index = at.into().index_or_else(|key| {\n            self.vertices()\n                .keys()\n                .enumerate()\n                .find(|(_, a)| *a == key)\n                .map(|(n, _)| n)\n                .ok_or(GraphError::TopologyNotFound)\n        })?;\n        if index == 0 || index >= self.keys.len() {\n            return Err(GraphError::TopologyMalformed);\n        }\n        let Path { keys, storage, .. } = self.into_ref();\n        let mut right = keys.into_owned();\n        let left = right.split_off(index);\n        Ok((\n            Path {\n                keys: Cow::Owned(left),\n                storage,\n            },\n            Path {\n                keys: Cow::Owned(right),\n                storage,\n            },\n        ))\n    }\n}\n\nimpl<B, G> Path<'_, B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    /// Gets an iterator over the vertices in the path.\n    pub fn vertices(&self) -> impl Clone + Iterator<Item = VertexView<&B::Target>> {\n        let (key, _) = self.terminals();\n        Some(key)\n            .into_iter()\n            .chain(self.keys.iter().cloned().rev().map(|key| {\n                let (_, key) = key.into();\n                key\n            }))\n            .map(move |key| View::bind_unchecked(self.storage.reborrow(), key))\n            .map(From::from)\n    }\n\n    /// Gets an iterator over the arcs in the path.\n    pub fn arcs(&self) -> impl Clone + ExactSizeIterator<Item = ArcView<&B::Target>> {\n        self.keys\n            .iter()\n            .rev()\n            .cloned()\n            .map(move |key| View::bind_unchecked(self.storage.reborrow(), key))\n            .map(From::from)\n    }\n}\n\nimpl<'a, M, G> Path<'_, &'a mut M>\nwhere\n    M: AsStorage<Arc<G>>\n        + AsStorage<Edge<G>>\n        + AsStorage<Face<G>>\n        + AsStorage<Vertex<G>>\n        + Default\n        + Mutable<Data = G>,\n    G: GraphData,\n{\n    /// Extrudes the contour of a boundary path.\n    ///\n    /// A path is a boundary path if all of its arcs are boundary arcs.\n    /// Extruding the path transforms the vertices along the path in order using\n    /// the given function and inserts a face between the path and its extruded\n    /// contour.\n    ///\n    /// Unlike extruding individual arcs, extruding the contour of a path\n    /// inserts a single face in which all involved arcs participate.\n    ///\n    /// Returns the inserted face.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the path is not a boundary path.\n    pub fn extrude_contour_with<F>(self, f: F) -> Result<FaceView<&'a mut M>, GraphError>\n    where\n        F: Fn(&G::Vertex) -> G::Vertex,\n    {\n        let cache = PathExtrudeCache::from_path(self.to_ref())?;\n        let Path { storage, .. } = self;\n        Ok(Mutation::take(storage)\n            .bypass_or_commit_with(|mutation| path::extrude_contour_with(mutation, cache, f))\n            .map(|(storage, face)| Bind::bind(storage, face).expect_consistent())\n            .map_err(|(_, error)| error)\n            .expect_consistent())\n    }\n\n    /// Extrudes the surface of a closed path.\n    pub fn extrude_surface_with<F>(self, f: F) -> Result<Self, GraphError>\n    where\n        F: Fn(G::Vertex) -> G::Vertex,\n    {\n        let _ = f;\n        todo!()\n    }\n}\n\nimpl<B, M, G> From<Ring<B>> for Path<'static, B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn from(ring: Ring<B>) -> Self {\n        let keys = Cow::Owned(ring.arcs().keys().collect());\n        let (storage, _) = ring.into_arc().unbind();\n        Path { keys, storage }\n    }\n}\n\nimpl<B, M, G> PartialEq for Path<'_, B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn eq(&self, other: &Self) -> bool {\n        let keys = |path: &Self| path.keys.iter().cloned().collect::<HashSet<_>>();\n        keys(self) == keys(other)\n    }\n}\n\nfn truncate<T>(\n    arcs: impl IntoIterator<Item = T>,\n    from: VertexKey,\n    to: VertexKey,\n) -> impl Iterator<Item = T>\nwhere\n    T: Borrow<ArcKey> + Copy,\n{\n    arcs.into_iter()\n        .map(|arc| (arc, (*arc.borrow()).into()))\n        .skip_while(move |(_, (a, _))| *a != from)\n        .take_while(move |(_, (a, _))| *a != to)\n        .map(|(arc, _)| arc)\n}\n\n#[cfg(test)]\nmod tests {\n    use nalgebra::Point2;\n\n    use crate::graph::{ClosedView, MeshGraph};\n    use crate::prelude::*;\n    use crate::primitive::{Tetragon, Trigon};\n    use crate::IteratorExt;\n\n    type E2 = Point2<f64>;\n\n    #[test]\n    fn open_close() {\n        let graph = MeshGraph::<E2>::from_raw_buffers(\n            vec![Trigon::from([0usize, 1, 2])],\n            vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0)],\n        )\n        .unwrap();\n        let keys = graph\n            .faces()\n            .next()\n            .unwrap()\n            .adjacent_arcs()\n            .map(|arc| arc.into_source_vertex())\n            .keys()\n            .collect::<Vec<_>>();\n\n        let mut path = graph.path(keys.iter()).unwrap();\n        assert!(path.is_open());\n        // TODO: Move this assertion to a distinct test.\n        assert_eq!(path.vertices().keys().collect::<Vec<_>>(), keys.to_vec());\n\n        path.push_front(keys[0]).unwrap();\n        assert!(path.is_closed());\n        assert_eq!(path.front().key(), path.back().key());\n    }\n\n    #[test]\n    fn logical_metrics() {\n        let graph = MeshGraph::<E2>::from_raw_buffers(\n            vec![Tetragon::from([0usize, 1, 2, 3])],\n            vec![(1.0, 1.0), (-1.0, 1.0), (-1.0, -1.0), (1.0, -1.0)],\n        )\n        .unwrap();\n        let path = {\n            let key = graph.faces().next().unwrap().key();\n            graph.face(key).unwrap().into_ring().into_path()\n        };\n        let keys: Vec<_> = path.vertices().keys().collect();\n\n        assert_eq!(0, path.shortest_metric_with(0, 0, |_, _| 1usize).unwrap());\n        assert_eq!(\n            0,\n            path.shortest_metric_with(keys[0], keys[0], |_, _| 1usize)\n                .unwrap()\n        );\n        assert_eq!(1, path.shortest_metric_with(0, 3, |_, _| 1usize).unwrap());\n        assert_eq!(\n            2,\n            path.shortest_metric_with(keys[3], keys[1], |_, _| 1usize)\n                .unwrap()\n        );\n    }\n\n    #[test]\n    fn split() {\n        let graph =\n            MeshGraph::<()>::from_raw_buffers(vec![Tetragon::from([0usize, 1, 2, 3])], vec![(); 4])\n                .unwrap();\n        let source = graph.vertices().next().unwrap();\n        let destination = source\n            .into_outgoing_arc()\n            .into_next_arc()\n            .into_destination_vertex();\n\n        let path = source.shortest_path(destination.key()).unwrap();\n        assert_eq!(path.arcs().count(), 2);\n\n        let (left, right) = path.split(1).unwrap();\n        assert_eq!(left.front().key(), right.back().key());\n        assert_eq!(left.arcs().count(), 1);\n        assert_eq!(right.arcs().count(), 1);\n    }\n}\n"
  },
  {
    "path": "plexus/src/graph/vertex.rs",
    "content": "use derivative::Derivative;\nuse smallvec::SmallVec;\nuse std::borrow::Borrow;\nuse std::hash::{Hash, Hasher};\nuse std::ops::{Deref, DerefMut};\nuse theon::space::Vector;\nuse theon::AsPosition;\n\nuse crate::entity::borrow::{Reborrow, ReborrowInto, ReborrowMut};\nuse crate::entity::dijkstra;\nuse crate::entity::storage::prelude::*;\nuse crate::entity::storage::{\n    AsStorage, AsStorageMut, AsStorageOf, HashStorage, IncrementalKeyer, Key,\n};\nuse crate::entity::traverse::{Adjacency, Breadth, Depth, Trace, TraceAny, TraceFirst, Traversal};\nuse crate::entity::view::{ClosedView, Orphan, Rebind, Unbind, View};\nuse crate::entity::{Entity, Payload};\nuse crate::geometry::Metric;\nuse crate::graph::data::{Data, GraphData, Parametric};\nuse crate::graph::edge::{Arc, ArcKey, ArcOrphan, ArcView, Edge};\nuse crate::graph::face::{Face, FaceOrphan, FaceView};\nuse crate::graph::geometry::{VertexCentroid, VertexNormal, VertexPosition};\nuse crate::graph::mutation::vertex::{self, VertexRemoveCache};\nuse crate::graph::mutation::{self, Consistent, Immediate, Mutable};\nuse crate::graph::path::Path;\nuse crate::graph::{\n    Circulator, GraphError, OptionExt as _, OrphanCirculator, ResultExt as _, ViewCirculator,\n};\nuse crate::transact::{BypassOrCommit, Mutate};\nuse crate::IteratorExt as _;\n\ntype Mutation<M> = mutation::Mutation<Immediate<M>>;\n\n/// Vertex entity.\n#[derive(Derivative)]\n#[derivative(Debug, Hash)]\npub struct Vertex<G>\nwhere\n    G: GraphData,\n{\n    /// User data.\n    #[derivative(Debug = \"ignore\", Hash = \"ignore\")]\n    pub(crate) data: G::Vertex,\n    /// Required key into the leading arc.\n    pub(crate) arc: Option<ArcKey>,\n}\n\nimpl<G> Vertex<G>\nwhere\n    G: GraphData,\n{\n    pub fn new(data: G::Vertex) -> Self {\n        Vertex { data, arc: None }\n    }\n}\n\nimpl<G> Entity for Vertex<G>\nwhere\n    G: GraphData,\n{\n    type Key = VertexKey;\n    type Storage = HashStorage<Self, IncrementalKeyer>;\n}\n\nimpl<G> Payload for Vertex<G>\nwhere\n    G: GraphData,\n{\n    type Data = G::Vertex;\n\n    fn get(&self) -> &Self::Data {\n        &self.data\n    }\n\n    fn get_mut(&mut self) -> &mut Self::Data {\n        &mut self.data\n    }\n}\n\n/// Vertex key.\n#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]\npub struct VertexKey(u64);\n\nimpl Key for VertexKey {\n    type Inner = u64;\n\n    fn from_inner(key: Self::Inner) -> Self {\n        VertexKey(key)\n    }\n\n    fn into_inner(self) -> Self::Inner {\n        self.0\n    }\n}\n\n/// View of a vertex entity.\n///\n/// See the [`graph`] module documentation for more information about views.\n///\n/// [`graph`]: crate::graph\npub struct VertexView<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Vertex<Data<B>>> + Parametric,\n{\n    inner: View<B, Vertex<Data<B>>>,\n}\n\nimpl<B, M> VertexView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Vertex<Data<B>>> + Parametric,\n{\n    pub fn to_ref(&self) -> VertexView<&M> {\n        self.inner.to_ref().into()\n    }\n}\n\nimpl<B, M> VertexView<B>\nwhere\n    B: ReborrowMut<Target = M>,\n    M: AsStorage<Vertex<Data<B>>> + Parametric,\n{\n    // LINT: This convention is specifically used for interior reborrows and is consistent with\n    //       `to_ref`.\n    #[expect(clippy::wrong_self_convention)]\n    fn to_mut_unchecked(&mut self) -> VertexView<&mut M> {\n        self.inner.to_mut_unchecked().into()\n    }\n}\n\nimpl<'a, B, M, G> VertexView<B>\nwhere\n    B: ReborrowInto<'a, Target = M>,\n    M: AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    // TODO: Relocate this documentation of `into_ref`.\n    /// # Examples\n    ///\n    /// ```rust\n    /// # extern crate decorum;\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use decorum::R64;\n    /// use nalgebra::Point3;\n    /// use plexus::graph::MeshGraph;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::cube::Cube;\n    /// use plexus::primitive::generate::Position;\n    ///\n    /// type E3 = Point3<R64>;\n    ///\n    /// let mut graph: MeshGraph<E3> = Cube::new().polygons::<Position<E3>>().collect();\n    /// let key = graph.arcs().next().unwrap().key();\n    /// let vertex = graph.arc_mut(key).unwrap().split_at_midpoint().into_ref();\n    ///\n    /// // This would not be possible without conversion into an immutable view.\n    /// let _ = vertex.into_outgoing_arc().into_face().unwrap();\n    /// let _ = vertex\n    ///     .into_outgoing_arc()\n    ///     .into_opposite_arc()\n    ///     .into_face()\n    ///     .unwrap();\n    /// ```\n    pub fn into_ref(self) -> VertexView<&'a M> {\n        self.inner.into_ref().into()\n    }\n}\n\nimpl<B, M, G> VertexView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn get<'a>(&'a self) -> &'a G::Vertex\n    where\n        G: 'a,\n    {\n        self.inner.get()\n    }\n\n    pub fn position<'a>(&'a self) -> &'a VertexPosition<G>\n    where\n        G: 'a,\n        G::Vertex: AsPosition,\n    {\n        self.data.as_position()\n    }\n}\n\nimpl<B, M, G> VertexView<B>\nwhere\n    B: ReborrowMut<Target = M>,\n    M: AsStorageMut<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn get_mut<'a>(&'a mut self) -> &'a mut G::Vertex\n    where\n        G: 'a,\n    {\n        self.inner.get_mut()\n    }\n}\n\n/// Reachable API.\nimpl<B, M, G> VertexView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub(in crate::graph) fn into_reachable_outgoing_arc(self) -> Option<ArcView<B>> {\n        let key = self.arc;\n        key.and_then(|key| self.rebind(key))\n    }\n}\n\nimpl<B, M, G> VertexView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    /// Converts the vertex into its outgoing (leading) arc.\n    pub fn into_outgoing_arc(self) -> ArcView<B> {\n        self.into_reachable_outgoing_arc().expect_consistent()\n    }\n\n    /// Gets the outgoing (leading) arc of the vertex.\n    pub fn outgoing_arc(&self) -> ArcView<&M> {\n        self.to_ref().into_outgoing_arc()\n    }\n\n    pub fn shortest_path(&self, key: VertexKey) -> Result<Path<'static, &M>, GraphError> {\n        self.to_ref().into_shortest_path(key)\n    }\n\n    pub fn into_shortest_path(self, key: VertexKey) -> Result<Path<'static, B>, GraphError> {\n        self.into_shortest_path_with(key, |_, _| 1usize)\n    }\n\n    pub fn shortest_path_with<Q, F>(\n        &self,\n        key: VertexKey,\n        f: F,\n    ) -> Result<Path<'static, &M>, GraphError>\n    where\n        Q: Copy + Metric,\n        F: Fn(VertexView<&M>, VertexView<&M>) -> Q,\n    {\n        self.to_ref().into_shortest_path_with(key, f)\n    }\n\n    pub fn into_shortest_path_with<Q, F>(\n        self,\n        mut key: VertexKey,\n        f: F,\n    ) -> Result<Path<'static, B>, GraphError>\n    where\n        Q: Copy + Metric,\n        F: Fn(VertexView<&M>, VertexView<&M>) -> Q,\n    {\n        let metrics = dijkstra::metrics_with(self.to_ref(), Some(key), f)?;\n        let mut keys = vec![key];\n        while let Some((Some(previous), _)) = metrics.get(&key) {\n            key = *previous;\n            keys.push(key);\n        }\n        if keys.len() < 2 {\n            return Err(GraphError::TopologyUnreachable);\n        }\n        let (storage, _) = self.unbind();\n        Path::bind(storage, keys.iter().rev())\n    }\n\n    /// Gets the valence of the vertex.\n    ///\n    /// A vertex's _valence_ is the number of adjacent vertices to which it is\n    /// connected by arcs. The valence of a vertex is the same as its _degree_,\n    /// which is the number of edges to which the vertex is connected.\n    pub fn valence(&self) -> usize {\n        self.adjacent_vertices().count()\n    }\n\n    pub fn centroid(&self) -> VertexPosition<G>\n    where\n        G: VertexCentroid,\n        G::Vertex: AsPosition,\n    {\n        <G as VertexCentroid>::centroid(self.to_ref()).expect_consistent()\n    }\n}\n\nimpl<B, M, G> VertexView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>>\n        + AsStorage<Face<G>>\n        + AsStorage<Vertex<G>>\n        + Consistent\n        + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn normal(&self) -> Result<Vector<VertexPosition<G>>, GraphError>\n    where\n        G: VertexNormal,\n        G::Vertex: AsPosition,\n    {\n        <G as VertexNormal>::normal(self.to_ref())\n    }\n}\n\n/// Reachable API.\nimpl<'a, B, M, G> VertexView<B>\nwhere\n    B: ReborrowInto<'a, Target = M>,\n    M: 'a + AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub(in crate::graph) fn into_reachable_incoming_arcs(\n        self,\n    ) -> impl Clone + Iterator<Item = ArcView<&'a M>> {\n        // This reachable circulator is needed for face insertions.\n        ArcCirculator::<TraceAny<_>, _>::from(self.into_ref())\n    }\n\n    pub(in crate::graph) fn into_reachable_outgoing_arcs(\n        self,\n    ) -> impl Clone + Iterator<Item = ArcView<&'a M>> {\n        // This reachable circulator is needed for face insertions.\n        self.into_reachable_incoming_arcs()\n            .flat_map(|arc| arc.into_reachable_opposite_arc())\n    }\n}\n\n/// Reachable API.\nimpl<B, G> VertexView<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub(in crate::graph) fn reachable_incoming_arcs(\n        &self,\n    ) -> impl Clone + Iterator<Item = ArcView<&B::Target>> {\n        self.to_ref().into_reachable_incoming_arcs()\n    }\n\n    pub(in crate::graph) fn reachable_outgoing_arcs(\n        &self,\n    ) -> impl Clone + Iterator<Item = ArcView<&B::Target>> {\n        self.to_ref().into_reachable_outgoing_arcs()\n    }\n}\n\nimpl<'a, B, M, G> VertexView<B>\nwhere\n    B: ReborrowInto<'a, Target = M>,\n    M: 'a + AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn into_adjacent_vertices(self) -> impl Clone + Iterator<Item = VertexView<&'a M>> {\n        VertexCirculator::from(ArcCirculator::<TraceFirst<_>, _>::from(self.into_ref()))\n    }\n\n    pub fn into_incoming_arcs(self) -> impl Clone + Iterator<Item = ArcView<&'a M>> {\n        ArcCirculator::<TraceFirst<_>, _>::from(self.into_ref())\n    }\n\n    pub fn into_outgoing_arcs(self) -> impl Clone + Iterator<Item = ArcView<&'a M>> {\n        self.into_incoming_arcs().map(|arc| arc.into_opposite_arc())\n    }\n}\n\nimpl<B, G> VertexView<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn adjacent_vertices(&self) -> impl Clone + Iterator<Item = VertexView<&B::Target>> {\n        self.to_ref().into_adjacent_vertices()\n    }\n\n    /// Gets an iterator of views over the incoming arcs of the vertex.\n    ///\n    /// The ordering of arcs is deterministic and is based on the leading arc of\n    /// the vertex.\n    pub fn incoming_arcs(&self) -> impl Clone + Iterator<Item = ArcView<&B::Target>> {\n        self.to_ref().into_incoming_arcs()\n    }\n\n    /// Gets an iterator of views over the outgoing arcs of the vertex.\n    ///\n    /// The ordering of arcs is deterministic and is based on the leading arc of\n    /// the vertex.\n    pub fn outgoing_arcs(&self) -> impl Clone + Iterator<Item = ArcView<&B::Target>> {\n        self.to_ref().into_outgoing_arcs()\n    }\n\n    /// Gets an iterator that traverses adjacent vertices by breadth.\n    ///\n    /// The traversal moves from the vertex to its adjacent vertices and so on.\n    /// If there are disjoint subgraphs in the graph, then a traversal will not\n    /// reach every vertex in the graph.\n    pub fn traverse_by_breadth(&self) -> impl Clone + Iterator<Item = VertexView<&B::Target>> {\n        Traversal::<_, _, Breadth>::from(self.to_ref())\n    }\n\n    /// Gets an iterator that traverses adjacent vertices by depth.\n    ///\n    /// The traversal moves from the vertex to its adjacent vertices and so on.\n    /// If there are disjoint subgraphs in the graph, then a traversal will not\n    /// reach every vertex in the graph.\n    pub fn traverse_by_depth(&self) -> impl Clone + Iterator<Item = VertexView<&B::Target>> {\n        Traversal::<_, _, Depth>::from(self.to_ref())\n    }\n}\n\nimpl<'a, B, M, G> VertexView<B>\nwhere\n    B: ReborrowInto<'a, Target = M>,\n    M: 'a\n        + AsStorage<Arc<G>>\n        + AsStorage<Face<G>>\n        + AsStorage<Vertex<G>>\n        + Consistent\n        + Parametric<Data = G>,\n    G: GraphData,\n{\n    pub fn into_adjacent_faces(self) -> impl Clone + Iterator<Item = FaceView<&'a M>> {\n        FaceCirculator::from(ArcCirculator::<TraceFirst<_>, _>::from(self.into_ref()))\n    }\n}\n\nimpl<B, G> VertexView<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Arc<G>>\n        + AsStorage<Face<G>>\n        + AsStorage<Vertex<G>>\n        + Consistent\n        + Parametric<Data = G>,\n    G: GraphData,\n{\n    /// Gets an iterator of views over the adjacent faces of the vertex.\n    ///\n    /// The ordering of faces is deterministic and is based on the leading arc\n    /// of the vertex.\n    pub fn adjacent_faces(&self) -> impl Clone + Iterator<Item = FaceView<&B::Target>> {\n        self.to_ref().into_adjacent_faces()\n    }\n}\n\nimpl<'a, M> VertexView<&'a mut M>\nwhere\n    M: AsStorage<Arc<M::Data>> + AsStorageMut<Vertex<M::Data>> + Consistent + Parametric,\n{\n    pub fn into_adjacent_vertex_orphans(self) -> impl Iterator<Item = VertexOrphan<'a, M::Data>> {\n        VertexCirculator::from(ArcCirculator::<TraceFirst<_>, _>::from(self))\n    }\n}\n\nimpl<B> VertexView<B>\nwhere\n    B: ReborrowMut,\n    B::Target: AsStorage<Arc<Data<B>>> + AsStorageMut<Vertex<Data<B>>> + Consistent + Parametric,\n{\n    pub fn adjacent_vertex_orphans(&mut self) -> impl Iterator<Item = VertexOrphan<Data<B>>> {\n        self.to_mut_unchecked().into_adjacent_vertex_orphans()\n    }\n}\n\nimpl<'a, M> VertexView<&'a mut M>\nwhere\n    M: AsStorageMut<Arc<M::Data>> + AsStorage<Vertex<M::Data>> + Consistent + Parametric,\n{\n    pub fn into_incoming_arc_orphans(self) -> impl Iterator<Item = ArcOrphan<'a, M::Data>> {\n        ArcCirculator::<TraceFirst<_>, _>::from(self)\n    }\n}\n\nimpl<B> VertexView<B>\nwhere\n    B: ReborrowMut,\n    B::Target: AsStorageMut<Arc<Data<B>>> + AsStorage<Vertex<Data<B>>> + Consistent + Parametric,\n{\n    /// Gets an iterator of orphan views over the incoming arcs of the vertex.\n    ///\n    /// The ordering of arcs is deterministic and is based on the leading arc of\n    /// the vertex.\n    pub fn incoming_arc_orphans(&mut self) -> impl Iterator<Item = ArcOrphan<Data<B>>> {\n        self.to_mut_unchecked().into_incoming_arc_orphans()\n    }\n}\n\nimpl<'a, M> VertexView<&'a mut M>\nwhere\n    M: AsStorage<Arc<M::Data>>\n        + AsStorageMut<Face<M::Data>>\n        + AsStorage<Vertex<M::Data>>\n        + Consistent\n        + Parametric,\n{\n    pub fn into_adjacent_face_orphans(self) -> impl Iterator<Item = FaceOrphan<'a, M::Data>> {\n        FaceCirculator::from(ArcCirculator::<TraceFirst<_>, _>::from(self))\n    }\n}\n\nimpl<B> VertexView<B>\nwhere\n    B: ReborrowMut,\n    B::Target: AsStorage<Arc<Data<B>>>\n        + AsStorageMut<Face<Data<B>>>\n        + AsStorage<Vertex<Data<B>>>\n        + Consistent\n        + Parametric,\n{\n    /// Gets an iterator of orphan views over the adjacent faces of the vertex.\n    ///\n    /// The ordering of faces is deterministic and is based on the leading arc\n    /// of the vertex.\n    pub fn adjacent_face_orphans(&mut self) -> impl Iterator<Item = FaceOrphan<Data<B>>> {\n        self.to_mut_unchecked().into_adjacent_face_orphans()\n    }\n}\n\nimpl<M, G> VertexView<&'_ mut M>\nwhere\n    M: AsStorage<Arc<G>>\n        + AsStorage<Edge<G>>\n        + AsStorage<Face<G>>\n        + AsStorage<Vertex<G>>\n        + Default\n        + Mutable<Data = G>,\n    G: GraphData,\n{\n    // TODO: This is not yet implemented, so examples use `no_run`. Run these\n    //       examples in doc tests once this no longer intentionally panics.\n    /// Removes the vertex.\n    ///\n    /// Any and all dependent entities are also removed, such as arcs and edges\n    /// connected to the vertex, faces connected to such arcs, vertices with no\n    /// remaining leading arc, etc.\n    ///\n    /// Vertex removal is the most destructive removal, because vertices are a\n    /// dependency of all other entities.\n    ///\n    /// # Examples\n    ///\n    /// Removing a corner from a cube by removing its vertex:\n    ///\n    /// ```rust,no_run\n    /// # extern crate decorum;\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use decorum::R64;\n    /// use nalgebra::Point3;\n    /// use plexus::graph::MeshGraph;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::cube::Cube;\n    /// use plexus::primitive::generate::Position;\n    ///\n    /// type E3 = Point3<R64>;\n    ///\n    /// let mut graph: MeshGraph<E3> = Cube::new().polygons::<Position<E3>>().collect();\n    /// let key = graph.vertices().next().unwrap().key();\n    /// graph.vertex_mut(key).unwrap().remove();\n    /// ```\n    pub fn remove(self) {\n        // This should never fail here.\n        let cache = VertexRemoveCache::from_vertex(self.to_ref()).expect_consistent();\n        let (storage, _) = self.unbind();\n        Mutation::take(storage)\n            .bypass_or_commit_with(|mutation| vertex::remove(mutation, cache))\n            .map(|_| ())\n            .map_err(|(_, error)| error)\n            .expect_consistent()\n    }\n}\n\nimpl<B, M, G> Adjacency for VertexView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Output = SmallVec<[Self::Key; 8]>;\n\n    fn adjacency(&self) -> Self::Output {\n        self.adjacent_vertices().keys().collect()\n    }\n}\n\nimpl<B> Borrow<VertexKey> for VertexView<B>\nwhere\n    B: Reborrow,\n    B::Target: AsStorage<Vertex<Data<B>>> + Parametric,\n{\n    fn borrow(&self) -> &VertexKey {\n        self.inner.as_ref()\n    }\n}\n\nimpl<B, M, G> Clone for VertexView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n    View<B, Vertex<G>>: Clone,\n{\n    fn clone(&self) -> Self {\n        VertexView {\n            inner: self.inner.clone(),\n        }\n    }\n}\n\nimpl<B, M, G> ClosedView for VertexView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Key = VertexKey;\n    type Entity = Vertex<G>;\n\n    fn key(&self) -> Self::Key {\n        self.inner.key()\n    }\n}\n\nimpl<B, M, G> Copy for VertexView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n    View<B, Vertex<G>>: Copy,\n{\n}\n\nimpl<B, M, G> Deref for VertexView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Target = Vertex<G>;\n\n    fn deref(&self) -> &Self::Target {\n        self.inner.deref()\n    }\n}\n\nimpl<B, M, G> DerefMut for VertexView<B>\nwhere\n    B: ReborrowMut<Target = M>,\n    M: AsStorageMut<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        self.inner.deref_mut()\n    }\n}\n\nimpl<B, M, G> Eq for VertexView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n}\n\nimpl<B, M, G> From<View<B, Vertex<G>>> for VertexView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn from(view: View<B, Vertex<G>>) -> Self {\n        VertexView { inner: view }\n    }\n}\n\nimpl<B, M, G> From<VertexView<B>> for View<B, Vertex<G>>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn from(vertex: VertexView<B>) -> Self {\n        let VertexView { inner, .. } = vertex;\n        inner\n    }\n}\n\nimpl<B, M, G> Hash for VertexView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn hash<H>(&self, state: &mut H)\n    where\n        H: Hasher,\n    {\n        self.inner.hash(state);\n    }\n}\n\nimpl<B, M, G> PartialEq for VertexView<B>\nwhere\n    B: Reborrow<Target = M>,\n    M: AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn eq(&self, other: &Self) -> bool {\n        self.inner == other.inner\n    }\n}\n\n/// Orphan view of a vertex entity.\npub struct VertexOrphan<'a, G>\nwhere\n    G: GraphData,\n{\n    inner: Orphan<'a, Vertex<G>>,\n}\n\nimpl<G> VertexOrphan<'_, G>\nwhere\n    G: GraphData,\n{\n    pub fn position(&self) -> &VertexPosition<G>\n    where\n        G::Vertex: AsPosition,\n    {\n        self.inner.get().as_position()\n    }\n}\n\nimpl<G> VertexOrphan<'_, G>\nwhere\n    G: GraphData,\n{\n    pub fn get(&self) -> &G::Vertex {\n        self.inner.get()\n    }\n\n    pub fn get_mut(&mut self) -> &mut G::Vertex {\n        self.inner.get_mut()\n    }\n}\n\nimpl<G> Borrow<VertexKey> for VertexOrphan<'_, G>\nwhere\n    G: GraphData,\n{\n    fn borrow(&self) -> &VertexKey {\n        self.inner.as_ref()\n    }\n}\n\nimpl<G> ClosedView for VertexOrphan<'_, G>\nwhere\n    G: GraphData,\n{\n    type Key = VertexKey;\n    type Entity = Vertex<G>;\n\n    fn key(&self) -> Self::Key {\n        self.inner.key()\n    }\n}\n\nimpl<G> Eq for VertexOrphan<'_, G> where G: GraphData {}\n\nimpl<'a, G> From<Orphan<'a, Vertex<G>>> for VertexOrphan<'a, G>\nwhere\n    G: GraphData,\n{\n    fn from(inner: Orphan<'a, Vertex<G>>) -> Self {\n        VertexOrphan { inner }\n    }\n}\n\nimpl<'a, M> From<View<&'a mut M, Vertex<M::Data>>> for VertexOrphan<'a, M::Data>\nwhere\n    M: AsStorageMut<Vertex<M::Data>> + Parametric,\n{\n    fn from(view: View<&'a mut M, Vertex<M::Data>>) -> Self {\n        VertexOrphan { inner: view.into() }\n    }\n}\n\nimpl<'a, M> From<VertexView<&'a mut M>> for VertexOrphan<'a, M::Data>\nwhere\n    M: AsStorageMut<Vertex<M::Data>> + Parametric,\n{\n    fn from(vertex: VertexView<&'a mut M>) -> Self {\n        Orphan::from(vertex.inner).into()\n    }\n}\n\nimpl<G> Hash for VertexOrphan<'_, G>\nwhere\n    G: GraphData,\n{\n    fn hash<H>(&self, state: &mut H)\n    where\n        H: Hasher,\n    {\n        self.inner.hash(state);\n    }\n}\n\nimpl<G> PartialEq for VertexOrphan<'_, G>\nwhere\n    G: GraphData,\n{\n    fn eq(&self, other: &Self) -> bool {\n        self.inner == other.inner\n    }\n}\n\npub struct VertexCirculator<P, B>\nwhere\n    P: Trace<ArcKey>,\n    B: Reborrow,\n    B::Target: AsStorage<Arc<Data<B>>> + AsStorage<Vertex<Data<B>>> + Parametric,\n{\n    inner: ArcCirculator<P, B>,\n}\n\nimpl<P, B, M, G> Circulator<B> for VertexCirculator<P, B>\nwhere\n    P: Trace<ArcKey>,\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Entity = Vertex<G>;\n\n    fn next(&mut self) -> Option<<Self::Entity as Entity>::Key> {\n        self.inner.next().map(|arc| {\n            let (source, _) = arc.into();\n            source\n        })\n    }\n}\n\nimpl<P, B, M, G> Clone for VertexCirculator<P, B>\nwhere\n    P: Clone + Trace<ArcKey>,\n    B: Clone + Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn clone(&self) -> Self {\n        VertexCirculator {\n            inner: self.inner.clone(),\n        }\n    }\n}\n\nimpl<P, B, M, G> From<ArcCirculator<P, B>> for VertexCirculator<P, B>\nwhere\n    P: Trace<ArcKey>,\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn from(inner: ArcCirculator<P, B>) -> Self {\n        VertexCirculator { inner }\n    }\n}\n\nimpl<'a, P, M> Iterator for VertexCirculator<P, &'a M>\nwhere\n    P: Trace<ArcKey>,\n    M: AsStorage<Arc<M::Data>> + AsStorage<Vertex<M::Data>> + Parametric,\n{\n    type Item = VertexView<&'a M>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        self.bind_next_view()\n    }\n}\n\nimpl<'a, M> Iterator for VertexCirculator<TraceAny<ArcKey>, &'a mut M>\nwhere\n    M: AsStorage<Arc<M::Data>> + AsStorageMut<Vertex<M::Data>> + Parametric,\n{\n    type Item = VertexOrphan<'a, M::Data>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        unsafe { self.bind_next_orphan() }\n    }\n}\n\nimpl<'a, M> Iterator for VertexCirculator<TraceFirst<ArcKey>, &'a mut M>\nwhere\n    M: AsStorage<Arc<M::Data>> + AsStorageMut<Vertex<M::Data>> + Consistent + Parametric,\n{\n    type Item = VertexOrphan<'a, M::Data>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        unsafe { self.bind_next_orphan() }\n    }\n}\n\nimpl<'a, P, M> OrphanCirculator<'a, M> for VertexCirculator<P, &'a mut M>\nwhere\n    P: Trace<ArcKey>,\n    M: AsStorage<Arc<M::Data>> + AsStorageMut<Vertex<M::Data>> + Parametric,\n{\n    fn target(&mut self) -> &mut M {\n        self.inner.storage\n    }\n}\n\nimpl<'a, P, M> ViewCirculator<'a, M> for VertexCirculator<P, &'a M>\nwhere\n    P: Trace<ArcKey>,\n    M: AsStorage<Arc<M::Data>> + AsStorage<Vertex<M::Data>> + Parametric,\n{\n    fn target(&self) -> &'a M {\n        self.inner.storage\n    }\n}\n\npub struct ArcCirculator<P, B>\nwhere\n    P: Trace<ArcKey>,\n    B: Reborrow,\n    B::Target: AsStorage<Arc<Data<B>>> + Parametric,\n{\n    storage: B,\n    outgoing: Option<ArcKey>,\n    trace: P,\n}\n\nimpl<P, B, M, G> Circulator<B> for ArcCirculator<P, B>\nwhere\n    P: Trace<ArcKey>,\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Entity = Arc<G>;\n\n    fn next(&mut self) -> Option<<Self::Entity as Entity>::Key> {\n        self.outgoing\n            .and_then(|outgoing| self.trace.insert(outgoing).then_some(outgoing))\n            .map(|outgoing| outgoing.into_opposite())\n            .and_then(|incoming| {\n                self.storage\n                    .reborrow()\n                    .as_storage()\n                    .get(&incoming)\n                    .map(|incoming| incoming.next)\n                    .map(|outgoing| (incoming, outgoing))\n            })\n            .map(|(incoming, outgoing)| {\n                self.outgoing = outgoing;\n                incoming\n            })\n    }\n}\n\nimpl<P, B, M, G> Clone for ArcCirculator<P, B>\nwhere\n    P: Clone + Trace<ArcKey>,\n    B: Clone + Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn clone(&self) -> Self {\n        ArcCirculator {\n            storage: self.storage.clone(),\n            outgoing: self.outgoing,\n            trace: self.trace.clone(),\n        }\n    }\n}\n\nimpl<P, B, M, G> From<VertexView<B>> for ArcCirculator<P, B>\nwhere\n    P: Default + Trace<ArcKey>,\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn from(vertex: VertexView<B>) -> Self {\n        let key = vertex.arc;\n        let (storage, _) = vertex.unbind();\n        ArcCirculator {\n            storage,\n            outgoing: key,\n            trace: Default::default(),\n        }\n    }\n}\n\nimpl<'a, P, M> Iterator for ArcCirculator<P, &'a M>\nwhere\n    P: Trace<ArcKey>,\n    M: AsStorage<Arc<M::Data>> + Parametric,\n{\n    type Item = ArcView<&'a M>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        self.bind_next_view()\n    }\n}\n\nimpl<'a, M> Iterator for ArcCirculator<TraceAny<ArcKey>, &'a mut M>\nwhere\n    M: AsStorageMut<Arc<M::Data>> + Parametric,\n{\n    type Item = ArcOrphan<'a, M::Data>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        unsafe { self.bind_next_orphan() }\n    }\n}\n\nimpl<'a, M> Iterator for ArcCirculator<TraceFirst<ArcKey>, &'a mut M>\nwhere\n    M: AsStorageMut<Arc<M::Data>> + Consistent + Parametric,\n{\n    type Item = ArcOrphan<'a, M::Data>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        unsafe { self.bind_next_orphan() }\n    }\n}\n\nimpl<'a, P, M> OrphanCirculator<'a, M> for ArcCirculator<P, &'a mut M>\nwhere\n    P: Trace<ArcKey>,\n    M: AsStorageMut<Arc<M::Data>> + Parametric,\n{\n    fn target(&mut self) -> &mut M {\n        self.storage\n    }\n}\n\nimpl<'a, P, M> ViewCirculator<'a, M> for ArcCirculator<P, &'a M>\nwhere\n    P: Trace<ArcKey>,\n    M: AsStorage<Arc<M::Data>> + Parametric,\n{\n    fn target(&self) -> &'a M {\n        self.storage\n    }\n}\n\npub struct FaceCirculator<P, B>\nwhere\n    P: Trace<ArcKey>,\n    B: Reborrow,\n    B::Target: AsStorage<Arc<Data<B>>> + AsStorage<Face<Data<B>>> + Parametric,\n{\n    inner: ArcCirculator<P, B>,\n}\n\nimpl<P, B, M, G> Circulator<B> for FaceCirculator<P, B>\nwhere\n    P: Trace<ArcKey>,\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    type Entity = Face<G>;\n\n    fn next(&mut self) -> Option<<Self::Entity as Entity>::Key> {\n        while let Some(arc) = self.inner.next() {\n            if let Some(face) = self\n                .inner\n                .storage\n                .reborrow()\n                .as_storage_of::<Arc<_>>()\n                .get(&arc)\n                .and_then(|arc| arc.face)\n            {\n                return Some(face);\n            }\n            else {\n                // Skip arcs with no face. This can occur within non-enclosed\n                // meshes.\n                continue;\n            }\n        }\n        None\n    }\n}\n\nimpl<P, B, M, G> Clone for FaceCirculator<P, B>\nwhere\n    P: Clone + Trace<ArcKey>,\n    B: Clone + Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn clone(&self) -> Self {\n        FaceCirculator {\n            inner: self.inner.clone(),\n        }\n    }\n}\n\nimpl<P, B, M, G> From<ArcCirculator<P, B>> for FaceCirculator<P, B>\nwhere\n    P: Trace<ArcKey>,\n    B: Reborrow<Target = M>,\n    M: AsStorage<Arc<G>> + AsStorage<Face<G>> + Parametric<Data = G>,\n    G: GraphData,\n{\n    fn from(inner: ArcCirculator<P, B>) -> Self {\n        FaceCirculator { inner }\n    }\n}\n\nimpl<'a, P, M> Iterator for FaceCirculator<P, &'a M>\nwhere\n    P: Trace<ArcKey>,\n    M: AsStorage<Arc<M::Data>> + AsStorage<Face<M::Data>> + Parametric,\n{\n    type Item = FaceView<&'a M>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        self.bind_next_view()\n    }\n}\n\nimpl<'a, M> Iterator for FaceCirculator<TraceAny<ArcKey>, &'a mut M>\nwhere\n    M: AsStorage<Arc<M::Data>> + AsStorageMut<Face<M::Data>> + Parametric,\n{\n    type Item = FaceOrphan<'a, M::Data>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        unsafe { self.bind_next_orphan() }\n    }\n}\n\nimpl<'a, M> Iterator for FaceCirculator<TraceFirst<ArcKey>, &'a mut M>\nwhere\n    M: AsStorage<Arc<M::Data>> + AsStorageMut<Face<M::Data>> + Consistent + Parametric,\n{\n    type Item = FaceOrphan<'a, M::Data>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        unsafe { self.bind_next_orphan() }\n    }\n}\n\nimpl<'a, P, M> OrphanCirculator<'a, M> for FaceCirculator<P, &'a mut M>\nwhere\n    P: Trace<ArcKey>,\n    M: AsStorage<Arc<M::Data>> + AsStorageMut<Face<M::Data>> + Parametric,\n{\n    fn target(&mut self) -> &mut M {\n        self.inner.storage\n    }\n}\n\nimpl<'a, P, M> ViewCirculator<'a, M> for FaceCirculator<P, &'a M>\nwhere\n    P: Trace<ArcKey>,\n    M: AsStorage<Arc<M::Data>> + AsStorage<Face<M::Data>> + Parametric,\n{\n    fn target(&self) -> &'a M {\n        self.inner.storage\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use decorum::R64;\n    use nalgebra::{Point2, Point3};\n\n    use crate::graph::{GraphError, MeshGraph};\n    use crate::prelude::*;\n    use crate::primitive::cube::Cube;\n    use crate::primitive::generate::Position;\n    use crate::primitive::sphere::UvSphere;\n    use crate::primitive::Trigon;\n\n    type E3 = Point3<R64>;\n\n    #[test]\n    fn circulate_over_arcs() {\n        let graph: MeshGraph<E3> = UvSphere::new(4, 2)\n            .polygons::<Position<E3>>() // 6 triangles, 18 vertices.\n            .collect();\n\n        // All faces should be triangles and all vertices should have 4\n        // (incoming) arcs.\n        for vertex in graph.vertices() {\n            assert_eq!(4, vertex.incoming_arcs().count());\n        }\n    }\n\n    #[test]\n    fn reachable_shortest_path() {\n        let graph = MeshGraph::<Point2<f64>>::from_raw_buffers(\n            vec![Trigon::new(0usize, 1, 2)],\n            vec![(-1.0, 0.0), (0.0, 1.0), (1.0, 0.0)],\n        )\n        .unwrap();\n        let from = graph.vertices().next().unwrap();\n        let to = from.outgoing_arc().destination_vertex().key();\n        let path = from.shortest_path(to).unwrap();\n\n        assert_eq!(path.back().key(), from.key());\n        assert_eq!(path.front().key(), to);\n        assert_eq!(path.arcs().count(), 1);\n    }\n\n    #[test]\n    fn unreachable_shortest_path() {\n        // Create a graph from two disjoint trigons.\n        let graph = MeshGraph::<Point2<f64>>::from_raw_buffers(\n            vec![Trigon::new(0usize, 1, 2), Trigon::new(3, 4, 5)],\n            vec![\n                (-2.0, 0.0),\n                (-1.0, 1.0),\n                (-1.0, 0.0),\n                (0.0, 0.0),\n                (1.0, 1.0),\n                (1.0, 0.0),\n            ],\n        )\n        .unwrap();\n        let mut vertices = graph.disjoint_subgraph_vertices();\n        let from = vertices.next().unwrap();\n        let to = vertices.next().unwrap().key();\n\n        assert!(matches!(\n            from.into_shortest_path(to),\n            Err(GraphError::TopologyUnreachable)\n        ));\n    }\n\n    #[test]\n    fn traverse_by_breadth() {\n        let graph: MeshGraph<E3> = Cube::new()\n            .polygons::<Position<E3>>() // 6 quadrilaterals, 24 vertices.\n            .collect();\n\n        let vertex = graph.vertices().next().unwrap();\n        assert_eq!(graph.vertex_count(), vertex.traverse_by_breadth().count());\n    }\n\n    #[test]\n    fn traverse_by_depth() {\n        let graph: MeshGraph<E3> = Cube::new()\n            .polygons::<Position<E3>>() // 6 quadrilaterals, 24 vertices.\n            .collect();\n\n        let vertex = graph.vertices().next().unwrap();\n        assert_eq!(graph.vertex_count(), vertex.traverse_by_depth().count());\n    }\n}\n"
  },
  {
    "path": "plexus/src/index.rs",
    "content": "//! Indexing and aggregation.\n//!\n//! This module provides types and traits that describe _index buffers_ and\n//! _indexers_ that disambiguate vertex data to construct minimal _index_ and\n//! _vertex buffers_. Plexus refers to independent vertex and index buffers as\n//! _raw buffers_. See the [`buffer`] module and [`MeshBuffer`] type for tools\n//! for working with these buffers.\n//!\n//! # Index Buffers\n//!\n//! Index buffers describe the topology of a polygonal mesh as ordered groups of\n//! indices into a vertex buffer. Each group of indices represents a polygon.\n//! The vertex buffer contains data that describes each vertex, such as\n//! positions or surface normals. Plexus supports _structured_ and _flat_ index\n//! buffers via the [`Grouping`] and [`IndexBuffer`] traits. These traits are\n//! implemented for [`Vec`].\n//!\n//! Flat index buffers contain unstructured indices with an implicit grouping,\n//! such as `Vec<usize>`. Arity of these buffers is constant and is described by\n//! the [`Flat`] meta-grouping. Rendering pipelines typically expect this\n//! format.\n//!\n//! Structured index buffers contain elements that explicitly group indices,\n//! such as `Vec<Trigon<usize>>`. These buffers can be formed from polygonal\n//! types in the [`primitive`] module.\n//!\n//! # Indexers\n//!\n//! [`Indexer`]s construct index and vertex buffers from iterators of polygonal\n//! types in the [`primitive`] module, such as [`NGon`] and\n//! [`UnboundedPolygon`]. The [`IndexVertices`] trait provides functions for\n//! collecting an iterator of $n$-gons into these buffers.\n//!\n//! Mesh data structures also implement the [`FromIndexer`] and [`FromIterator`]\n//! traits so that iterators of $n$-gons can be collected into these types\n//! (using a [`HashIndexer`] by default). A specific [`Indexer`] can be\n//! configured using the [`CollectWithIndexer`] trait.\n//!\n//! # Examples\n//!\n//! Indexing data for a cube to create raw buffers and a [`MeshBuffer`]:\n//!\n//! ```rust\n//! # extern crate decorum;\n//! # extern crate nalgebra;\n//! # extern crate plexus;\n//! #\n//! use decorum::R64;\n//! use nalgebra::Point3;\n//! use plexus::buffer::MeshBuffer;\n//! use plexus::index::{Flat3, HashIndexer};\n//! use plexus::prelude::*;\n//! use plexus::primitive::cube::Cube;\n//! use plexus::primitive::generate::Position;\n//!\n//! type E3 = Point3<R64>;\n//!\n//! let (indices, positions) = Cube::new()\n//!     .polygons::<Position<E3>>()\n//!     .triangulate()\n//!     .index_vertices::<Flat3, _>(HashIndexer::default());\n//! let buffer = MeshBuffer::<Flat3, E3>::from_raw_buffers(indices, positions).unwrap();\n//! ```\n//!\n//! [`FromIterator`]: std::iter::FromIterator\n//! [`Vec`]: std::vec::Vec\n//! [`MeshBuffer`]: crate::buffer::MeshBuffer\n//! [`buffer`]: crate::buffer\n//! [`MeshGraph`]: crate::graph::MeshGraph\n//! [`CollectWithIndexer`]: crate::index::CollectWithIndexer\n//! [`Flat`]: crate::index::Flat\n//! [`FromIndexer`]: crate::index::FromIndexer\n//! [`HashIndexer`]: crate::index::HashIndexer\n//! [`Indexer`]: crate::index::Indexer\n//! [`IndexVertices`]: crate::index::IndexVertices\n//! [`NGon`]: crate::primitive::NGon\n//! [`UnboundedPolygon`]: crate::primitive::UnboundedPolygon\n//! [`primitive`]: crate::primitive\n\nuse num::{Integer, NumCast, Unsigned};\nuse std::cmp;\nuse std::collections::HashMap;\nuse std::fmt::Debug;\nuse std::hash::Hash;\nuse std::marker::PhantomData;\nuse theon::adjunct::Map;\nuse typenum::NonZero;\n\nuse crate::constant::{Constant, ToType, TypeOf};\nuse crate::primitive::decompose::IntoVertices;\nuse crate::primitive::Topological;\nuse crate::{Monomorphic, StaticArity};\n\npub(crate) type BufferOf<R> = Vec<<R as Grouping>::Group>;\npub(crate) type IndexOf<R> = <BufferOf<R> as IndexBuffer<R>>::Index;\n\n// Note that it isn't possible for `IndexBuffer` types to implement\n// `DynamicArity`, because they are typically parameterized by `R` (see\n// implementations for `Vec<_>`). Instead, `DynamicArity` is implemented for\n// `MeshBuffer`, which can bind a `Grouping` and its implementation of\n// `StaticArity` with the underlying index buffer type.\n/// Index buffer.\n///\n/// This trait is implemented by types that can be used as an index buffer. The\n/// elements in the buffer are determined by a `Grouping`.\n///\n/// In particular, this trait is implemented by `Vec`, such as `Vec<usize>` or\n/// `Vec<Trigon<usize>>`.\npub trait IndexBuffer<R>\nwhere\n    R: Grouping,\n{\n    /// The type of individual indices in the buffer.\n    ///\n    /// This type is distinct from the grouping. For example, if an index buffer\n    /// contains [`Trigon<usize>`][`Trigon`] elements, then this type is `usize`.\n    ///\n    /// [`Trigon`]: crate::primitive::Trigon\n    type Index: Copy + Integer + Unsigned;\n}\n\nimpl<T, const N: usize> IndexBuffer<Flat<T, N>> for Vec<T>\nwhere\n    Constant<N>: ToType,\n    TypeOf<N>: NonZero,\n    T: Copy + Integer + Unsigned,\n{\n    type Index = T;\n}\n\nimpl<P> IndexBuffer<P> for Vec<P>\nwhere\n    P: Topological,\n    P::Vertex: Copy + Integer + Unsigned,\n{\n    type Index = P::Vertex;\n}\n\npub trait Push<R, P>: IndexBuffer<R>\nwhere\n    R: Grouping,\n    P: Topological<Vertex = Self::Index>,\n    P::Vertex: Copy + Integer + Unsigned,\n{\n    fn push(&mut self, index: P);\n}\n\nimpl<T, P, const N: usize> Push<Flat<T, N>, P> for Vec<T>\nwhere\n    Constant<N>: ToType,\n    TypeOf<N>: NonZero,\n    T: Copy + Integer + Unsigned,\n    P: Monomorphic + IntoVertices + Topological<Vertex = T>,\n{\n    fn push(&mut self, index: P) {\n        for index in index.into_vertices() {\n            self.push(index);\n        }\n    }\n}\n\nimpl<P, Q> Push<P, Q> for Vec<P>\nwhere\n    P: From<Q> + Grouping + Topological,\n    P::Vertex: Copy + Integer + Unsigned,\n    Q: Topological<Vertex = P::Vertex>,\n    Self: IndexBuffer<P, Index = P::Vertex>,\n{\n    fn push(&mut self, index: Q) {\n        self.push(P::from(index));\n    }\n}\n\npub trait Grouping: StaticArity {\n    type Group;\n}\n\n/// Flat index buffer meta-grouping.\n///\n/// Describes a flat index buffer with a constant arity. The number of vertices\n/// in the indexed topological structures is specified using a constant\n/// parameter `N`, which represents the number of grouped elements in the index\n/// buffer. For example, `Flat<_, 3>` describes an index buffer with indices in\n/// implicit and contiguous groups of three. Note that this constant may be\n/// distinct from the arity of the indexed topological structures (i.e., if `N`\n/// is less than three, then arity is `N - 1` and may be zero.).\n///\n/// Unlike structured groupings, this meta-grouping is needed to associate an\n/// index type with an implicit grouping and arity. For example, `Vec<usize>`\n/// implements both `IndexBuffer<Flat<usize, 3>>` (a triangular buffer) and\n/// `IndexBuffer<Flat<usize, 4>>` (a quadrilateral buffer).\n///\n/// See the [`index`] module documention for more information about index\n/// buffers.\n///\n/// # Examples\n///\n/// Creating a [`MeshBuffer`] with a flat and triangular index buffer:\n///\n/// ```rust\n/// use plexus::buffer::MeshBuffer;\n/// use plexus::index::Flat;\n/// use plexus::prelude::*;\n///\n/// let mut buffer = MeshBuffer::<Flat<usize, 3>, (f64, f64, f64)>::default();\n/// ```\n///\n/// [`MeshBuffer`]: crate::buffer::MeshBuffer\n/// [`index`]: crate::index\n#[derive(Debug)]\npub struct Flat<T, const N: usize>\nwhere\n    Constant<N>: ToType,\n    TypeOf<N>: NonZero,\n    T: Copy + Integer + Unsigned,\n{\n    phantom: PhantomData<fn() -> T>,\n}\n\nimpl<T, const N: usize> Grouping for Flat<T, N>\nwhere\n    Constant<N>: ToType,\n    TypeOf<N>: NonZero,\n    T: Copy + Integer + Unsigned,\n{\n    /// The elements of flat index buffers are indices. These indices are\n    /// implicitly grouped by the arity of the buffer (`N`).\n    type Group = T;\n}\n\nimpl<T, const N: usize> Monomorphic for Flat<T, N>\nwhere\n    Constant<N>: ToType,\n    TypeOf<N>: NonZero,\n    T: Copy + Integer + Unsigned,\n{\n}\n\nimpl<T, const N: usize> StaticArity for Flat<T, N>\nwhere\n    Constant<N>: ToType,\n    TypeOf<N>: NonZero,\n    T: Copy + Integer + Unsigned,\n{\n    type Static = usize;\n\n    const ARITY: Self::Static = crate::n_arity(N);\n}\n\n/// Alias for a flat and triangular index buffer.\npub type Flat3<T = usize> = Flat<T, 3>;\n/// Alias for a flat and quadrilateral index buffer.\npub type Flat4<T = usize> = Flat<T, 4>;\n\n/// Structured index buffer grouping.\n///\n/// Describes a structured index buffer containing [`Topological`] types with\n/// index data in their vertices.\n///\n/// # Examples\n///\n/// Creating a [`MeshBuffer`] with a structured index buffer:\n///\n/// ```rust\n/// use plexus::buffer::MeshBuffer;\n/// use plexus::prelude::*;\n/// use plexus::primitive::BoundedPolygon;\n///\n/// let mut buffer = MeshBuffer::<BoundedPolygon<usize>, (f64, f64, f64)>::default();\n/// ```\n///\n/// [`MeshBuffer`]: crate::buffer::MeshBuffer\n/// [`Topological`]: crate::primitive::Topological\nimpl<P> Grouping for P\nwhere\n    P: Topological,\n    P::Vertex: Copy + Integer + Unsigned,\n{\n    /// [`Topological`] index buffers contain $n$-gons that explicitly group\n    /// their indices.\n    ///\n    /// [`Topological`]: crate::primitive::Topological\n    type Group = P;\n}\n\n/// Vertex indexer.\n///\n/// Disambiguates arbitrary vertex data and emits a one-to-one mapping of\n/// indices to vertices.\npub trait Indexer<T, K>\nwhere\n    T: Topological,\n{\n    /// Indexes a vertex using a keying function.\n    ///\n    /// Returns a tuple containing the index and optionally vertex data. Vertex\n    /// data is only returned if the data has not yet been indexed, otherwise\n    /// `None` is returned.\n    fn index<F>(&mut self, vertex: T::Vertex, f: F) -> (usize, Option<T::Vertex>)\n    where\n        F: Fn(&T::Vertex) -> &K;\n}\n\n/// Hashing vertex indexer.\n///\n/// This indexer hashes key data for vertices to form an index. This is fast,\n/// reliable, and requires no configuration. Prefer this indexer when possible.\n///\n/// The vertex key data must implement [`Hash`]. Vertex data often includes\n/// floating-point values (i.e., `f32` or `f64`), which do not implement\n/// [`Hash`]. Types from the [`decorum`] crate can be used to allow\n/// floating-point data to be hashed.\n///\n/// # Examples\n///\n/// ```rust\n/// # extern crate decorum;\n/// # extern crate nalgebra;\n/// # extern crate plexus;\n/// #\n/// use decorum::R64;\n/// use nalgebra::Point3;\n/// use plexus::index::{Flat3, HashIndexer};\n/// use plexus::prelude::*;\n/// use plexus::primitive::cube::Cube;\n/// use plexus::primitive::generate::Position;\n///\n/// let (indices, positions) = Cube::new()\n///     .polygons::<Position<Point3<R64>>>()\n///     .triangulate()\n///     .index_vertices::<Flat3, _>(HashIndexer::default());\n/// ```\n///\n/// [`decorum`]: https://crates.io/crates/decorum\n///\n/// [`Hash`]: std::hash::Hash\npub struct HashIndexer<T, K>\nwhere\n    T: Topological,\n    K: Clone + Eq + Hash,\n{\n    hash: HashMap<K, usize>,\n    n: usize,\n    phantom: PhantomData<fn() -> T>,\n}\n\nimpl<T, K> HashIndexer<T, K>\nwhere\n    T: Topological,\n    K: Clone + Eq + Hash,\n{\n    /// Creates a new `HashIndexer`.\n    pub fn new() -> Self {\n        HashIndexer {\n            hash: HashMap::new(),\n            n: 0,\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<T, K> Default for HashIndexer<T, K>\nwhere\n    T: Topological,\n    K: Clone + Eq + Hash,\n{\n    fn default() -> Self {\n        HashIndexer::new()\n    }\n}\n\nimpl<T, K> Indexer<T, K> for HashIndexer<T, K>\nwhere\n    T: Topological,\n    K: Clone + Eq + Hash,\n{\n    fn index<F>(&mut self, input: T::Vertex, f: F) -> (usize, Option<T::Vertex>)\n    where\n        F: Fn(&T::Vertex) -> &K,\n    {\n        let mut vertex = None;\n        let mut n = self.n;\n        let index = self.hash.entry(f(&input).clone()).or_insert_with(|| {\n            vertex = Some(input);\n            let m = n;\n            n += 1;\n            m\n        });\n        self.n = n;\n        (*index, vertex)\n    }\n}\n\n/// LRU caching vertex indexer.\n///\n/// This indexer uses a _least recently used_ (LRU) cache to form an index. To\n/// function correctly, an adequate cache capacity is necessary. If the capacity\n/// is insufficient, then redundant vertex data may be emitted. See\n/// [`LruIndexer::with_capacity`].\n///\n/// This indexer is useful if the vertex key data does not implement [`Hash`].\n/// If the key data can be hashed, prefer `HashIndexer` instead.\n///\n/// # Examples\n///\n/// ```rust\n/// # extern crate nalgebra;\n/// # extern crate plexus;\n/// #\n/// use nalgebra::Point3;\n/// use plexus::index::{Flat3, LruIndexer};\n/// use plexus::prelude::*;\n/// use plexus::primitive::generate::Position;\n/// use plexus::primitive::sphere::UvSphere;\n///\n/// let (indices, positions) = UvSphere::new(8, 8)\n///     .polygons::<Position<Point3<f64>>>()\n///     .triangulate()\n///     .index_vertices::<Flat3, _>(LruIndexer::with_capacity(64));\n/// ```\n///\n/// [`Hash`]: std::hash::Hash\n/// [`LruIndexer::with_capacity`]: crate::index::LruIndexer::with_capacity\npub struct LruIndexer<T, K>\nwhere\n    T: Topological,\n    K: Clone + PartialEq,\n{\n    lru: Vec<(K, usize)>,\n    capacity: usize,\n    n: usize,\n    phantom: PhantomData<fn() -> T>,\n}\n\nimpl<T, K> LruIndexer<T, K>\nwhere\n    T: Topological,\n    K: Clone + PartialEq,\n{\n    /// Creates a new `LruIndexer` with a default capacity.\n    pub fn new() -> Self {\n        LruIndexer::with_capacity(16)\n    }\n\n    /// Creates a new `LruIndexer` with the specified capacity.\n    ///\n    /// The capacity of the cache must be sufficient in order to generate a\n    /// unique set of index and vertex data.\n    pub fn with_capacity(capacity: usize) -> Self {\n        let capacity = cmp::max(1, capacity);\n        LruIndexer {\n            lru: Vec::with_capacity(capacity),\n            capacity,\n            n: 0,\n            phantom: PhantomData,\n        }\n    }\n\n    fn find(&self, key: &K) -> Option<(usize, usize)> {\n        self.lru\n            .iter()\n            .enumerate()\n            .find(|&(_, entry)| entry.0 == *key)\n            .map(|(index, entry)| (index, entry.1))\n    }\n}\n\nimpl<T, K> Default for LruIndexer<T, K>\nwhere\n    T: Topological,\n    K: Clone + PartialEq,\n{\n    fn default() -> Self {\n        LruIndexer::new()\n    }\n}\n\nimpl<T, K> Indexer<T, K> for LruIndexer<T, K>\nwhere\n    T: Topological,\n    K: Clone + PartialEq,\n{\n    fn index<F>(&mut self, input: T::Vertex, f: F) -> (usize, Option<T::Vertex>)\n    where\n        F: Fn(&T::Vertex) -> &K,\n    {\n        let mut vertex = None;\n        let key = f(&input).clone();\n        let index = if let Some(entry) = self.find(&key) {\n            let vertex = self.lru.remove(entry.0);\n            self.lru.push(vertex);\n            entry.1\n        }\n        else {\n            vertex = Some(input);\n            let m = self.n;\n            self.n += 1;\n            if self.lru.len() >= self.capacity {\n                self.lru.remove(0);\n            }\n            self.lru.push((key, m));\n            m\n        };\n        (index, vertex)\n    }\n}\n\n/// Functions for collecting an iterator of $n$-gons into raw index and vertex\n/// buffers.\n///\n/// Unlike [`IndexVertices`], this trait provides functions that are closed (not\n/// parameterized) with respect to [`Grouping`]. Instead, the trait is\n/// implemented for a particular [`Grouping`]. These functions cannot be used\n/// fluently as part of an iterator expression.\n///\n/// [`Grouping`]: crate::index::Grouping\n/// [`IndexVertices`]: crate::index::IndexVertices\npub trait GroupedIndexVertices<R, P>: Sized\nwhere\n    R: Grouping,\n    P: Topological,\n{\n    fn index_vertices_with<N, K, F>(self, indexer: N, f: F) -> (Vec<R::Group>, Vec<P::Vertex>)\n    where\n        N: Indexer<P, K>,\n        F: Fn(&P::Vertex) -> &K;\n\n    fn index_vertices<N>(self, indexer: N) -> (Vec<R::Group>, Vec<P::Vertex>)\n    where\n        N: Indexer<P, P::Vertex>,\n    {\n        self.index_vertices_with::<N, P::Vertex, _>(indexer, |vertex| vertex)\n    }\n}\n\nimpl<R, P, I> GroupedIndexVertices<R, P> for I\nwhere\n    I: Iterator<Item = P>,\n    R: Grouping,\n    P: Map<IndexOf<R>> + Topological,\n    P::Output: Topological<Vertex = IndexOf<R>>,\n    BufferOf<R>: Push<R, P::Output>,\n    IndexOf<R>: NumCast,\n{\n    fn index_vertices_with<N, K, F>(self, mut indexer: N, f: F) -> (Vec<R::Group>, Vec<P::Vertex>)\n    where\n        N: Indexer<P, K>,\n        F: Fn(&P::Vertex) -> &K,\n    {\n        let mut indices = Vec::new();\n        let mut vertices = Vec::new();\n        for topology in self {\n            Push::push(\n                &mut indices,\n                topology.map(|vertex| {\n                    let (index, vertex) = indexer.index(vertex, &f);\n                    if let Some(vertex) = vertex {\n                        vertices.push(vertex);\n                    }\n                    NumCast::from(index).unwrap()\n                }),\n            );\n        }\n        (indices, vertices)\n    }\n}\n\n/// Functions for collecting an iterator of $n$-gons into raw index and vertex\n/// buffers.\n///\n/// Unlike [`GroupedIndexVertices`], this trait provides functions that are\n/// parameterized with respect to [`Grouping`].\n///\n/// See [`HashIndexer`] and [`LruIndexer`].\n///\n/// # Examples\n///\n///\n/// ```rust\n/// # extern crate decorum;\n/// # extern crate nalgebra;\n/// # extern crate plexus;\n/// #\n/// use decorum::R64;\n/// use nalgebra::Point3;\n/// use plexus::index::{Flat3, HashIndexer};\n/// use plexus::prelude::*;\n/// use plexus::primitive::generate::Position;\n/// use plexus::primitive::sphere::UvSphere;\n///\n/// let sphere = UvSphere::new(32, 32);\n/// let (indices, positions) = sphere\n///     .polygons::<Position<Point3<R64>>>()\n///     .triangulate()\n///     .index_vertices::<Flat3, _>(HashIndexer::default());\n/// ```\n///\n/// [`GroupedIndexVertices`]: crate::index::GroupedIndexVertices\n/// [`Grouping`]: crate::index::Grouping\n/// [`HashIndexer`]: crate::index::HashIndexer\n/// [`LruIndexer`]: crate::index::LruIndexer\npub trait IndexVertices<P>\nwhere\n    P: Topological,\n{\n    /// Indexes an iterator of $n$-gons into raw index and vertex buffers using\n    /// the given grouping, indexer, and keying function.\n    fn index_vertices_with<R, N, K, F>(self, indexer: N, f: F) -> (Vec<R::Group>, Vec<P::Vertex>)\n    where\n        Self: GroupedIndexVertices<R, P>,\n        R: Grouping,\n        N: Indexer<P, K>,\n        F: Fn(&P::Vertex) -> &K,\n    {\n        GroupedIndexVertices::<R, P>::index_vertices_with(self, indexer, f)\n    }\n\n    /// Indexes an iterator of $n$-gons into raw index and vertex buffers using\n    /// the given grouping and indexer.\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// # extern crate decorum;\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use decorum::R64;\n    /// use nalgebra::Point3;\n    /// use plexus::index::HashIndexer;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::cube::Cube;\n    /// use plexus::primitive::generate::Position;\n    /// use plexus::primitive::Trigon;\n    ///\n    /// // `indices` contains `Trigon`s with index data.\n    /// let (indices, positions) = Cube::new()\n    ///     .polygons::<Position<Point3<R64>>>()\n    ///     .subdivide()\n    ///     .triangulate()\n    ///     .index_vertices::<Trigon<usize>, _>(HashIndexer::default());\n    /// ```\n    fn index_vertices<R, N>(self, indexer: N) -> (Vec<R::Group>, Vec<P::Vertex>)\n    where\n        Self: GroupedIndexVertices<R, P>,\n        R: Grouping,\n        N: Indexer<P, P::Vertex>,\n    {\n        IndexVertices::<P>::index_vertices_with(self, indexer, |vertex| vertex)\n    }\n}\n\nimpl<P, I> IndexVertices<P> for I\nwhere\n    I: Iterator<Item = P>,\n    P: Topological,\n{\n}\n\npub trait FromIndexer<P, Q>: Sized\nwhere\n    P: Topological,\n    Q: Topological<Vertex = P::Vertex>,\n{\n    type Error: Debug;\n\n    fn from_indexer<I, N>(input: I, indexer: N) -> Result<Self, Self::Error>\n    where\n        I: IntoIterator<Item = P>,\n        N: Indexer<Q, P::Vertex>;\n}\n\n/// Functions for collecting an iterator of $n$-gons into a mesh data structure.\n///\n/// These functions can be used to collect data from an iterator into mesh data\n/// structures like [`MeshBuffer`] or [`MeshGraph`].\n///\n/// See [`HashIndexer`] and [`LruIndexer`].\n///\n/// [`MeshBuffer`]: crate::buffer::MeshBuffer\n/// [`MeshGraph`]: crate::graph::MeshGraph\n/// [`HashIndexer`]: crate::index::HashIndexer\n/// [`LruIndexer`]: crate::index::LruIndexer\npub trait CollectWithIndexer<P, Q>\nwhere\n    P: Topological,\n    Q: Topological<Vertex = P::Vertex>,\n{\n    /// Collects an iterator of $n$-gons into a mesh data structure using the\n    /// given indexer.\n    ///\n    /// Unlike `collect`, this function allows the indexer to be specified.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error defined by the implementer if the target type cannot be\n    /// constructed from the indexed vertex data.\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// # extern crate decorum;\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use decorum::R64;\n    /// use nalgebra::Point3;\n    /// use plexus::graph::MeshGraph;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::cube::Cube;\n    /// use plexus::primitive::generate::Position;\n    /// use plexus::index::HashIndexer;\n    ///\n    /// let graph: MeshGraph<Point3<f64>> = Cube::new()\n    ///     .polygons::<Position<Point3<R64>>>()\n    ///     .collect_with_indexer(HashIndexer::default())\n    ///     .unwrap();\n    fn collect_with_indexer<T, N>(self, indexer: N) -> Result<T, T::Error>\n    where\n        T: FromIndexer<P, Q>,\n        N: Indexer<Q, P::Vertex>;\n}\n\nimpl<P, Q, I> CollectWithIndexer<P, Q> for I\nwhere\n    I: Iterator<Item = P>,\n    P: Topological,\n    Q: Topological<Vertex = P::Vertex>,\n{\n    fn collect_with_indexer<T, N>(self, indexer: N) -> Result<T, T::Error>\n    where\n        T: FromIndexer<P, Q>,\n        N: Indexer<Q, P::Vertex>,\n    {\n        T::from_indexer(self, indexer)\n    }\n}\n"
  },
  {
    "path": "plexus/src/integration/cgmath.rs",
    "content": "#![cfg(feature = \"geometry-cgmath\")]\n\nuse cgmath::{Point2, Point3, Vector2, Vector3};\nuse decorum::{ExtendedReal, Primitive, Real, Total};\nuse num::{NumCast, ToPrimitive};\n\nuse crate::geometry::{FromGeometry, UnitGeometry};\nuse crate::graph::GraphData;\n\nimpl<T, U> FromGeometry<(U, U)> for Vector2<T>\nwhere\n    T: NumCast,\n    U: ToPrimitive,\n{\n    fn from_geometry(other: (U, U)) -> Self {\n        Vector2::new(T::from(other.0).unwrap(), T::from(other.1).unwrap())\n    }\n}\n\nimpl<T, U> FromGeometry<Vector2<T>> for (U, U)\nwhere\n    T: ToPrimitive,\n    U: NumCast,\n{\n    fn from_geometry(other: Vector2<T>) -> Self {\n        (U::from(other.x).unwrap(), U::from(other.y).unwrap())\n    }\n}\n\nimpl<T, U> FromGeometry<(U, U, U)> for Vector3<T>\nwhere\n    T: NumCast,\n    U: ToPrimitive,\n{\n    fn from_geometry(other: (U, U, U)) -> Self {\n        Vector3::new(\n            T::from(other.0).unwrap(),\n            T::from(other.1).unwrap(),\n            T::from(other.2).unwrap(),\n        )\n    }\n}\n\nimpl<T, U> FromGeometry<Vector3<T>> for (U, U, U)\nwhere\n    T: ToPrimitive,\n    U: NumCast,\n{\n    fn from_geometry(other: Vector3<T>) -> Self {\n        (\n            U::from(other.x).unwrap(),\n            U::from(other.y).unwrap(),\n            U::from(other.z).unwrap(),\n        )\n    }\n}\n\nimpl<T, U> FromGeometry<(U, U)> for Point2<T>\nwhere\n    T: NumCast,\n    U: ToPrimitive,\n{\n    fn from_geometry(other: (U, U)) -> Self {\n        Point2::new(T::from(other.0).unwrap(), T::from(other.1).unwrap())\n    }\n}\n\nimpl<T, U> FromGeometry<Point2<T>> for (U, U)\nwhere\n    T: ToPrimitive,\n    U: NumCast,\n{\n    fn from_geometry(other: Point2<T>) -> Self {\n        (U::from(other.x).unwrap(), U::from(other.y).unwrap())\n    }\n}\n\nimpl<T> UnitGeometry for Point2<T> {}\n\nimpl<T, U> FromGeometry<(U, U, U)> for Point3<T>\nwhere\n    T: NumCast,\n    U: ToPrimitive,\n{\n    fn from_geometry(other: (U, U, U)) -> Self {\n        Point3::new(\n            T::from(other.0).unwrap(),\n            T::from(other.1).unwrap(),\n            T::from(other.2).unwrap(),\n        )\n    }\n}\n\nimpl<T, U> FromGeometry<Point3<T>> for (U, U, U)\nwhere\n    T: ToPrimitive,\n    U: NumCast,\n{\n    fn from_geometry(other: Point3<T>) -> Self {\n        (\n            U::from(other.x).unwrap(),\n            U::from(other.y).unwrap(),\n            U::from(other.z).unwrap(),\n        )\n    }\n}\n\nimpl<T> GraphData for Point2<T>\nwhere\n    Self: Copy,\n{\n    type Vertex = Self;\n    type Arc = ();\n    type Edge = ();\n    type Face = ();\n}\n\nimpl<T> GraphData for Point3<T>\nwhere\n    Self: Copy,\n{\n    type Vertex = Self;\n    type Arc = ();\n    type Edge = ();\n    type Face = ();\n}\n\nimpl<T> UnitGeometry for Point3<T> {}\n\nmacro_rules! with_constrained_scalars {\n    ($f:ident) => {\n        $f!(proxy => Real);\n        $f!(proxy => ExtendedReal);\n        $f!(proxy => Total);\n    };\n}\n\nmacro_rules! with_geometric_structures {\n    ($f:ident) => {\n        $f!(geometry => Vector2);\n        $f!(geometry => Vector3);\n        $f!(geometry => Point2);\n        $f!(geometry => Point3);\n    };\n}\n\nmacro_rules! impl_from_geometry_for_constrained_scalar_structures {\n    () => {\n        with_constrained_scalars!(impl_from_geometry_for_constrained_scalar_structures);\n    };\n    (proxy => $p:ident) => {\n        macro_rules! impl_from_geometry_for_scalar_structure {\n            () => {\n                with_geometric_structures!(impl_from_geometry_for_scalar_structure);\n            };\n            (geometry => $g:ident) => {\n                impl<T> FromGeometry<$g<$p<T>>> for $g<T>\n                where\n                    T: Primitive,\n                {\n                    fn from_geometry(other: $g<$p<T>>) -> Self {\n                        other.map(|value| value.into_inner())\n                    }\n                }\n\n                impl<T> FromGeometry<$g<T>> for $g<$p<T>>\n                where\n                    T: Primitive,\n                {\n                    fn from_geometry(other: $g<T>) -> Self {\n                        other.map($p::<T>::assert)\n                    }\n                }\n            };\n        }\n        impl_from_geometry_for_scalar_structure!();\n    };\n}\nimpl_from_geometry_for_constrained_scalar_structures!();\n"
  },
  {
    "path": "plexus/src/integration/glam.rs",
    "content": "#![cfg(feature = \"geometry-glam\")]\n\nuse glam::{Vec2, Vec3, Vec3A};\n\nuse crate::geometry::{FromGeometry, UnitGeometry};\nuse crate::graph::GraphData;\n\nimpl FromGeometry<(f32, f32)> for Vec2 {\n    fn from_geometry(other: (f32, f32)) -> Self {\n        Self::from(other)\n    }\n}\n\nimpl FromGeometry<(f32, f32, f32)> for Vec3 {\n    fn from_geometry(other: (f32, f32, f32)) -> Self {\n        Self::from(other)\n    }\n}\n\nimpl FromGeometry<(f32, f32, f32)> for Vec3A {\n    fn from_geometry(other: (f32, f32, f32)) -> Self {\n        Self::from(other)\n    }\n}\n\nimpl GraphData for Vec2 {\n    type Vertex = Self;\n    type Arc = ();\n    type Edge = ();\n    type Face = ();\n}\n\nimpl GraphData for Vec3 {\n    type Vertex = Self;\n    type Arc = ();\n    type Edge = ();\n    type Face = ();\n}\n\nimpl GraphData for Vec3A {\n    type Vertex = Self;\n    type Arc = ();\n    type Edge = ();\n    type Face = ();\n}\n\nimpl UnitGeometry for Vec2 {}\n\nimpl UnitGeometry for Vec3 {}\n\nimpl UnitGeometry for Vec3A {}\n"
  },
  {
    "path": "plexus/src/integration/mint.rs",
    "content": "#![cfg(feature = \"geometry-mint\")]\n\nuse decorum::{ExtendedReal, Primitive, Real, Total};\nuse mint::{Point2, Point3, Vector2, Vector3};\nuse num::{NumCast, ToPrimitive};\n\nuse crate::geometry::{FromGeometry, UnitGeometry};\nuse crate::graph::GraphData;\n\nimpl<T, U> FromGeometry<(U, U)> for Vector2<T>\nwhere\n    T: NumCast,\n    U: ToPrimitive,\n{\n    fn from_geometry(other: (U, U)) -> Self {\n        Vector2 {\n            x: T::from(other.0).unwrap(),\n            y: T::from(other.1).unwrap(),\n        }\n    }\n}\n\nimpl<T, U> FromGeometry<Vector2<T>> for (U, U)\nwhere\n    T: ToPrimitive,\n    U: NumCast,\n{\n    fn from_geometry(other: Vector2<T>) -> Self {\n        (U::from(other.x).unwrap(), U::from(other.y).unwrap())\n    }\n}\n\nimpl<T, U> FromGeometry<(U, U, U)> for Vector3<T>\nwhere\n    T: NumCast,\n    U: ToPrimitive,\n{\n    fn from_geometry(other: (U, U, U)) -> Self {\n        Vector3 {\n            x: T::from(other.0).unwrap(),\n            y: T::from(other.1).unwrap(),\n            z: T::from(other.2).unwrap(),\n        }\n    }\n}\n\nimpl<T, U> FromGeometry<Vector3<T>> for (U, U, U)\nwhere\n    T: ToPrimitive,\n    U: NumCast,\n{\n    fn from_geometry(other: Vector3<T>) -> Self {\n        (\n            U::from(other.x).unwrap(),\n            U::from(other.y).unwrap(),\n            U::from(other.z).unwrap(),\n        )\n    }\n}\n\nimpl<T, U> FromGeometry<(U, U)> for Point2<T>\nwhere\n    T: NumCast,\n    U: ToPrimitive,\n{\n    fn from_geometry(other: (U, U)) -> Self {\n        Point2 {\n            x: T::from(other.0).unwrap(),\n            y: T::from(other.1).unwrap(),\n        }\n    }\n}\n\nimpl<T, U> FromGeometry<Point2<T>> for (U, U)\nwhere\n    T: ToPrimitive,\n    U: NumCast,\n{\n    fn from_geometry(other: Point2<T>) -> Self {\n        (U::from(other.x).unwrap(), U::from(other.y).unwrap())\n    }\n}\n\nimpl<T> UnitGeometry for Point2<T> {}\n\nimpl<T, U> FromGeometry<(U, U, U)> for Point3<T>\nwhere\n    T: NumCast,\n    U: ToPrimitive,\n{\n    fn from_geometry(other: (U, U, U)) -> Self {\n        Point3 {\n            x: T::from(other.0).unwrap(),\n            y: T::from(other.1).unwrap(),\n            z: T::from(other.2).unwrap(),\n        }\n    }\n}\n\nimpl<T, U> FromGeometry<Point3<T>> for (U, U, U)\nwhere\n    T: ToPrimitive,\n    U: NumCast,\n{\n    fn from_geometry(other: Point3<T>) -> Self {\n        (\n            U::from(other.x).unwrap(),\n            U::from(other.y).unwrap(),\n            U::from(other.z).unwrap(),\n        )\n    }\n}\n\nimpl<T> GraphData for Point2<T>\nwhere\n    Self: Copy,\n{\n    type Vertex = Self;\n    type Arc = ();\n    type Edge = ();\n    type Face = ();\n}\n\nimpl<T> GraphData for Point3<T>\nwhere\n    Self: Copy,\n{\n    type Vertex = Self;\n    type Arc = ();\n    type Edge = ();\n    type Face = ();\n}\n\nimpl<T> UnitGeometry for Point3<T> {}\n\nmacro_rules! with_constrained_scalars {\n    ($f:ident) => {\n        $f!(proxy => Real);\n        $f!(proxy => ExtendedReal);\n        $f!(proxy => Total);\n    };\n}\n\nmacro_rules! impl_from_geometry_for_constrained_scalar_structures {\n    () => {\n        with_constrained_scalars!(impl_from_geometry_for_constrained_scalar_structures);\n    };\n    (proxy => $p:ident) => {\n        impl<T> FromGeometry<Vector2<$p<T>>> for Vector2<T>\n        where\n            T: Primitive,\n        {\n            fn from_geometry(other: Vector2<$p<T>>) -> Self {\n                Vector2 {\n                    x: other.x.into_inner(),\n                    y: other.y.into_inner(),\n                }\n            }\n        }\n\n        impl<T> FromGeometry<Vector2<T>> for Vector2<$p<T>>\n        where\n            T: Primitive,\n        {\n            fn from_geometry(other: Vector2<T>) -> Self {\n                Vector2 {\n                    x: $p::<T>::assert(other.x),\n                    y: $p::<T>::assert(other.y),\n                }\n            }\n        }\n\n        impl<T> FromGeometry<Vector3<$p<T>>> for Vector3<T>\n        where\n            T: Primitive,\n        {\n            fn from_geometry(other: Vector3<$p<T>>) -> Self {\n                Vector3 {\n                    x: other.x.into_inner(),\n                    y: other.y.into_inner(),\n                    z: other.z.into_inner(),\n                }\n            }\n        }\n\n        impl<T> FromGeometry<Vector3<T>> for Vector3<$p<T>>\n        where\n            T: Primitive,\n        {\n            fn from_geometry(other: Vector3<T>) -> Self {\n                Vector3 {\n                    x: $p::<T>::assert(other.x),\n                    y: $p::<T>::assert(other.y),\n                    z: $p::<T>::assert(other.z),\n                }\n            }\n        }\n\n        impl<T> FromGeometry<Point2<$p<T>>> for Point2<T>\n        where\n            T: Primitive,\n        {\n            fn from_geometry(other: Point2<$p<T>>) -> Self {\n                Point2 {\n                    x: other.x.into_inner(),\n                    y: other.y.into_inner(),\n                }\n            }\n        }\n\n        impl<T> FromGeometry<Point2<T>> for Point2<$p<T>>\n        where\n            T: Primitive,\n        {\n            fn from_geometry(other: Point2<T>) -> Self {\n                Point2 {\n                    x: $p::<T>::assert(other.x),\n                    y: $p::<T>::assert(other.y),\n                }\n            }\n        }\n\n        impl<T> FromGeometry<Point3<$p<T>>> for Point3<T>\n        where\n            T: Primitive,\n        {\n            fn from_geometry(other: Point3<$p<T>>) -> Self {\n                Point3 {\n                    x: other.x.into_inner(),\n                    y: other.y.into_inner(),\n                    z: other.z.into_inner(),\n                }\n            }\n        }\n\n        impl<T> FromGeometry<Point3<T>> for Point3<$p<T>>\n        where\n            T: Primitive,\n        {\n            fn from_geometry(other: Point3<T>) -> Self {\n                Point3 {\n                    x: $p::<T>::assert(other.x),\n                    y: $p::<T>::assert(other.y),\n                    z: $p::<T>::assert(other.z),\n                }\n            }\n        }\n    };\n}\nimpl_from_geometry_for_constrained_scalar_structures!();\n"
  },
  {
    "path": "plexus/src/integration/mod.rs",
    "content": "//! Integration of external crates and foreign types.\n//!\n//! This module provides implementations of traits in Plexus for foreign types.\n\n// TODO: Do not implement geometric traits and conversions over tuples of scalars. Prefer array\n//       types instead.\n\nmod cgmath;\nmod glam;\nmod mint;\nmod nalgebra;\nmod ultraviolet;\n"
  },
  {
    "path": "plexus/src/integration/nalgebra.rs",
    "content": "#![cfg(feature = \"geometry-nalgebra\")]\n\nuse decorum::{ExtendedReal, Primitive, Real, Total};\nuse nalgebra::base::allocator::Allocator;\nuse nalgebra::{\n    DefaultAllocator, DimName, OMatrix, OPoint, Point2, Point3, Scalar, Vector2, Vector3,\n};\nuse num::{NumCast, ToPrimitive};\n\nuse crate::geometry::{FromGeometry, UnitGeometry};\nuse crate::graph::GraphData;\n\nimpl<T, U> FromGeometry<(U, U)> for Vector2<T>\nwhere\n    T: NumCast + Scalar,\n    U: ToPrimitive,\n{\n    fn from_geometry(other: (U, U)) -> Self {\n        Vector2::new(T::from(other.0).unwrap(), T::from(other.1).unwrap())\n    }\n}\n\nimpl<T, U> FromGeometry<Vector2<T>> for (U, U)\nwhere\n    T: Scalar + ToPrimitive,\n    U: NumCast,\n{\n    fn from_geometry(other: Vector2<T>) -> Self {\n        let [x, y]: [T; 2] = other.into();\n        (U::from(x).unwrap(), U::from(y).unwrap())\n    }\n}\n\nimpl<T, U> FromGeometry<(U, U, U)> for Vector3<T>\nwhere\n    T: NumCast + Scalar,\n    U: ToPrimitive,\n{\n    fn from_geometry(other: (U, U, U)) -> Self {\n        Vector3::new(\n            T::from(other.0).unwrap(),\n            T::from(other.1).unwrap(),\n            T::from(other.2).unwrap(),\n        )\n    }\n}\n\nimpl<T, U> FromGeometry<Vector3<T>> for (U, U, U)\nwhere\n    T: Scalar + ToPrimitive,\n    U: NumCast,\n{\n    fn from_geometry(other: Vector3<T>) -> Self {\n        let [x, y, z]: [T; 3] = other.into();\n        (\n            U::from(x).unwrap(),\n            U::from(y).unwrap(),\n            U::from(z).unwrap(),\n        )\n    }\n}\n\nimpl<T, U> FromGeometry<(U, U)> for Point2<T>\nwhere\n    T: NumCast + Scalar,\n    U: ToPrimitive,\n{\n    fn from_geometry(other: (U, U)) -> Self {\n        Point2::new(T::from(other.0).unwrap(), T::from(other.1).unwrap())\n    }\n}\n\nimpl<T, U> FromGeometry<Point2<T>> for (U, U)\nwhere\n    T: Scalar + ToPrimitive,\n    U: NumCast,\n{\n    fn from_geometry(other: Point2<T>) -> Self {\n        let [x, y]: [T; 2] = other.coords.into();\n        (U::from(x).unwrap(), U::from(y).unwrap())\n    }\n}\n\nimpl<T, U> FromGeometry<(U, U, U)> for Point3<T>\nwhere\n    T: NumCast + Scalar,\n    U: ToPrimitive,\n{\n    fn from_geometry(other: (U, U, U)) -> Self {\n        Point3::new(\n            T::from(other.0).unwrap(),\n            T::from(other.1).unwrap(),\n            T::from(other.2).unwrap(),\n        )\n    }\n}\n\nimpl<T, U> FromGeometry<Point3<T>> for (U, U, U)\nwhere\n    T: Scalar + ToPrimitive,\n    U: NumCast,\n{\n    fn from_geometry(other: Point3<T>) -> Self {\n        let [x, y, z]: [T; 3] = other.coords.into();\n        (\n            U::from(x).unwrap(),\n            U::from(y).unwrap(),\n            U::from(z).unwrap(),\n        )\n    }\n}\n\nimpl<T, D> GraphData for OPoint<T, D>\nwhere\n    T: Scalar,\n    D: DimName,\n    DefaultAllocator: Allocator<D>,\n    Self: Copy,\n{\n    type Vertex = Self;\n    type Arc = ();\n    type Edge = ();\n    type Face = ();\n}\n\nimpl<T, D> UnitGeometry for OPoint<T, D>\nwhere\n    T: Scalar,\n    D: DimName,\n    DefaultAllocator: Allocator<D>,\n{\n}\n\nmacro_rules! with_constrained_scalars {\n    ($f:ident) => {\n        $f!(proxy => Real);\n        $f!(proxy => ExtendedReal);\n        $f!(proxy => Total);\n    };\n}\n\nmacro_rules! impl_from_geometry_for_constrained_scalar_structures {\n    () => {\n        with_constrained_scalars!(impl_from_geometry_for_constrained_scalar_structures);\n    };\n    (proxy => $p:ident) => {\n        impl<T, R, C> FromGeometry<OMatrix<$p<T>, R, C>> for OMatrix<T, R, C>\n        where\n            T: Primitive + Scalar,\n            R: DimName,\n            C: DimName,\n            DefaultAllocator: Allocator<R, C>,\n        {\n            fn from_geometry(other: OMatrix<$p<T>, R, C>) -> Self {\n                other.map(|value| value.into_inner())\n            }\n        }\n\n        impl<T, R, C> FromGeometry<OMatrix<T, R, C>> for OMatrix<$p<T>, R, C>\n        where\n            T: Primitive + Scalar,\n            R: DimName,\n            C: DimName,\n            DefaultAllocator: Allocator<R, C>,\n        {\n            fn from_geometry(other: OMatrix<T, R, C>) -> Self {\n                other.map($p::<T>::assert)\n            }\n        }\n\n        impl<T, D> FromGeometry<OPoint<$p<T>, D>> for OPoint<T, D>\n        where\n            T: Primitive + Scalar,\n            D: DimName,\n            DefaultAllocator: Allocator<D>,\n        {\n            fn from_geometry(other: OPoint<$p<T>, D>) -> Self {\n                OPoint::from(other.coords.map(|value| value.into_inner()))\n            }\n        }\n\n        impl<T, D> FromGeometry<OPoint<T, D>> for OPoint<$p<T>, D>\n        where\n            T: Primitive + Scalar,\n            D: DimName,\n            DefaultAllocator: Allocator<D>,\n        {\n            fn from_geometry(other: OPoint<T, D>) -> Self {\n                OPoint::from(other.coords.map($p::<T>::assert))\n            }\n        }\n    };\n}\nimpl_from_geometry_for_constrained_scalar_structures!();\n"
  },
  {
    "path": "plexus/src/integration/ultraviolet.rs",
    "content": "#![cfg(feature = \"geometry-ultraviolet\")]\n\nuse ultraviolet::vec::{Vec2, Vec3};\n\nuse crate::geometry::{FromGeometry, UnitGeometry};\nuse crate::graph::GraphData;\n\nimpl FromGeometry<(f32, f32)> for Vec2 {\n    fn from_geometry(other: (f32, f32)) -> Self {\n        Self::from(other)\n    }\n}\n\nimpl FromGeometry<(f32, f32, f32)> for Vec3 {\n    fn from_geometry(other: (f32, f32, f32)) -> Self {\n        Self::from(other)\n    }\n}\n\nimpl GraphData for Vec2 {\n    type Vertex = Self;\n    type Arc = ();\n    type Edge = ();\n    type Face = ();\n}\n\nimpl GraphData for Vec3 {\n    type Vertex = Self;\n    type Arc = ();\n    type Edge = ();\n    type Face = ();\n}\n\nimpl UnitGeometry for Vec2 {}\n\nimpl UnitGeometry for Vec3 {}\n"
  },
  {
    "path": "plexus/src/lib.rs",
    "content": "//! **Plexus** is a highly composable library for polygonal mesh processing.\n//!\n//! Versions of Plexus in the `0.0.*` series are experimental and unstable.\n//! Consider depending on the development branch of the repository. See [the\n//! website][website] for the latest information and documentation.\n//!\n//! [website]: https://plexus.rs\n\n#![doc(html_favicon_url = \"https://plexus.rs/img/favicon.ico\")]\n#![doc(html_logo_url = \"https://plexus.rs/img/plexus.svg\")]\n\nmod entity;\nmod integration;\nmod transact;\n\npub mod buffer;\npub mod builder;\npub mod constant;\npub mod encoding;\npub mod geometry;\npub mod graph;\npub mod index;\npub mod primitive;\n\nuse arrayvec::ArrayVec;\nuse itertools::{self, Itertools, MinMaxResult, MultiPeek};\nuse std::borrow::Borrow;\nuse std::fmt::Debug;\n\nuse crate::entity::view::ClosedView;\n\npub mod prelude {\n    //! Re-exports of commonly used types and traits.\n    //!\n    //! Importing the contents of this module is recommended, especially when\n    //! working with generators and iterator expressions, as those operations\n    //! are expressed mostly through traits.\n    //!\n    //! # Traits\n    //!\n    //! Traits from the [`primitive`] module for generating and decomposing\n    //! iterators of topological data (e.g., [`Trigon`], [`Tetragon`], etc.) are\n    //! re-exported so that functions in iterator expressions can be used more\n    //! easily.\n    //!\n    //! Traits for (de)constructing [`MeshBuffer`]s and [`MeshGraph`]s are\n    //! re-exported. These traits allow mesh types to be constructed from raw\n    //! buffers and buffers to be re-indexed.\n    //!\n    //! Extension traits are also re-exported.\n    //!\n    //! # Types\n    //!\n    //! The [`Selector`] `enum` and its variants are re-exported for\n    //! convenience.\n    //!\n    //! [`MeshBuffer`]: crate::buffer::MeshBuffer\n    //! [`MeshGraph`]: crate::graph::MeshGraph\n    //! [`Selector`]: crate::graph::Selector\n    //! [`Tetragon`]: crate::primitive::Tetragon\n    //! [`Trigon`]: crate::primitive::Trigon\n    //! [`primitive`]: crate::primitive\n\n    pub use crate::buffer::{\n        FromRawBuffers as _, FromRawBuffersWithArity as _, IntoFlatIndex as _,\n        IntoStructuredIndex as _,\n    };\n    pub use crate::builder::{FacetBuilder as _, MeshBuilder as _, SurfaceBuilder as _};\n    pub use crate::geometry::{FromGeometry as _, IntoGeometry as _};\n    pub use crate::graph::{ClosedView as _, Rebind as _, Selector};\n    pub use crate::index::{CollectWithIndexer as _, IndexVertices as _};\n    pub use crate::primitive::decompose::{\n        Edges as _, IntoEdges as _, IntoSubdivisions as _, IntoTetrahedrons as _, IntoTrigons as _,\n        IntoVertices as _, Subdivide as _, Tetrahedrons as _, Triangulate as _, Vertices as _,\n    };\n    pub use crate::primitive::generate::Generator as _;\n    pub use crate::primitive::{\n        IntoPolygons as _, MapVertices as _, Polygonal as _, Topological as _,\n    };\n    pub use crate::DynamicArity as _;\n    pub use crate::IteratorExt as _;\n\n    pub use Selector::ByIndex;\n    pub use Selector::ByKey;\n}\n\n/// Arity of primitives and polygonal meshes.\n///\n/// The _arity_ of a primitive topological structure (e.g., an edge, trigon,\n/// pentagon, etc.) is the number of edges that comprise the structure. For\n/// compound structures like polygonal meshes, arity describes the individual\n/// polygons that form the structure and may not be representable as a singular\n/// value.\n///\n/// Arity is most generally described as an _open interval_ with a minimum and\n/// optional maximum inclusive range. This trait provides a conversion into this\n/// general form for all types that represent arity. See the implementations of\n/// this trait for more information.\n///\n/// Types with arity implement the [`StaticArity`] and [`DynamicArity`] traits,\n/// which describe their type-level and value-level arity, respectively.\n///\n/// [`DynamicArity`]: crate::DynamicArity\n/// [`StaticArity`]: crate::StaticArity\npub trait Arity: Copy {\n    fn into_interval(self) -> (usize, Option<usize>);\n}\n\n/// Singular arity.\nimpl Arity for usize {\n    fn into_interval(self) -> (usize, Option<usize>) {\n        (self, Some(self))\n    }\n}\n\n/// Closed interval arity.\n///\n/// This type represents a _closed interval_ arity with a minimum and maximum\n/// inclusive range.\nimpl Arity for (usize, usize) {\n    fn into_interval(self) -> (usize, Option<usize>) {\n        let (min, max) = self;\n        (min, Some(max))\n    }\n}\n\n/// Open interval arity.\n///\n/// This type represents an _open interval_ arity with a minimum and optional\n/// maximum inclusive range. When there is no maximum (`None`), the maximum\n/// arity is unspecified. This typically means that there is no theoretical\n/// maximum.\nimpl Arity for (usize, Option<usize>) {\n    fn into_interval(self) -> (usize, Option<usize>) {\n        self\n    }\n}\n\n/// Type-level arity.\n///\n/// This trait specifies the arity that a type supports. Values of a\n/// `StaticArity` type have an arity that reflects this constant, which may be\n/// any type or form implementing the [`Arity`] trait.\n///\n/// [`Arity`]: crate::Arity\npub trait StaticArity {\n    type Static: Arity;\n\n    const ARITY: Self::Static;\n}\n\n/// Value-level arity.\n///\n/// This trait specifies the arity of a value at runtime. This is often\n/// distinct from the type-level arity of the [`StaticArity`] trait, which\n/// expresses the capabilities of a type.\n///\n/// [`StaticArity`]: crate::StaticArity\npub trait DynamicArity: StaticArity {\n    type Dynamic: Arity;\n\n    fn arity(&self) -> Self::Dynamic;\n}\n\n/// Topological types with fixed and singular arity.\n///\n/// Types are _monomorphic_ if they have a fixed and singular arity as types and\n/// values. For example, [`Trigon`] always and only represents a trigon\n/// (triangle) with an arity of three. [`Trigon`] values always have an arity of\n/// three and types composed of only [`Trigon`]s have a compound arity of three.\n///\n/// This contrasts _polymorphic_ types like [`BoundedPolygon`], which have an\n/// interval arity at the type-level and a singular but varying arity for values\n/// (because a [`BoundedPolygon`] value may be either a trigon or tertragon).\n///\n/// [`BoundedPolygon`]: crate::primitive::BoundedPolygon\n/// [`Trigon`]: crate::primitive::Trigon\npub trait Monomorphic: StaticArity<Static = usize> {}\n\n/// Arity of a compound structure.\n///\n/// `MeshArity` represents the arity of a compound structure, which may be\n/// _uniform_ or _non-uniform_. This is typically the value-level arity for\n/// mesh data structures like [`MeshGraph`] and [`MeshBuffer`].\n///\n/// [`MeshBuffer`]: crate::buffer::MeshBuffer\n/// [`MeshGraph`]: crate::graph::MeshGraph\n#[derive(Clone, Copy, Debug, Eq, PartialEq)]\npub enum MeshArity {\n    /// A compound structure has _uniform_ arity if all of its components have\n    /// the same arity, such as a [`MeshBuffer`] composed entirely of trigons.\n    ///\n    /// [`MeshBuffer`]: crate::buffer::MeshBuffer\n    Uniform(usize),\n    /// A compound structure has _non-uniform_ arity if the arity of its\n    /// components differ, such as a [`MeshGraph`] composed of trigons and\n    /// tetragons.\n    ///\n    /// Non-uniform arity is represented as an inclusive range known as an\n    /// _interval_. This is the minimum and maximum arity of the components, in\n    /// that order.\n    ///\n    /// [`MeshGraph`]: crate::graph::MeshGraph\n    NonUniform(usize, usize),\n}\n\nimpl MeshArity {\n    pub fn from_components<T, I>(components: I) -> Self\n    where\n        T: DynamicArity<Dynamic = usize>,\n        I: IntoIterator,\n        I::Item: Borrow<T>,\n    {\n        match components\n            .into_iter()\n            .map(|component| component.borrow().arity())\n            .minmax()\n        {\n            MinMaxResult::OneElement(exact) => MeshArity::Uniform(exact),\n            MinMaxResult::MinMax(min, max) => MeshArity::NonUniform(min, max),\n            _ => MeshArity::Uniform(0),\n        }\n    }\n}\n\nimpl Arity for MeshArity {\n    fn into_interval(self) -> (usize, Option<usize>) {\n        match self {\n            MeshArity::Uniform(exact) => (exact, Some(exact)),\n            MeshArity::NonUniform(min, max) => (min, Some(max)),\n        }\n    }\n}\n\npub trait TryFromIterator<T>: Sized {\n    type Error;\n\n    fn try_from_iter<I>(items: I) -> Result<Self, Self::Error>\n    where\n        I: Iterator<Item = T>;\n}\n\nimpl<T, const N: usize> TryFromIterator<T> for [T; N] {\n    type Error = ();\n\n    fn try_from_iter<I>(items: I) -> Result<Self, Self::Error>\n    where\n        I: Iterator<Item = T>,\n    {\n        items\n            .has_exactly(N)\n            .and_then(|items| items.collect::<ArrayVec<T, N>>().into_inner().ok())\n            .ok_or(())\n    }\n}\n\nmacro_rules! count {\n    ($x:tt $($xs:tt)*) => (1usize + count!($($xs)*));\n    () => (0usize);\n}\nmacro_rules! substitute {\n    ($_t:tt, $with:ty) => {\n        $with\n    };\n}\nmacro_rules! impl_try_from_iterator {\n    (tuples => ($($i:ident),+)) => (\n        impl<T> TryFromIterator<T> for ($(substitute!(($i), T),)+) {\n            type Error = ();\n\n            // LINT: The `i` metavariable items are conventionally uppercase and represent type\n            //       names. Here, these names are substituted, but uppercase is used for\n            //       consistency.\n            #[expect(non_snake_case)]\n            fn try_from_iter<I>(items: I) -> Result<Self, Self::Error>\n            where\n                I: Iterator<Item = T>,\n            {\n                use $crate::IteratorExt as _;\n\n                items\n                    .has_exactly(count!($($i)*))\n                    .map(|mut items| {\n                        $(let $i = items.next().unwrap();)*\n                        ($($i,)*)\n                    })\n                    .ok_or(())\n            }\n        }\n    );\n}\nimpl_try_from_iterator!(tuples => (A, B));\nimpl_try_from_iterator!(tuples => (A, B, C));\nimpl_try_from_iterator!(tuples => (A, B, C, D));\nimpl_try_from_iterator!(tuples => (A, B, C, D, E));\nimpl_try_from_iterator!(tuples => (A, B, C, D, E, F));\n\n/// Extension methods for types implementing [`Iterator`].\n///\n/// [`Iterator`]: std::iter::Iterator\npub trait IteratorExt: Iterator + Sized {\n    /// Provides an iterator over a window of duplets that includes the first\n    /// item in the sequence at both the beginning and end of the iteration.\n    ///\n    /// Given a collection of ordered items $(a,b,c)$, this iterator yeilds the\n    /// ordered items $((a,b),(b,c),(c,a))$.\n    fn perimeter(self) -> Perimeter<Self>\n    where\n        Self::Item: Clone,\n    {\n        Perimeter::new(self)\n    }\n\n    /// Maps an iterator over [`graph`] views to the keys of those views.\n    ///\n    /// It is often useful to examine or collect the keys of views over a\n    /// [`MeshGraph`]. This iterator avoids redundant use of\n    /// [`map`][`Iterator::map`] to extract keys.\n    ///\n    /// # Examples\n    ///\n    /// Collecting keys of faces before a topological mutation in a\n    /// [`MeshGraph`]:\n    ///\n    /// ```rust\n    /// # extern crate decorum;\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use decorum::Total;\n    /// use nalgebra::Point3;\n    /// use plexus::graph::MeshGraph;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::generate::Position;\n    /// use plexus::primitive::sphere::UvSphere;\n    ///\n    /// type E3 = Point3<Total<f64>>;\n    ///\n    /// let mut graph = UvSphere::new(6, 6)\n    ///     .polygons::<Position<E3>>()\n    ///     .collect::<MeshGraph<E3>>();\n    ///\n    /// let keys = graph\n    ///     .faces()\n    ///     .filter(|face| face.arity() > 3)\n    ///     .keys()\n    ///     .collect::<Vec<_>>();\n    /// for key in keys {\n    ///     graph.face_mut(key).unwrap().poke_with_offset(0.5);\n    /// }\n    /// ```\n    ///\n    /// [`Iterator::map`]: std::iter::Iterator::map\n    /// [`MeshGraph`]: crate::graph::MeshGraph\n    /// [`graph`]: crate::graph\n    fn keys(self) -> Keys<Self>\n    where\n        Self::Item: ClosedView,\n    {\n        Keys::new(self)\n    }\n\n    /// Determines if an iterator provides `n` or more items.\n    ///\n    /// Returns a peekable iterator if the source iterator provides at least `n`\n    /// items, otherwise `None`.\n    ///\n    /// # Examples\n    ///\n    /// Ensuring that an iterator over vertices has an arity of at least three:\n    ///\n    /// ```rust\n    /// use plexus::IteratorExt;\n    ///\n    /// fn is_convex(vertices: impl Iterator<Item = [f64; 2]>) -> bool {\n    ///     vertices\n    ///         .has_at_least(3)\n    ///         .and_then(|vertices| {\n    ///             for vertex in vertices {\n    ///                 // ...\n    ///             }\n    ///             // ...\n    ///             # Some(0usize)\n    ///         })\n    ///         .is_some()\n    /// }\n    /// ```\n    fn has_at_least(self, n: usize) -> Option<MultiPeek<Self>> {\n        peek_n(self, n).map(|mut peekable| {\n            peekable.reset_peek();\n            peekable\n        })\n    }\n\n    fn has_exactly(self, n: usize) -> Option<MultiPeek<Self>> {\n        peek_n(self, n).and_then(|mut peekable| {\n            peekable.peek().is_none().then(|| {\n                peekable.reset_peek();\n                peekable\n            })\n        })\n    }\n\n    fn try_collect<T>(self) -> Result<T, T::Error>\n    where\n        T: TryFromIterator<Self::Item>,\n    {\n        T::try_from_iter(self)\n    }\n}\n\nimpl<I> IteratorExt for I where I: Iterator {}\n\n/// Iterator that produces a window of duplets over its input.\n///\n/// The duplets produced include the first item in the input at both the\n/// beginning and end of the iteration, forming a perimeter. Given a collection\n/// of ordered items $(a,b,c)$, this iterator yields the ordered items\n/// $((a,b),(b,c),(c,a))$.\n///\n/// See [`IteratorExt::perimeter`].\n///\n/// [`IteratorExt::perimeter`]: crate::IteratorExt::perimeter\n#[derive(Clone)]\npub struct Perimeter<I>\nwhere\n    I: Iterator,\n    I::Item: Clone,\n{\n    input: I,\n    first: Option<I::Item>,\n    previous: Option<I::Item>,\n}\n\nimpl<I> Perimeter<I>\nwhere\n    I: Iterator,\n    I::Item: Clone,\n{\n    fn new(mut input: I) -> Self {\n        let first = input.next();\n        let previous = first.clone();\n        Perimeter {\n            input,\n            first,\n            previous,\n        }\n    }\n}\n\nimpl<I> Iterator for Perimeter<I>\nwhere\n    I: Iterator,\n    I::Item: Clone,\n{\n    type Item = (I::Item, I::Item);\n\n    fn next(&mut self) -> Option<Self::Item> {\n        let next = self.input.next();\n        self.previous\n            .clone()\n            .zip(next.or_else(|| self.first.take()))\n            .map(|(a, b)| {\n                self.previous = Some(b.clone());\n                (a, b)\n            })\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        self.input.size_hint()\n    }\n}\n\n/// Iterator that maps [`graph`] views to their keys.\n///\n/// See [`IteratorExt::keys`].\n///\n/// [`graph`]: crate::graph\n/// [`IteratorExt::keys`]: crate::IteratorExt::keys\n#[derive(Clone)]\npub struct Keys<I>\nwhere\n    I: Iterator,\n    I::Item: ClosedView,\n{\n    input: I,\n}\n\nimpl<I> Keys<I>\nwhere\n    I: Iterator,\n    I::Item: ClosedView,\n{\n    fn new(input: I) -> Self {\n        Keys { input }\n    }\n}\n\nimpl<I> Iterator for Keys<I>\nwhere\n    I: Iterator,\n    I::Item: ClosedView,\n{\n    type Item = <I::Item as ClosedView>::Key;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        self.input.next().map(|view| view.key())\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        self.input.size_hint()\n    }\n}\n\nfn peek_n<I>(input: I, n: usize) -> Option<MultiPeek<I>>\nwhere\n    I: Iterator,\n{\n    let mut peekable = itertools::multipeek(input);\n    for _ in 0..n {\n        peekable.peek()?;\n    }\n    Some(peekable)\n}\n\n/// Computes the arity of a polygon with `n` vertices.\n///\n/// For `n` greater than two, these values are the same and well-formed. For `n`\n/// less than three, the polygon is degenerate (a digon, monogon, or zerogon),\n/// all of which are assigned an arity of one. Note that some topological types\n/// do not allow `n` being one nor zero.\nconst fn n_arity(n: usize) -> usize {\n    if n < 3 {\n        1\n    }\n    else {\n        n\n    }\n}\n"
  },
  {
    "path": "plexus/src/primitive/cube.rs",
    "content": "//! Cube primitives.\n//!\n//! # Examples\n//!\n//! ```rust\n//! # extern crate decorum;\n//! # extern crate nalgebra;\n//! # extern crate plexus;\n//! #\n//! use decorum::R32;\n//! use nalgebra::Point3;\n//! use plexus::graph::MeshGraph;\n//! use plexus::prelude::*;\n//! use plexus::primitive::cube::Cube;\n//! use plexus::primitive::generate::Position;\n//!\n//! let mut graph = Cube::new()\n//!     .polygons::<Position<Point3<R32>>>()\n//!     .collect::<MeshGraph<Point3<R32>>>();\n//! ```\n\nuse num::One;\nuse theon::adjunct::{Converged, Map};\nuse theon::query::Unit;\nuse theon::space::{Basis, EuclideanSpace, FiniteDimensional, InnerSpace, Scalar, Vector};\nuse typenum::U3;\n\nuse crate::primitive::generate::{\n    Attribute, AttributeGenerator, AttributePolygonGenerator, AttributeVertexGenerator, Generator,\n    IndexingPolygonGenerator, Normal, PolygonGenerator, Position,\n};\nuse crate::primitive::Tetragon;\n\n#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]\npub enum Plane {\n    Xy,  // front\n    Nxy, // back\n    Yz,  // right\n    Nyz, // left\n    Xz,  // bottom\n    Nxz, // top\n}\n\nimpl Plane {\n    pub fn normal<S>(self) -> Unit<S>\n    where\n        S: Basis + FiniteDimensional<N = U3> + InnerSpace,\n    {\n        match self {\n            Plane::Xy => Unit::<S>::z(),   // front\n            Plane::Nxy => -Unit::<S>::z(), // back\n            Plane::Yz => Unit::<S>::x(),   // right\n            Plane::Nyz => -Unit::<S>::x(), // left\n            Plane::Xz => -Unit::<S>::y(),  // bottom\n            Plane::Nxz => Unit::<S>::y(),  // top\n        }\n    }\n}\n\nimpl Attribute for Plane {}\n\n#[derive(Clone, Copy)]\npub struct Bounds<S>\nwhere\n    S: EuclideanSpace,\n{\n    lower: Scalar<S>,\n    upper: Scalar<S>,\n}\n\nimpl<S> Bounds<S>\nwhere\n    S: EuclideanSpace,\n{\n    pub fn with_radius(radius: Scalar<S>) -> Self {\n        Bounds {\n            lower: -radius,\n            upper: radius,\n        }\n    }\n\n    pub fn with_width(width: Scalar<S>) -> Self {\n        Self::with_radius(width / (Scalar::<S>::one() + One::one()))\n    }\n\n    pub fn unit_radius() -> Self {\n        Self::with_radius(One::one())\n    }\n\n    pub fn unit_width() -> Self {\n        Self::with_width(One::one())\n    }\n}\n\nimpl<S> Default for Bounds<S>\nwhere\n    S: EuclideanSpace,\n{\n    fn default() -> Self {\n        Self::unit_width()\n    }\n}\n\n#[derive(Clone, Copy)]\npub struct Cube;\n\nimpl Cube {\n    pub fn new() -> Self {\n        Cube\n    }\n}\n\nimpl Default for Cube {\n    fn default() -> Self {\n        Cube::new()\n    }\n}\n\nimpl PolygonGenerator for Cube {\n    fn polygon_count(&self) -> usize {\n        6\n    }\n}\n\nimpl<S> AttributeGenerator<Normal<S>> for Cube\nwhere\n    S: EuclideanSpace + FiniteDimensional<N = U3>,\n{\n    type State = ();\n}\n\nimpl<S> AttributeVertexGenerator<Normal<S>> for Cube\nwhere\n    S: EuclideanSpace + FiniteDimensional<N = U3>,\n{\n    type Output = Unit<Vector<S>>;\n\n    fn vertex_count(&self) -> usize {\n        self.polygon_count()\n    }\n\n    fn vertex_from(&self, _: &Self::State, index: usize) -> Self::Output {\n        AttributeVertexGenerator::<Plane>::vertex_from(self, &(), index).normal::<Vector<S>>()\n    }\n}\n\nimpl<S> AttributePolygonGenerator<Normal<S>> for Cube\nwhere\n    S: EuclideanSpace + FiniteDimensional<N = U3>,\n{\n    type Output = Tetragon<Unit<Vector<S>>>;\n\n    fn polygon_from(&self, state: &Self::State, index: usize) -> Self::Output {\n        IndexingPolygonGenerator::<Normal<S>>::indexing_polygon(self, index)\n            .map(|index| AttributeVertexGenerator::<Normal<S>>::vertex_from(self, state, index))\n    }\n}\n\nimpl<S> IndexingPolygonGenerator<Normal<S>> for Cube {\n    type Output = Tetragon<usize>;\n\n    fn indexing_polygon(&self, index: usize) -> Self::Output {\n        assert!(index < self.polygon_count());\n        Tetragon::converged(index)\n    }\n}\n\nimpl<S> AttributeGenerator<Position<S>> for Cube\nwhere\n    S: EuclideanSpace + FiniteDimensional<N = U3>,\n{\n    type State = Bounds<S>;\n}\n\nimpl<S> AttributeVertexGenerator<Position<S>> for Cube\nwhere\n    S: EuclideanSpace + FiniteDimensional<N = U3>,\n{\n    type Output = S;\n\n    fn vertex_count(&self) -> usize {\n        8\n    }\n\n    fn vertex_from(&self, state: &Self::State, index: usize) -> Self::Output {\n        let x = if index & 0b100 == 0b100 {\n            state.upper\n        }\n        else {\n            state.lower\n        };\n        let y = if index & 0b010 == 0b010 {\n            state.upper\n        }\n        else {\n            state.lower\n        };\n        let z = if index & 0b001 == 0b001 {\n            state.upper\n        }\n        else {\n            state.lower\n        };\n        S::from_xyz(x, y, z)\n    }\n}\n\nimpl<S> AttributePolygonGenerator<Position<S>> for Cube\nwhere\n    S: EuclideanSpace + FiniteDimensional<N = U3>,\n{\n    type Output = Tetragon<S>;\n\n    fn polygon_from(&self, state: &Self::State, index: usize) -> Self::Output {\n        IndexingPolygonGenerator::<Position<S>>::indexing_polygon(self, index)\n            .map(|index| AttributeVertexGenerator::<Position<S>>::vertex_from(self, state, index))\n    }\n}\n\nimpl<S> IndexingPolygonGenerator<Position<S>> for Cube {\n    type Output = Tetragon<usize>;\n\n    fn indexing_polygon(&self, index: usize) -> Self::Output {\n        match index {\n            0 => Tetragon::new(5, 7, 3, 1), // front\n            1 => Tetragon::new(6, 7, 5, 4), // right\n            2 => Tetragon::new(3, 7, 6, 2), // top\n            3 => Tetragon::new(0, 1, 3, 2), // left\n            4 => Tetragon::new(4, 5, 1, 0), // bottom\n            5 => Tetragon::new(0, 2, 6, 4), // back\n            _ => panic!(),\n        }\n    }\n}\n\nimpl AttributeGenerator<Plane> for Cube {\n    type State = ();\n}\n\nimpl AttributeVertexGenerator<Plane> for Cube {\n    type Output = Plane;\n\n    fn vertex_count(&self) -> usize {\n        self.polygon_count()\n    }\n\n    fn vertex_from(&self, _: &Self::State, index: usize) -> Self::Output {\n        match index {\n            0 => Plane::Xy,  // front\n            1 => Plane::Yz,  // right\n            2 => Plane::Nxz, // top\n            3 => Plane::Nyz, // left\n            4 => Plane::Xz,  // bottom\n            5 => Plane::Nxy, // back\n            _ => panic!(),\n        }\n    }\n}\n\nimpl AttributePolygonGenerator<Plane> for Cube {\n    type Output = Tetragon<Plane>;\n\n    fn polygon_from(&self, state: &Self::State, index: usize) -> Self::Output {\n        IndexingPolygonGenerator::<Plane>::indexing_polygon(self, index)\n            .map(|index| AttributeVertexGenerator::<Plane>::vertex_from(self, state, index))\n    }\n}\n\nimpl IndexingPolygonGenerator<Plane> for Cube {\n    type Output = Tetragon<usize>;\n\n    fn indexing_polygon(&self, index: usize) -> Self::Output {\n        match index {\n            0 => Tetragon::converged(0), // front\n            1 => Tetragon::converged(1), // right\n            2 => Tetragon::converged(2), // top\n            3 => Tetragon::converged(3), // left\n            4 => Tetragon::converged(4), // bottom\n            5 => Tetragon::converged(5), // back\n            _ => panic!(),\n        }\n    }\n}\n\nimpl Generator for Cube {}\n"
  },
  {
    "path": "plexus/src/primitive/decompose.rs",
    "content": "//! Decomposition and tessellation.\n//!\n//! The [`Decompose`] iterator uses various traits to decompose and tessellate\n//! iterators of topological structures.\n//!\n//! This module provides two kinds of decomposition traits: conversions and\n//! [`Iterator`] extensions. Conversion traits are implemented by topological\n//! types and decompose a single structure into any number of output structures.\n//! Extensions are implemented for iterators of topological structures and\n//! perform the corresponding conversion on the input items to produce flattened\n//! output. For example, [`IntoTrigons`] converts a [`Polygonal`] type into an\n//! iterator of [`Trigon`]s while [`Triangulate`] does the same to the items of\n//! an iterator.\n//!\n//! Many of these traits are re-exported in the [`prelude`] module.\n//!\n//! # Examples\n//!\n//! Tessellating a [`Tetragon`] into [`Trigon`]s:\n//!\n//! ```rust\n//! # extern crate nalgebra;\n//! # extern crate plexus;\n//! #\n//! use nalgebra::Point2;\n//! use plexus::prelude::*;\n//! use plexus::primitive::Tetragon;\n//!\n//! type E2 = Point2<f64>;\n//!\n//! let square = Tetragon::from([\n//!     E2::new(1.0, 1.0),\n//!     E2::new(-1.0, 1.0),\n//!     E2::new(-1.0, -1.0),\n//!     E2::new(1.0, -1.0),\n//! ]);\n//! let trigons = square.into_trigons();\n//! ```\n//!\n//! Tessellating an iterator of [`Tetragon`]s from a [generator][`generate`]:\n//!\n//! ```rust\n//! # extern crate nalgebra;\n//! # extern crate plexus;\n//! #\n//! use nalgebra::Point3;\n//! use plexus::prelude::*;\n//! use plexus::primitive::cube::Cube;\n//! use plexus::primitive::generate::Position;\n//!\n//! type E3 = Point3<f64>;\n//!\n//! let polygons: Vec<_> = Cube::new()\n//!     .polygons::<Position<E3>>()\n//!     .subdivide()\n//!     .triangulate()\n//!     .collect();\n//! ```\n//!\n//! [`Iterator`]: std::iter::Iterator\n//! [`prelude`]: crate::prelude\n//! [`Decompose`]: crate::primitive::decompose::Decompose\n//! [`IntoTrigons`]: crate::primitive::decompose::IntoTrigons\n//! [`Triangulate`]: crate::primitive::decompose::Triangulate\n//! [`generate`]: crate::primitive::generate\n//! [`Polygonal`]: crate::primitive::Polygonal\n//! [`Tetragon`]: crate::primitive::Tetragon\n//! [`Trigon`]: crate::primitive::Trigon\n\nuse arrayvec::ArrayVec;\nuse std::collections::VecDeque;\nuse std::iter::IntoIterator;\nuse theon::ops::Interpolate;\nuse typenum::{Cmp, Greater, U1};\n\nuse crate::constant::{Constant, ToType, TypeOf};\nuse crate::primitive::{\n    BoundedPolygon, Edge, NGon, Polygonal, Tetragon, Topological, Trigon, UnboundedPolygon,\n};\nuse crate::IteratorExt as _;\n\npub struct Decompose<I, P, Q, R>\nwhere\n    R: IntoIterator<Item = Q>,\n{\n    input: I,\n    output: VecDeque<Q>,\n    f: fn(P) -> R,\n}\n\nimpl<I, P, Q, R> Decompose<I, P, Q, R>\nwhere\n    R: IntoIterator<Item = Q>,\n{\n    pub(in crate::primitive) fn new(input: I, f: fn(P) -> R) -> Self {\n        Decompose {\n            input,\n            output: VecDeque::new(),\n            f,\n        }\n    }\n}\n\nimpl<I, P, R> Decompose<I, P, P, R>\nwhere\n    I: Iterator<Item = P>,\n    R: IntoIterator<Item = P>,\n{\n    /// Reapplies a congruent decomposition.\n    ///\n    /// A decomposition is _congruent_ if its input and output types are the\n    /// same. This is useful when the number of applications is somewhat large\n    /// or variable, in which case chaining calls is impractical or impossible.\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// # extern crate decorum;\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use decorum::R64;\n    /// use nalgebra::Point3;\n    /// use plexus::index::{Flat4, HashIndexer};\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::cube::Cube;\n    /// use plexus::primitive::generate::Position;\n    ///\n    /// let (indices, positions) = Cube::new()\n    ///     .polygons::<Position<Point3<R64>>>()\n    ///     .subdivide()\n    ///     .remap(7) // 8 subdivision operations are applied.\n    ///     .index_vertices::<Flat4, _>(HashIndexer::default());\n    /// ```\n    pub fn remap(self, n: usize) -> Decompose<impl Iterator<Item = P>, P, P, R> {\n        let Decompose { input, output, f } = self;\n        Decompose::new(output.into_iter().rev().chain(remap(n, input, f)), f)\n    }\n}\n\nimpl<I, P, Q, R> Iterator for Decompose<I, P, Q, R>\nwhere\n    I: Iterator<Item = P>,\n    R: IntoIterator<Item = Q>,\n{\n    type Item = Q;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        loop {\n            if let Some(ngon) = self.output.pop_front() {\n                return Some(ngon);\n            }\n            if let Some(ngon) = self.input.next() {\n                self.output.extend((self.f)(ngon));\n            }\n            else {\n                return None;\n            }\n        }\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        let (lower, _) = self.input.size_hint();\n        (lower, None)\n    }\n}\n\npub trait IntoVertices: Topological {\n    type Output: IntoIterator<Item = Self::Vertex>;\n\n    fn into_vertices(self) -> Self::Output;\n}\n\nimpl<T> IntoVertices for T\nwhere\n    T: Topological,\n{\n    type Output = <T as IntoIterator>::IntoIter;\n\n    fn into_vertices(self) -> Self::Output {\n        self.into_iter()\n    }\n}\n\npub trait IntoEdges: Topological {\n    type Output: IntoIterator<Item = Edge<Self::Vertex>>;\n\n    fn into_edges(self) -> Self::Output;\n}\n\npub trait IntoTrigons: Polygonal {\n    type Output: IntoIterator<Item = Trigon<Self::Vertex>>;\n\n    fn into_trigons(self) -> Self::Output;\n}\n\npub trait IntoSubdivisions: Polygonal {\n    type Output: IntoIterator<Item = Self>;\n\n    fn into_subdivisions(self) -> Self::Output;\n}\n\npub trait IntoTetrahedrons: Polygonal {\n    fn into_tetrahedrons(self) -> ArrayVec<Trigon<Self::Vertex>, 4>;\n}\n\nimpl<G, const N: usize> IntoEdges for NGon<G, N>\nwhere\n    G: Clone,\n    Constant<N>: ToType,\n    TypeOf<N>: Cmp<U1, Output = Greater>,\n{\n    // TODO: As of Rust 1.51.1, it is not possible to constrain constant\n    //       generics nor use them in expressions. If and when this is possible,\n    //       do not implement this trait for degenerate `NGon`s and use use an\n    //       `ArrayVec<Edge<Self::Vertex>, {if N == 2 { 1 } else { N }}>` as\n    //       output.\n    type Output = Vec<Edge<Self::Vertex>>;\n\n    fn into_edges(self) -> Self::Output {\n        if N == 2 {\n            // At the time of writing, it is not possible to specialize this\n            // case for `NGon<G, 2>` nor prove to the compiler that `Self` is of\n            // type `Edge<G>` when the condition `N == 2` is `true`.\n            vec![self.into_iter().try_collect().unwrap()]\n        }\n        else {\n            self.into_iter()\n                .perimeter()\n                .map(|(a, b)| Edge::new(a, b))\n                .collect()\n        }\n    }\n}\n\nimpl<T> IntoEdges for BoundedPolygon<T>\nwhere\n    T: Clone,\n{\n    type Output = Vec<Edge<Self::Vertex>>;\n\n    fn into_edges(self) -> Self::Output {\n        match self {\n            BoundedPolygon::N3(trigon) => trigon.into_edges().into_iter().collect(),\n            BoundedPolygon::N4(tetragon) => tetragon.into_edges().into_iter().collect(),\n        }\n    }\n}\n\nimpl<T> IntoEdges for UnboundedPolygon<T>\nwhere\n    T: Clone,\n{\n    type Output = Vec<Edge<Self::Vertex>>;\n\n    fn into_edges(self) -> Self::Output {\n        self.into_iter()\n            .perimeter()\n            .map(|(a, b)| Edge::new(a, b))\n            .collect()\n    }\n}\n\nimpl<T> IntoTrigons for Trigon<T> {\n    type Output = ArrayVec<Trigon<Self::Vertex>, 1>;\n\n    fn into_trigons(self) -> Self::Output {\n        ArrayVec::from([self])\n    }\n}\n\nimpl<T> IntoTrigons for Tetragon<T>\nwhere\n    T: Clone,\n{\n    type Output = ArrayVec<Trigon<Self::Vertex>, 2>;\n\n    fn into_trigons(self) -> Self::Output {\n        let [a, b, c, d] = self.into_array();\n        ArrayVec::from([Trigon::new(a.clone(), b, c.clone()), Trigon::new(c, d, a)])\n    }\n}\n\nimpl<T> IntoTrigons for BoundedPolygon<T>\nwhere\n    T: Clone,\n{\n    type Output = Vec<Trigon<Self::Vertex>>;\n\n    fn into_trigons(self) -> Self::Output {\n        match self {\n            BoundedPolygon::N3(trigon) => trigon.into_trigons().into_iter().collect(),\n            BoundedPolygon::N4(tetragon) => tetragon.into_trigons().into_iter().collect(),\n        }\n    }\n}\n\nimpl<T> IntoSubdivisions for Trigon<T>\nwhere\n    T: Clone + Interpolate<Output = T>,\n{\n    type Output = ArrayVec<Trigon<Self::Vertex>, 2>;\n\n    fn into_subdivisions(self) -> Self::Output {\n        let [a, b, c] = self.into_array();\n        let ac = a.clone().midpoint(c.clone());\n        ArrayVec::from([Trigon::new(b.clone(), ac.clone(), a), Trigon::new(c, ac, b)])\n    }\n}\n\nimpl<T> IntoSubdivisions for Tetragon<T>\nwhere\n    T: Clone + Interpolate<Output = T>,\n{\n    type Output = ArrayVec<Tetragon<Self::Vertex>, 4>;\n\n    fn into_subdivisions(self) -> Self::Output {\n        let [a, b, c, d] = self.into_array();\n        let ab = a.clone().midpoint(b.clone());\n        let bc = b.clone().midpoint(c.clone());\n        let cd = c.clone().midpoint(d.clone());\n        let da = d.clone().midpoint(a.clone());\n        let ac = a.clone().midpoint(c.clone()); // Diagonal.\n        ArrayVec::from([\n            Tetragon::new(a, ab.clone(), ac.clone(), da.clone()),\n            Tetragon::new(ab, b, bc.clone(), ac.clone()),\n            Tetragon::new(ac.clone(), bc, c, cd.clone()),\n            Tetragon::new(da, ac, cd, d),\n        ])\n    }\n}\n\nimpl<T> IntoTetrahedrons for Tetragon<T>\nwhere\n    T: Clone + Interpolate<Output = T>,\n{\n    fn into_tetrahedrons(self) -> ArrayVec<Trigon<Self::Vertex>, 4> {\n        let [a, b, c, d] = self.into_array();\n        let ac = a.clone().midpoint(c.clone()); // Diagonal.\n        ArrayVec::from([\n            Trigon::new(a.clone(), b.clone(), ac.clone()),\n            Trigon::new(b, c.clone(), ac.clone()),\n            Trigon::new(c, d.clone(), ac.clone()),\n            Trigon::new(d, a, ac),\n        ])\n    }\n}\n\nimpl<T> IntoSubdivisions for BoundedPolygon<T>\nwhere\n    T: Clone + Interpolate<Output = T>,\n{\n    type Output = Vec<Self>;\n\n    fn into_subdivisions(self) -> Self::Output {\n        match self {\n            BoundedPolygon::N3(trigon) => trigon\n                .into_subdivisions()\n                .into_iter()\n                .map(|trigon| trigon.into())\n                .collect(),\n            BoundedPolygon::N4(tetragon) => tetragon\n                .into_subdivisions()\n                .into_iter()\n                .map(|tetragon| tetragon.into())\n                .collect(),\n        }\n    }\n}\n\npub trait Vertices<P>: Sized\nwhere\n    P: IntoVertices,\n{\n    fn vertices(self) -> Decompose<Self, P, P::Vertex, P::Output>;\n}\n\nimpl<I, P> Vertices<P> for I\nwhere\n    I: Iterator<Item = P>,\n    P: IntoVertices,\n{\n    fn vertices(self) -> Decompose<Self, P, P::Vertex, P::Output> {\n        Decompose::new(self, P::into_vertices)\n    }\n}\n\npub trait Edges<P>: Sized\nwhere\n    P: IntoEdges,\n{\n    fn edges(self) -> Decompose<Self, P, Edge<P::Vertex>, P::Output>;\n}\n\nimpl<I, P> Edges<P> for I\nwhere\n    I: Iterator<Item = P>,\n    P: IntoEdges,\n    P::Vertex: Clone,\n{\n    fn edges(self) -> Decompose<Self, P, Edge<P::Vertex>, P::Output> {\n        Decompose::new(self, P::into_edges)\n    }\n}\n\npub trait Triangulate<P>: Sized\nwhere\n    P: IntoTrigons,\n{\n    fn triangulate(self) -> Decompose<Self, P, Trigon<P::Vertex>, P::Output>;\n}\n\nimpl<I, P> Triangulate<P> for I\nwhere\n    I: Iterator<Item = P>,\n    P: IntoTrigons,\n{\n    fn triangulate(self) -> Decompose<Self, P, Trigon<P::Vertex>, P::Output> {\n        Decompose::new(self, P::into_trigons)\n    }\n}\n\npub trait Subdivide<P>: Sized\nwhere\n    P: IntoSubdivisions,\n{\n    fn subdivide(self) -> Decompose<Self, P, P, P::Output>;\n}\n\nimpl<I, P> Subdivide<P> for I\nwhere\n    I: Iterator<Item = P>,\n    P: IntoSubdivisions,\n{\n    fn subdivide(self) -> Decompose<Self, P, P, P::Output> {\n        Decompose::new(self, P::into_subdivisions)\n    }\n}\n\npub trait Tetrahedrons<T>: Sized {\n    fn tetrahedrons(self) -> Decompose<Self, Tetragon<T>, Trigon<T>, ArrayVec<Trigon<T>, 4>>;\n}\n\nimpl<I, T> Tetrahedrons<T> for I\nwhere\n    I: Iterator<Item = Tetragon<T>>,\n    T: Clone + Interpolate<Output = T>,\n{\n    fn tetrahedrons(self) -> Decompose<Self, Tetragon<T>, Trigon<T>, ArrayVec<Trigon<T>, 4>> {\n        Decompose::new(self, Tetragon::into_tetrahedrons)\n    }\n}\n\nfn remap<I, P, R, F>(n: usize, ngons: I, f: F) -> Vec<P>\nwhere\n    I: IntoIterator<Item = P>,\n    R: IntoIterator<Item = P>,\n    F: Fn(P) -> R,\n{\n    let mut ngons: Vec<_> = ngons.into_iter().collect();\n    for _ in 0..n {\n        ngons = ngons.into_iter().flat_map(&f).collect();\n    }\n    ngons\n}\n"
  },
  {
    "path": "plexus/src/primitive/generate.rs",
    "content": "//! Polytope generation.\n//!\n//! This module provides a generic iterator and traits for generating polygons\n//! and vertices containing geometric attributes of polytopes like cubes and\n//! spheres. The [`Generate`] iterator can be used in iterator expressions.\n//!\n//! The primary API of this module is provided by the [`Generator`] trait, which\n//! is implemented by polytope types like [`Cube`] and [`UvSphere`].\n//!\n//! # Examples\n//!\n//! Generating [raw buffers][`buffer`] from the positional data of a\n//! [$uv$-sphere][`UvSphere`]:\n//!\n//! ```rust\n//! # extern crate nalgebra;\n//! # extern crate plexus;\n//! #\n//! use nalgebra::Point3;\n//! use plexus::prelude::*;\n//! use plexus::primitive::generate::Position;\n//! use plexus::primitive::sphere::UvSphere;\n//!\n//! let sphere = UvSphere::new(16, 16);\n//!\n//! // Generate the unique set of positional vertices.\n//! let positions = sphere\n//!     .vertices::<Position<Point3<f64>>>()\n//!     .collect::<Vec<_>>();\n//!\n//! // Generate polygons that index the unique set of positional vertices. The\n//! // polygons are decomposed into triangles and then into vertices, where each\n//! // vertex is an index into the position data.\n//! let indices = sphere\n//!     .indexing_polygons::<Position>()\n//!     .triangulate()\n//!     .vertices()\n//!     .collect::<Vec<_>>();\n//! ```\n//!\n//! [`buffer`]: crate::buffer\n//! [`Cube`]: crate::primitive::cube::Cube\n//! [`Generate`]: crate::primitive::generate::Generate\n//! [`Generator`]: crate::primitive::generate::Generator\n//! [`UvSphere`]: crate::primitive::sphere::UvSphere\n\nuse std::marker::PhantomData;\nuse std::ops::Range;\n\nuse crate::primitive::Polygonal;\n\n/// Geometric attribute.\n///\n/// Types implementing this trait can be used with [`Generator`] to query\n/// geometric attributes. For example, the [`Position`] type can be used to get\n/// positional data for cubes or spheres via [`Cube`] and [`UvSphere`].\n///\n/// [`Cube`]: crate::primitive::cube::Cube\n/// [`Generator`]: crate::primitive::generate::Generator\n/// [`Position`]: crate::primitive::generate::Position\n/// [`UvSphere`]: crate::primitive::sphere::UvSphere\npub trait Attribute {}\n\n/// Meta-attribute for surface normals.\n///\n/// Describes the surface normals of a polytope. The generated data is derived\n/// from the type parameter `S`, which typically requires [`EuclideanSpace`].\n///\n/// # Examples\n///\n/// Generating raw buffers with normal data of a [$uv$-sphere][`UvSphere`]:\n///\n/// ```rust\n/// # extern crate decorum;\n/// # extern crate nalgebra;\n/// # extern crate plexus;\n/// #\n/// use decorum::R64;\n/// use nalgebra::Point3;\n/// use plexus::index::{Flat3, HashIndexer};\n/// use plexus::prelude::*;\n/// use plexus::primitive::generate::Normal;\n/// use plexus::primitive::sphere::UvSphere;\n///\n/// let (indices, normals) = UvSphere::new(8, 8)\n///     .polygons::<Normal<Point3<R64>>>()\n///     .map_vertices(|normal| normal.into_inner())\n///     .triangulate()\n///     .index_vertices::<Flat3, _>(HashIndexer::default());\n/// ```\n///\n/// [`EuclideanSpace`]: theon::space::EuclideanSpace\n/// [`UvSphere`]: crate::primitive::sphere::UvSphere\npub struct Normal<S = ()> {\n    phantom: PhantomData<fn() -> S>,\n}\n\nimpl<S> Attribute for Normal<S> {}\n\n/// Meta-attribute for positions.\n///\n/// Describes the position of vertices in a polytope. The generated data is\n/// derived from the type parameter `S`, which typically requires\n/// [`EuclideanSpace`].\n///\n/// # Examples\n///\n/// Generating raw buffers with positional data of a [cube][`Cube`]:\n///\n/// ```rust\n/// # extern crate decorum;\n/// # extern crate nalgebra;\n/// # extern crate plexus;\n/// #\n/// use decorum::R64;\n/// use nalgebra::Point3;\n/// use plexus::index::{Flat3, HashIndexer};\n/// use plexus::prelude::*;\n/// use plexus::primitive::cube::Cube;\n/// use plexus::primitive::generate::Position;\n/// use plexus::primitive::UnboundedPolygon;\n///\n/// let (indices, positions) = Cube::new()\n///     .polygons::<Position<Point3<R64>>>()\n///     .triangulate()\n///     .index_vertices::<UnboundedPolygon<usize>, _>(HashIndexer::default());\n/// ```\n///\n/// [`EuclideanSpace`]: theon::space::EuclideanSpace\n/// [`Cube`]: crate::primitive::cube::Cube\n/// [`UvSphere`]: crate::primitive::sphere::UvSphere\npub struct Position<S = ()> {\n    phantom: PhantomData<fn() -> S>,\n}\n\nimpl<S> Attribute for Position<S> {}\n\n/// Iterator that generates topology and geometric attributes.\npub struct Generate<'a, G, S, P>\nwhere\n    G: 'a,\n{\n    generator: &'a G,\n    state: S,\n    range: Range<usize>,\n    f: fn(&'a G, &S, usize) -> P,\n}\n\nimpl<'a, G, S, P> Generate<'a, G, S, P>\nwhere\n    G: 'a,\n{\n    fn new(generator: &'a G, state: S, n: usize, f: fn(&'a G, &S, usize) -> P) -> Self {\n        Generate {\n            generator,\n            state,\n            range: 0..n,\n            f,\n        }\n    }\n}\n\nimpl<'a, G, S, P> Iterator for Generate<'a, G, S, P>\nwhere\n    G: 'a,\n{\n    type Item = P;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        self.range\n            .next()\n            .map(|index| (self.f)(self.generator, &self.state, index))\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        self.range.size_hint()\n    }\n}\n\npub trait PolygonGenerator {\n    fn polygon_count(&self) -> usize;\n}\n\npub trait AttributeGenerator<A>\nwhere\n    A: Attribute,\n{\n    type State: Default;\n}\n\npub trait AttributePolygonGenerator<A>: AttributeGenerator<A> + PolygonGenerator\nwhere\n    A: Attribute,\n{\n    type Output: Polygonal;\n\n    fn polygon_from(&self, state: &Self::State, index: usize) -> Self::Output;\n}\n\npub trait AttributeVertexGenerator<A>: AttributeGenerator<A>\nwhere\n    A: Attribute,\n{\n    type Output;\n\n    fn vertex_count(&self) -> usize;\n\n    fn vertex_from(&self, state: &Self::State, index: usize) -> Self::Output;\n}\n\npub trait IndexingPolygonGenerator<A>: PolygonGenerator\nwhere\n    A: Attribute,\n{\n    type Output: Polygonal<Vertex = usize>;\n\n    fn indexing_polygon(&self, index: usize) -> Self::Output;\n}\n\n/// Functions for iterating over the topology and geometry of polytopes.\npub trait Generator: Sized {\n    /// Gets an iterator over the set of **unique** vertices with the given\n    /// attribute data.\n    ///\n    /// Each geometric attribute has an independent set of unique values. For\n    /// example, [`Cube`] generates six unique surface normals and eight unique\n    /// positions.\n    ///\n    /// This can be paired with the\n    /// [`indexing_polygons`][`Generator::indexing_polygons`] function to index\n    /// the set of vertices.\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use nalgebra::Point3;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::cube::Cube;\n    /// use plexus::primitive::generate::Position;\n    ///\n    /// type E3 = Point3<f64>;\n    ///\n    /// let cube = Cube::new();\n    ///\n    /// let positions = cube.vertices::<Position<E3>>().collect::<Vec<_>>();\n    /// let indices = cube\n    ///     .indexing_polygons::<Position>()\n    ///     .triangulate()\n    ///     .vertices()\n    ///     .collect::<Vec<_>>();\n    /// ```\n    ///\n    /// [`Cube`]: crate::primitive::cube::Cube\n    /// [`Generator::indexing_polygons`]: crate::primitive::generate::Generator::indexing_polygons\n    fn vertices<A>(\n        &self,\n    ) -> Generate<Self, Self::State, <Self as AttributeVertexGenerator<A>>::Output>\n    where\n        Self: AttributeVertexGenerator<A>,\n        A: Attribute,\n    {\n        self.vertices_from(Default::default())\n    }\n\n    fn vertices_from<A>(\n        &self,\n        state: Self::State,\n    ) -> Generate<Self, Self::State, <Self as AttributeVertexGenerator<A>>::Output>\n    where\n        Self: AttributeVertexGenerator<A>,\n        A: Attribute,\n    {\n        Generate::new(self, state, self.vertex_count(), Self::vertex_from)\n    }\n\n    /// Gets an iterator over the set of polygons with the given attribute data.\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// # extern crate decorum;\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use decorum::R64;\n    /// use nalgebra::Point3;\n    /// use plexus::index::HashIndexer;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::cube::Cube;\n    /// use plexus::primitive::generate::Position;\n    /// use plexus::primitive::Tetragon;\n    ///\n    /// let (indices, positions) = Cube::new()\n    ///     .polygons::<Position<Point3<R64>>>()\n    ///     .index_vertices::<Tetragon<usize>, _>(HashIndexer::default());\n    /// ```\n    fn polygons<A>(\n        &self,\n    ) -> Generate<Self, Self::State, <Self as AttributePolygonGenerator<A>>::Output>\n    where\n        Self: AttributePolygonGenerator<A>,\n        A: Attribute,\n    {\n        self.polygons_from(Default::default())\n    }\n\n    fn polygons_from<A>(\n        &self,\n        state: Self::State,\n    ) -> Generate<Self, Self::State, <Self as AttributePolygonGenerator<A>>::Output>\n    where\n        Self: AttributePolygonGenerator<A>,\n        A: Attribute,\n    {\n        Generate::new(self, state, self.polygon_count(), Self::polygon_from)\n    }\n\n    /// Gets an iterator over a set of polygons that index the unique set of\n    /// vertices with the given attribute.\n    ///\n    /// Indexing differs per geometric attribute, because each attribute has an\n    /// independent set of unique values. For example, [`Cube`] generates six\n    /// unique surface normals and eight unique positions.\n    ///\n    /// When used with meta-attribute types like [`Position`], input types are\n    /// not needed and default type parameters can be used instead. For example,\n    /// if `Position<Point3<f64>>` is used to generate positional data, then\n    /// `Position<()>` (or `Position`) can be used to generate indexing\n    /// polygons.\n    ///\n    /// # Examples\n    ///\n    /// ```rust\n    /// # extern crate nalgebra;\n    /// # extern crate plexus;\n    /// #\n    /// use nalgebra::Point3;\n    /// use plexus::buffer::MeshBuffer4;\n    /// use plexus::prelude::*;\n    /// use plexus::primitive::cube::Cube;\n    /// use plexus::primitive::generate::Position;\n    ///\n    /// type E3 = Point3<f64>;\n    ///\n    /// let cube = Cube::new();\n    /// let buffer = MeshBuffer4::<usize, E3>::from_raw_buffers(\n    ///     cube.indexing_polygons::<Position>(),\n    ///     cube.vertices::<Position<E3>>(),\n    /// );\n    /// ```\n    ///\n    /// [`Cube`]: crate::primitive::cube::Cube\n    /// [`Position`]: crate::primitive::generate::Position\n    fn indexing_polygons<A>(&self) -> Generate<Self, (), Self::Output>\n    where\n        Self: IndexingPolygonGenerator<A>,\n        A: Attribute,\n    {\n        Generate::new(self, (), self.polygon_count(), |generator, _, index| {\n            generator.indexing_polygon(index)\n        })\n    }\n}\n"
  },
  {
    "path": "plexus/src/primitive/mod.rs",
    "content": "//! Primitive topological structures.\n//!\n//! This module provides composable primitives that describe polygonal\n//! structures. This includes simple $n$-gons like triangles, polytope\n//! [generators][`generate`], and iterator expressions that compose and\n//! decompose iterators of primitives.\n//!\n//! Types in this module generally describe [cycle graphs][cycle-graph] and are\n//! not strictly geometric. For example, [`Polygonal`] types may be\n//! geometrically degenerate (e.g., collinear, converged, etc.) or used to\n//! approximate polygons from $\\Reals^2$ embedded into higher-dimensional\n//! spaces. These types are also used for indexing, in which case their\n//! representation and data are both entirely topological.\n//!\n//! Plexus uses the terms _trigon_ and _tetragon_ for its polygon types, which\n//! mean _triangle_ and _quadrilateral_, respectively. This is done for\n//! consistency with higher arity polygon names (e.g., _decagon_). In some\n//! contexts, the term _triangle_ is still used, such as in functions concerning\n//! _triangulation_.\n//!\n//! # Representations\n//!\n//! Plexus provides various topological types with different capabilities\n//! summarized below:\n//!\n//! | Type               | Morphism    | Arity        | Map | Zip | Tessellate |\n//! |--------------------|-------------|--------------|-----|-----|------------|\n//! | `NGon`             | Monomorphic | $1,\\[3,32\\]$ | Yes | Yes | Yes        |\n//! | `BoundedPolygon`   | Polymorphic | $\\[3,4\\]$    | Yes | No  | Yes        |\n//! | `UnboundedPolygon` | Polymorphic | $[3,\\infin)$ | Yes | No  | No         |\n//!\n//! [`NGon`] is [monomorphic][`Monomorphic`] and supports the broadest set of\n//! traits and features. However, its [type-level][`StaticArity`] arity is\n//! somewhat limited and its [value-level][`DynamicArity`] arity is fixed. This\n//! means, for example, that it is not possible to have an iterator of [`NGon`]s\n//! represent both trigons and tetragons, because these polygons must be\n//! distinct [`NGon`] types.\n//!\n//! The polygon types [`BoundedPolygon`] and [`UnboundedPolygon`] are\n//! polymorphic and therefore support variable [value-level][`DynamicArity`]\n//! [arity][`Arity`]. [`BoundedPolygon`] only expresses a limited set of\n//! polygons by enumerating [`NGon`]s, but supports decomposition and other\n//! traits. [`UnboundedPolygon`] is most flexible and can represent any\n//! arbitrary polygon, but does not support any tessellation features.\n//!\n//! [`Edge`]s are always represented as `NGon<_, 2>`.\n//!\n//! # Examples\n//!\n//! Generating [raw buffers][`buffer`] with positional data of a [cube][`Cube`]\n//! using an [`Indexer`]:\n//!\n//! ```rust\n//! # extern crate decorum;\n//! # extern crate nalgebra;\n//! # extern crate plexus;\n//! #\n//! use decorum::R32;\n//! use nalgebra::Point3;\n//! use plexus::index::{Flat3, HashIndexer};\n//! use plexus::prelude::*;\n//! use plexus::primitive::cube::Cube;\n//! use plexus::primitive::generate::Position;\n//!\n//! let (indices, positions) = Cube::new()\n//!     .polygons::<Position<Point3<R32>>>()\n//!     .triangulate()\n//!     .index_vertices::<Flat3, _>(HashIndexer::default());\n//! ```\n//!\n//! [cycle-graph]: https://en.wikipedia.org/wiki/cycle_graph\n//!\n//! [`buffer`]: crate::buffer\n//! [`Indexer`]: crate::index::Indexer\n//! [`Cube`]: crate::primitive::cube::Cube\n//! [`BoundedPolygon`]: crate::primitive::BoundedPolygon\n//! [`NGon`]: crate::primitive::NGon\n//! [`UnboundedPolygon`]: crate::primitive::UnboundedPolygon\n//! [`Arity`]: crate::Arity\n//! [`DynamicArity`]: crate::DynamicArity\n//! [`StaticArity`]: crate::StaticArity\n\npub mod cube;\npub mod decompose;\npub mod generate;\npub mod sphere;\n\nuse arrayvec::ArrayVec;\nuse itertools::izip;\nuse itertools::structs::Zip as OuterZip; // Avoid collision with `Zip`.\nuse num::traits::real::Real;\nuse num::traits::FloatConst;\nuse num::{Integer, One, Unsigned, Zero};\nuse smallvec::{smallvec, SmallVec};\nuse std::array;\nuse std::convert::TryInto;\nuse std::fmt::{self, Debug, Formatter};\nuse std::marker::PhantomData;\nuse std::ops::{Index, IndexMut};\nuse theon::adjunct::{Adjunct, Converged, Extend, Fold, FromItems, IntoItems, Map, ZipMap};\nuse theon::ops::Cross;\nuse theon::query::{Intersection, Line, LineLine, LinePlane, Plane, Unit};\nuse theon::space::{EuclideanSpace, FiniteDimensional, Scalar, Vector, VectorSpace};\nuse theon::{AsPosition, AsPositionMut, Position};\nuse typenum::{Cmp, Greater, U1, U2, U3};\n\nuse crate::constant::{Constant, ToType, TypeOf};\nuse crate::geometry::partition::PointPartition;\nuse crate::primitive::decompose::IntoVertices;\nuse crate::{DynamicArity, IteratorExt as _, Monomorphic, StaticArity, TryFromIterator};\n\n/// Topological structure.\n///\n/// Types implementing `Topological` provide some notion of adjacency between\n/// vertices of their `Vertex` type. These types typically represent cycle\n/// graphs and polygonal structures, but may also include degenerate forms like\n/// monogons.\npub trait Topological:\n    Adjunct<Item = <Self as Topological>::Vertex>\n    + AsMut<[<Self as Topological>::Vertex]>\n    + AsRef<[<Self as Topological>::Vertex]>\n    + DynamicArity<Dynamic = usize>\n    + IntoIterator<Item = <Self as Topological>::Vertex>\n    + Sized\n{\n    type Vertex;\n\n    fn try_from_slice<T>(vertices: T) -> Option<Self>\n    where\n        Self::Vertex: Copy,\n        T: AsRef<[Self::Vertex]>;\n\n    /// Embeds an $n$-gon from $\\Reals^2$ into $\\Reals^3$.\n    ///\n    /// The scalar for the additional basis is normalized to the given value.\n    ///\n    /// # Examples\n    ///\n    /// Embedding a triangle into the $xy$-plane at $z=1$:\n    ///\n    /// ```rust\n    /// # extern crate nalgebra;\n    /// # extern crate theon;\n    /// #\n    /// use nalgebra::Point2;\n    /// use plexus::primitive::{Topological, Trigon};\n    /// use theon::space::EuclideanSpace;\n    ///\n    /// type E2 = Point2<f64>;\n    ///\n    /// let trigon = Trigon::embed_into_e3_xy(\n    ///     Trigon::from([\n    ///         E2::from_xy(-1.0, 0.0),\n    ///         E2::from_xy(0.0, 1.0),\n    ///         E2::from_xy(1.0, 0.0),\n    ///     ]),\n    ///     1.0,\n    /// );\n    /// ```\n    fn embed_into_e3_xy<P>(ngon: P, z: Scalar<Self::Vertex>) -> Self\n    where\n        Self::Vertex: EuclideanSpace + FiniteDimensional<N = U3>,\n        P: Map<Self::Vertex, Output = Self> + Topological,\n        P::Vertex: EuclideanSpace + FiniteDimensional<N = U2> + Extend<Self::Vertex>,\n        Vector<P::Vertex>: VectorSpace<Scalar = Scalar<Self::Vertex>>,\n    {\n        Self::embed_into_e3_xy_with(ngon, z, |position| position)\n    }\n\n    fn embed_into_e3_xy_with<P, F>(ngon: P, z: Scalar<Position<Self::Vertex>>, mut f: F) -> Self\n    where\n        Self::Vertex: AsPosition,\n        Position<Self::Vertex>: EuclideanSpace + FiniteDimensional<N = U3>,\n        P: Map<Self::Vertex, Output = Self> + Topological,\n        P::Vertex: EuclideanSpace + FiniteDimensional<N = U2> + Extend<Position<Self::Vertex>>,\n        Vector<P::Vertex>: VectorSpace<Scalar = Scalar<Position<Self::Vertex>>>,\n        F: FnMut(Position<Self::Vertex>) -> Self::Vertex,\n    {\n        ngon.map(move |position| f(position.extend(z)))\n    }\n\n    /// Embeds an $n$-gon from $\\Reals^2$ into $\\Reals^3$.\n    ///\n    /// The $n$-gon is rotated into the given plane about the origin.\n    ///\n    /// # Examples\n    ///\n    /// Embedding a triangle into the $xy$-plane at $z=0$:\n    ///\n    /// ```rust,no_run\n    /// # extern crate nalgebra;\n    /// # extern crate theon;\n    /// #\n    /// use nalgebra::{Point2, Point3};\n    /// use plexus::geometry::{Plane, Unit};\n    /// use plexus::primitive::{Topological, Trigon};\n    /// use theon::space::{Basis, EuclideanSpace};\n    ///\n    /// type E2 = Point2<f64>;\n    /// type E3 = Point3<f64>;\n    ///\n    /// let trigon = Trigon::embed_into_e3_plane(\n    ///     Trigon::from([\n    ///         E2::from_xy(-1.0, 0.0),\n    ///         E2::from_xy(0.0, 1.0),\n    ///         E2::from_xy(1.0, 0.0),\n    ///     ]),\n    ///     Plane::<E3> {\n    ///         origin: EuclideanSpace::origin(),\n    ///         normal: Unit::z(),\n    ///     },\n    /// );\n    /// ```\n    fn embed_into_e3_plane<P>(ngon: P, plane: Plane<Self::Vertex>) -> Self\n    where\n        Self::Vertex: EuclideanSpace + FiniteDimensional<N = U3>,\n        P: Map<Self::Vertex, Output = Self> + Topological,\n        P::Vertex: EuclideanSpace + FiniteDimensional<N = U2> + Extend<Self::Vertex>,\n        Vector<P::Vertex>: VectorSpace<Scalar = Scalar<Self::Vertex>>,\n    {\n        Self::embed_into_e3_plane_with(ngon, plane, |position| position)\n    }\n\n    fn embed_into_e3_plane_with<P, F>(ngon: P, _: Plane<Position<Self::Vertex>>, f: F) -> Self\n    where\n        Self::Vertex: AsPosition,\n        Position<Self::Vertex>: EuclideanSpace + FiniteDimensional<N = U3>,\n        P: Map<Self::Vertex, Output = Self> + Topological,\n        P::Vertex: EuclideanSpace + FiniteDimensional<N = U2> + Extend<Position<Self::Vertex>>,\n        Vector<P::Vertex>: VectorSpace<Scalar = Scalar<Position<Self::Vertex>>>,\n        F: FnMut(Position<Self::Vertex>) -> Self::Vertex,\n    {\n        // TODO: Rotate the embedded n-gon into the plane about the origin.\n        let _ = Self::embed_into_e3_xy_with(ngon, Zero::zero(), f);\n        unimplemented!()\n    }\n\n    /// Projects an $n$-gon into a plane.\n    ///\n    /// The positions in each vertex of the $n$-gon are translated along the\n    /// normal of the plane.\n    #[must_use]\n    fn project_into_plane(mut self, plane: Plane<Position<Self::Vertex>>) -> Self\n    where\n        Self::Vertex: AsPositionMut,\n        Position<Self::Vertex>: EuclideanSpace + FiniteDimensional,\n        <Position<Self::Vertex> as FiniteDimensional>::N: Cmp<U2, Output = Greater>,\n    {\n        for vertex in self.as_mut() {\n            let line = Line::<Position<Self::Vertex>> {\n                origin: *vertex.as_position(),\n                direction: plane.normal,\n            };\n            // TODO: Assert that this case always occurs; the line lies along\n            //       the normal.\n            if let Some(LinePlane::TimeOfImpact(distance)) = line.intersection(&plane) {\n                let translation = *line.direction.get() * distance;\n                vertex.transform(|position| *position + translation);\n            }\n        }\n        self\n    }\n\n    // TODO: Once GATs are stabilized, consider using a separate trait for this\n    //       to avoid using `Vec` and allocating. This may also require a\n    //       different name to avoid collisions with the `decompose` module. See\n    //       https://github.com/rust-lang/rust/issues/44265\n    fn edges(&self) -> Vec<Edge<&Self::Vertex>> {\n        self.as_ref()\n            .iter()\n            .perimeter()\n            .map(|(a, b)| Edge::new(a, b))\n            .collect()\n    }\n}\n\n/// Polygonal structure.\n///\n/// `Polygonal` types form cycle graphs and extend [`Topological`] types with\n/// the additional constraint that all vertices have a degree and valence of\n/// two. This requires at least three edges and forbids degenerate structures\n/// like monogons.\n///\n/// These types are topological and do not necessarily represent geometric\n/// concepts like polygons in the most strict sense. Polygons are only defined\n/// in $\\Reals^2$ and cannot have converged or collinear vertices, but\n/// `Polygonal` types support this kind of data. However, `Polygonal` types are\n/// often used as a geometric approximation of polygons. Moreover, `Polygonal`\n/// types often contain non-geometric data, particularly index data.\n///\n/// [`Topological`]: crate::primitive::Topological\npub trait Polygonal: Topological {\n    /// Determines if the polygon is convex.\n    ///\n    /// This function rejects (returns `false`) degenerate polygons, such as\n    /// polygons with collinear or converged vertices.\n    fn is_convex(&self) -> bool\n    where\n        Self::Vertex: AsPosition,\n        Position<Self::Vertex>: EuclideanSpace + FiniteDimensional<N = U2>,\n        Scalar<Position<Self::Vertex>>: FloatConst,\n    {\n        let pi = <Scalar<Position<Self::Vertex>> as FloatConst>::PI();\n        let mut sum = <Scalar<Position<Self::Vertex>> as Zero>::zero();\n        for (t1, t2) in angles(self).perimeter() {\n            if (t1 * t2) <= Zero::zero() {\n                return false;\n            }\n            sum = sum + t1;\n        }\n        // TODO: Use an approximate comparison and do not explicitly round.\n        (sum / (pi + pi)).round().abs() == One::one()\n    }\n}\n\npub trait IntoIndexed<N>: Polygonal\nwhere\n    N: Copy + Integer + Unsigned,\n{\n    type Indexed: Polygonal<Vertex = (N, Self::Vertex)>;\n\n    fn into_indexed(self) -> Self::Indexed;\n}\n\nimpl<N, P, Q> IntoIndexed<N> for P\nwhere\n    P: Map<(N, <P as Topological>::Vertex), Output = Q> + Polygonal,\n    Q: Polygonal<Vertex = (N, P::Vertex)>,\n    N: Copy + Integer + Unsigned,\n{\n    type Indexed = Q;\n\n    fn into_indexed(self) -> Self::Indexed {\n        let mut index = Zero::zero();\n        self.map(|vertex| {\n            let vertex = (index, vertex);\n            index = index + One::one();\n            vertex\n        })\n    }\n}\n\npub trait IntoPolygons: Sized {\n    type Output: IntoIterator<Item = Self::Polygon>;\n    type Polygon: Polygonal;\n\n    fn into_polygons(self) -> Self::Output;\n}\n\npub trait Rotate {\n    #[must_use]\n    fn rotate(self, n: isize) -> Self;\n}\n\npub trait Zip {\n    type Output: Topological;\n\n    fn zip(self) -> Self::Output;\n}\n\npub trait MapVertices<T, U>: Sized {\n    fn map_vertices<F>(self, f: F) -> InteriorMap<Self, U, F>\n    where\n        F: FnMut(T) -> U;\n}\n\nimpl<I, T, U> MapVertices<T, U> for I\nwhere\n    I: Iterator,\n    I::Item: Map<U> + Topological<Vertex = T>,\n    <I::Item as Map<U>>::Output: Topological<Vertex = U>,\n{\n    fn map_vertices<F>(self, f: F) -> InteriorMap<Self, U, F>\n    where\n        F: FnMut(T) -> U,\n    {\n        InteriorMap::new(self, f)\n    }\n}\n\npub struct InteriorMap<I, T, F> {\n    input: I,\n    f: F,\n    phantom: PhantomData<fn() -> T>,\n}\n\nimpl<I, T, F> InteriorMap<I, T, F> {\n    fn new(input: I, f: F) -> Self {\n        InteriorMap {\n            input,\n            f,\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<I, T, F> Iterator for InteriorMap<I, T, F>\nwhere\n    I: Iterator,\n    F: FnMut(<I::Item as Topological>::Vertex) -> T,\n    I::Item: Map<T> + Topological,\n    <I::Item as Map<T>>::Output: Topological<Vertex = T>,\n{\n    type Item = <I::Item as Map<T>>::Output;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        self.input.next().map(|topology| topology.map(&mut self.f))\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        self.input.size_hint()\n    }\n}\n\n/// Monomorphic $n$-gon.\n///\n/// `NGon` represents a polygonal structure as an array. Each array element\n/// represents vertex data in order with adjacent elements being connected by an\n/// implicit undirected edge. For example, an `NGon` with three vertices\n/// (`NGon<_, 3>`) would represent a trigon (triangle). Generally these elements\n/// are labeled $A$, $B$, $C$, etc. Note that the constant parameter `N`\n/// represents the number of the `NGon`'s vertices and **not** the number of its\n/// edges (arity).\n///\n/// `NGon`s with less than three vertices are a degenerate case. An `NGon` with\n/// two vertices (`NGon<_, 2>`) is considered a _monogon_ and is used to\n/// represent edges. Such an `NGon` is not considered a _digon_, as it\n/// represents a single undirected edge rather than two distinct (but collapsed)\n/// edges. Note that the polygonal types [`BoundedPolygon`] and\n/// [`UnboundedPolygon`] never represent edges. See the [`Edge`] type\n/// definition.\n///\n/// `NGon`s with one or zero vertices are unsupported and lack various trait\n/// implementations.\n///\n/// See the [module][`primitive`] documentation for more information.\n///\n/// [`BoundedPolygon`]: crate::primitive::BoundedPolygon\n/// [`Edge`]: crate::primitive::Edge\n/// [`primitive`]: crate::primitive\n/// [`UnboundedPolygon`]: crate::primitive::UnboundedPolygon\n#[derive(Clone, Copy, Debug, Eq, PartialEq)]\npub struct NGon<G, const N: usize>(pub [G; N]);\n\nimpl<G, const N: usize> NGon<G, N> {\n    pub fn into_array(self) -> [G; N] {\n        self.0\n    }\n\n    pub fn positions(&self) -> NGon<&Position<G>, N>\n    where\n        G: AsPosition,\n    {\n        if let Ok(array) = self\n            .as_ref()\n            .iter()\n            .map(|vertex| vertex.as_position())\n            .collect::<ArrayVec<_, N>>()\n            .into_inner()\n        {\n            array.into()\n        }\n        else {\n            panic!()\n        }\n    }\n}\n\nimpl<G, const N: usize> NGon<&'_ G, N> {\n    pub fn cloned(self) -> NGon<G, N>\n    where\n        G: Clone,\n    {\n        self.map(|vertex| vertex.clone())\n    }\n}\n\nimpl<G, const N: usize> AsRef<[G]> for NGon<G, N> {\n    fn as_ref(&self) -> &[G] {\n        &self.0\n    }\n}\n\nimpl<G, const N: usize> AsMut<[G]> for NGon<G, N> {\n    fn as_mut(&mut self) -> &mut [G] {\n        &mut self.0\n    }\n}\n\nimpl<G, const N: usize> Adjunct for NGon<G, N> {\n    type Item = G;\n}\n\nimpl<G, const N: usize> Converged for NGon<G, N>\nwhere\n    G: Copy,\n{\n    fn converged(vertex: G) -> Self {\n        NGon([vertex; N])\n    }\n}\n\nimpl<G, const N: usize> DynamicArity for NGon<G, N>\nwhere\n    Constant<N>: ToType,\n    TypeOf<N>: Cmp<U1, Output = Greater>,\n{\n    type Dynamic = usize;\n\n    fn arity(&self) -> Self::Dynamic {\n        <Self as StaticArity>::ARITY\n    }\n}\n\nimpl<G, const N: usize> Fold for NGon<G, N>\nwhere\n    Self: Topological,\n{\n    fn fold<U, F>(self, mut seed: U, mut f: F) -> U\n    where\n        F: FnMut(U, Self::Item) -> U,\n    {\n        for vertex in self.into_vertices() {\n            seed = f(seed, vertex);\n        }\n        seed\n    }\n}\n\nimpl<G, const N: usize> From<[G; N]> for NGon<G, N> {\n    fn from(array: [G; N]) -> Self {\n        NGon(array)\n    }\n}\n\nimpl<G, const N: usize> FromItems for NGon<G, N> {\n    fn from_items<I>(items: I) -> Option<Self>\n    where\n        I: IntoIterator<Item = Self::Item>,\n    {\n        items.into_iter().try_collect().ok()\n    }\n}\n\nimpl<G, const N: usize> Index<usize> for NGon<G, N> {\n    type Output = G;\n\n    fn index(&self, index: usize) -> &Self::Output {\n        self.0.as_ref().index(index)\n    }\n}\n\nimpl<G, const N: usize> IndexMut<usize> for NGon<G, N> {\n    fn index_mut(&mut self, index: usize) -> &mut Self::Output {\n        self.0.as_mut().index_mut(index)\n    }\n}\n\nimpl<G, const N: usize> IntoItems for NGon<G, N> {\n    type Output = <Self as IntoIterator>::IntoIter;\n\n    fn into_items(self) -> Self::Output {\n        self.into_iter()\n    }\n}\n\nimpl<G, const N: usize> IntoIterator for NGon<G, N> {\n    type Item = G;\n    type IntoIter = array::IntoIter<G, N>;\n\n    fn into_iter(self) -> Self::IntoIter {\n        self.into_array().into_iter()\n    }\n}\n\nimpl<G, H, const N: usize> Map<H> for NGon<G, N> {\n    type Output = NGon<H, N>;\n\n    fn map<F>(self, f: F) -> Self::Output\n    where\n        F: FnMut(Self::Item) -> H,\n    {\n        (self.into_iter().map(f)).try_collect().unwrap()\n    }\n}\n\nimpl<G, const N: usize> Monomorphic for NGon<G, N>\nwhere\n    Constant<N>: ToType,\n    TypeOf<N>: Cmp<U1, Output = Greater>,\n{\n}\n\nimpl<G, const N: usize> Polygonal for NGon<G, N>\nwhere\n    // The compiler cannot deduce that the bounds on `TypeOf<N>` are a strict\n    // subset of the similar bounds on the `Topological` implementation, so an\n    // explicit bound on `Self` is required.\n    Self: Topological,\n    Constant<N>: ToType,\n    TypeOf<N>: Cmp<U2, Output = Greater>,\n{\n}\n\nimpl<G, const N: usize> StaticArity for NGon<G, N>\nwhere\n    Constant<N>: ToType,\n    TypeOf<N>: Cmp<U1, Output = Greater>,\n{\n    type Static = usize;\n\n    const ARITY: Self::Static = crate::n_arity(N);\n}\n\nimpl<G, const N: usize> Topological for NGon<G, N>\nwhere\n    Constant<N>: ToType,\n    TypeOf<N>: Cmp<U1, Output = Greater>,\n{\n    type Vertex = G;\n\n    fn try_from_slice<I>(vertices: I) -> Option<Self>\n    where\n        Self::Vertex: Copy,\n        I: AsRef<[Self::Vertex]>,\n    {\n        vertices.as_ref().try_into().map(NGon).ok()\n    }\n}\n\nimpl<G, const N: usize> TryFromIterator<G> for NGon<G, N> {\n    type Error = ();\n\n    fn try_from_iter<I>(vertices: I) -> Result<Self, Self::Error>\n    where\n        I: Iterator<Item = G>,\n    {\n        vertices\n            .collect::<ArrayVec<G, N>>()\n            .into_inner()\n            .map(NGon)\n            .map_err(|_| ())\n    }\n}\n\nimpl<G, H, const N: usize> ZipMap<H> for NGon<G, N> {\n    type Output = NGon<H, N>;\n\n    fn zip_map<F>(self, other: Self, mut f: F) -> Self::Output\n    where\n        F: FnMut(Self::Item, Self::Item) -> H,\n    {\n        (self.into_iter().zip(other).map(|(a, b)| f(a, b)))\n            .try_collect()\n            .unwrap()\n    }\n}\n\nmacro_rules! impl_zip_ngon {\n    (ngons => ($($i:ident),*)) => (\n        impl<$($i),*, const N: usize> Zip for ($(NGon<$i, N>),*)\n        where\n            Constant<N>: ToType,\n            TypeOf<N>: Cmp<U1, Output = Greater>,\n        {\n            type Output = NGon<($($i),*), N>;\n\n            // LINT: The `i` metavariable items are conventionally uppercase and represent both\n            //       type names and local binding identifiers.\n            #[expect(non_snake_case)]\n            fn zip(self) -> Self::Output {\n                let ($($i,)*) = self;\n                (izip!($($i.into_iter()),*)).try_collect().unwrap()\n            }\n        }\n    );\n}\nimpl_zip_ngon!(ngons => (A, B));\nimpl_zip_ngon!(ngons => (A, B, C));\nimpl_zip_ngon!(ngons => (A, B, C, D));\nimpl_zip_ngon!(ngons => (A, B, C, D, E));\nimpl_zip_ngon!(ngons => (A, B, C, D, E, F));\n\npub type Edge<G> = NGon<G, 2>;\n\nimpl<G> Edge<G> {\n    pub fn new(a: G, b: G) -> Self {\n        NGon([a, b])\n    }\n\n    pub fn line(&self) -> Option<Line<Position<G>>>\n    where\n        G: AsPosition,\n    {\n        let [origin, endpoint] = self.positions().cloned().into_array();\n        Unit::try_from_inner(endpoint - origin).map(|direction| Line { origin, direction })\n    }\n\n    pub fn is_bisected(&self, other: &Self) -> bool\n    where\n        G: AsPosition,\n        Position<G>: FiniteDimensional<N = U2>,\n    {\n        let is_disjoint = |line: Line<Position<G>>, [a, b]: [Position<G>; 2]| {\n            line.partition(a)\n                .zip(line.partition(b))\n                .map(|(pa, pb)| pa != pb)\n                .unwrap_or(false)\n        };\n        self.line()\n            .zip(other.line())\n            .map(|(left, right)| {\n                let left = is_disjoint(left, other.positions().cloned().into_array());\n                let right = is_disjoint(right, self.positions().cloned().into_array());\n                left && right\n            })\n            .unwrap_or(false)\n    }\n}\n\n/// Intersection of edges.\n#[derive(Clone, Copy, Eq, PartialEq)]\npub enum EdgeEdge<S>\nwhere\n    S: EuclideanSpace,\n{\n    Point(S),\n    Edge(Edge<S>),\n}\n\nimpl<S> EdgeEdge<S>\nwhere\n    S: EuclideanSpace,\n{\n    pub fn into_point(self) -> Option<S> {\n        match self {\n            EdgeEdge::Point(point) => Some(point),\n            _ => None,\n        }\n    }\n\n    pub fn into_edge(self) -> Option<Edge<S>> {\n        match self {\n            EdgeEdge::Edge(edge) => Some(edge),\n            _ => None,\n        }\n    }\n}\n\nimpl<S> Debug for EdgeEdge<S>\nwhere\n    S: Debug + EuclideanSpace,\n    Vector<S>: Debug,\n{\n    fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> {\n        match *self {\n            EdgeEdge::Point(point) => write!(formatter, \"Point({:?})\", point),\n            EdgeEdge::Edge(edge) => write!(formatter, \"Edge({:?})\", edge),\n        }\n    }\n}\n\nimpl<T> Intersection<Edge<T>> for Edge<T>\nwhere\n    T: AsPosition,\n    Position<T>: FiniteDimensional<N = U2>,\n{\n    type Output = EdgeEdge<Position<T>>;\n\n    // TODO: This first computes a line intersection and then partitions each\n    //       edge's endpoints by the other edge's line. That's probably more\n    //       expensive than is necessary.\n    fn intersection(&self, other: &Edge<T>) -> Option<Self::Output> {\n        self.line()\n            .zip(other.line())\n            .and_then(|(left, right)| match left.intersection(&right) {\n                Some(LineLine::Point(point)) => {\n                    self.is_bisected(other).then_some(EdgeEdge::Point(point))\n                }\n                Some(LineLine::Line(_)) => todo!(),\n                _ => None,\n            })\n    }\n}\n\nimpl<T> Rotate for Edge<T> {\n    fn rotate(self, n: isize) -> Self {\n        if n % 2 != 0 {\n            let [a, b] = self.into_array();\n            Edge::new(b, a)\n        }\n        else {\n            self\n        }\n    }\n}\n\n/// Triangle.\npub type Trigon<G> = NGon<G, 3>;\n\nimpl<G> Trigon<G> {\n    pub fn new(a: G, b: G, c: G) -> Self {\n        NGon([a, b, c])\n    }\n\n    pub fn plane(&self) -> Option<Plane<Position<G>>>\n    where\n        G: AsPosition,\n        Position<G>: EuclideanSpace + FiniteDimensional<N = U3>,\n        Vector<Position<G>>: Cross<Output = Vector<Position<G>>>,\n    {\n        let [a, b, c] = self.positions().cloned().into_array();\n        let ab = a - b;\n        let ac = a - c;\n        Unit::try_from_inner(ab.cross(ac))\n            .map(move |normal| Plane::<Position<G>> { origin: a, normal })\n    }\n}\n\nimpl<G> Rotate for Trigon<G> {\n    fn rotate(self, n: isize) -> Self {\n        let n = umod(n, Self::ARITY as isize);\n        if n == 1 {\n            let [a, b, c] = self.into_array();\n            Trigon::new(b, c, a)\n        }\n        else if n == 2 {\n            let [a, b, c] = self.into_array();\n            Trigon::new(c, a, b)\n        }\n        else {\n            self\n        }\n    }\n}\n\n/// Quadrilateral.\npub type Tetragon<G> = NGon<G, 4>;\n\nimpl<G> Tetragon<G> {\n    pub fn new(a: G, b: G, c: G, d: G) -> Self {\n        NGon([a, b, c, d])\n    }\n}\n\nimpl<G> Rotate for Tetragon<G> {\n    // LINT: These names follow a convention, mainly concerning vertices.\n    #[expect(clippy::many_single_char_names)]\n    fn rotate(self, n: isize) -> Self {\n        let n = umod(n, Self::ARITY as isize);\n        if n == 1 {\n            let [a, b, c, d] = self.into_array();\n            Tetragon::new(b, c, d, a)\n        }\n        else if n == 2 {\n            let [a, b, c, d] = self.into_array();\n            Tetragon::new(c, d, a, b)\n        }\n        else if n == 3 {\n            let [a, b, c, d] = self.into_array();\n            Tetragon::new(d, a, b, c)\n        }\n        else {\n            self\n        }\n    }\n}\n\n/// Bounded polymorphic $n$-gon.\n///\n/// `BoundedPolygon` represents an $n$-gon with at least three edges by\n/// enumerating [`NGon`]s. As such, $n$ is bounded, because the enumeration only\n/// supports a limited set of polygons. Only common arities used by generators\n/// are provided.\n///\n/// See the [module][`primitive`] documentation for more information.\n///\n/// [`primitive`]: crate::primitive\n/// [`NGon`]: crate::primitive::NGon\n#[derive(Clone, Copy, Debug, Eq, PartialEq)]\npub enum BoundedPolygon<G> {\n    N3(Trigon<G>),\n    N4(Tetragon<G>),\n}\n\nimpl<G> AsRef<[G]> for BoundedPolygon<G> {\n    fn as_ref(&self) -> &[G] {\n        match *self {\n            BoundedPolygon::N3(ref trigon) => trigon.as_ref(),\n            BoundedPolygon::N4(ref tetragon) => tetragon.as_ref(),\n        }\n    }\n}\n\nimpl<G> AsMut<[G]> for BoundedPolygon<G> {\n    fn as_mut(&mut self) -> &mut [G] {\n        match *self {\n            BoundedPolygon::N3(ref mut trigon) => trigon.as_mut(),\n            BoundedPolygon::N4(ref mut tetragon) => tetragon.as_mut(),\n        }\n    }\n}\n\nimpl<G> Adjunct for BoundedPolygon<G> {\n    type Item = G;\n}\n\nimpl<G> DynamicArity for BoundedPolygon<G> {\n    type Dynamic = usize;\n\n    fn arity(&self) -> Self::Dynamic {\n        match *self {\n            BoundedPolygon::N3(..) => Trigon::<G>::ARITY,\n            BoundedPolygon::N4(..) => Tetragon::<G>::ARITY,\n        }\n    }\n}\n\nimpl<G> Fold for BoundedPolygon<G> {\n    fn fold<U, F>(self, mut seed: U, mut f: F) -> U\n    where\n        F: FnMut(U, Self::Item) -> U,\n    {\n        for vertex in self.into_vertices() {\n            seed = f(seed, vertex);\n        }\n        seed\n    }\n}\n\nimpl<G> From<[G; 3]> for BoundedPolygon<G> {\n    fn from(array: [G; 3]) -> Self {\n        BoundedPolygon::N3(array.into())\n    }\n}\n\nimpl<G> From<[G; 4]> for BoundedPolygon<G> {\n    fn from(array: [G; 4]) -> Self {\n        BoundedPolygon::N4(array.into())\n    }\n}\n\nimpl<G> From<Trigon<G>> for BoundedPolygon<G> {\n    fn from(trigon: Trigon<G>) -> Self {\n        BoundedPolygon::N3(trigon)\n    }\n}\n\nimpl<G> From<Tetragon<G>> for BoundedPolygon<G> {\n    fn from(tetragon: Tetragon<G>) -> Self {\n        BoundedPolygon::N4(tetragon)\n    }\n}\n\nimpl<G> Index<usize> for BoundedPolygon<G> {\n    type Output = G;\n\n    fn index(&self, index: usize) -> &Self::Output {\n        match *self {\n            BoundedPolygon::N3(ref trigon) => trigon.index(index),\n            BoundedPolygon::N4(ref tetragon) => tetragon.index(index),\n        }\n    }\n}\n\nimpl<G> IndexMut<usize> for BoundedPolygon<G> {\n    fn index_mut(&mut self, index: usize) -> &mut Self::Output {\n        match *self {\n            BoundedPolygon::N3(ref mut trigon) => trigon.index_mut(index),\n            BoundedPolygon::N4(ref mut tetragon) => tetragon.index_mut(index),\n        }\n    }\n}\n\nimpl<G> IntoItems for BoundedPolygon<G> {\n    type Output = SmallVec<[G; 4]>;\n\n    fn into_items(self) -> Self::Output {\n        match self {\n            BoundedPolygon::N3(trigon) => trigon.into_items().collect(),\n            BoundedPolygon::N4(tetragon) => tetragon.into_items().collect(),\n        }\n    }\n}\n\nimpl<G> IntoIterator for BoundedPolygon<G> {\n    type Item = G;\n    type IntoIter = <<Self as IntoItems>::Output as IntoIterator>::IntoIter;\n\n    fn into_iter(self) -> Self::IntoIter {\n        self.into_items().into_iter()\n    }\n}\n\nimpl<T, U> Map<U> for BoundedPolygon<T> {\n    type Output = BoundedPolygon<U>;\n\n    fn map<F>(self, f: F) -> Self::Output\n    where\n        F: FnMut(Self::Item) -> U,\n    {\n        match self {\n            BoundedPolygon::N3(trigon) => BoundedPolygon::N3(trigon.map(f)),\n            BoundedPolygon::N4(tetragon) => BoundedPolygon::N4(tetragon.map(f)),\n        }\n    }\n}\n\nimpl<G> Polygonal for BoundedPolygon<G> {}\n\nimpl<G> Rotate for BoundedPolygon<G> {\n    fn rotate(self, n: isize) -> Self {\n        match self {\n            BoundedPolygon::N3(trigon) => BoundedPolygon::N3(trigon.rotate(n)),\n            BoundedPolygon::N4(tetragon) => BoundedPolygon::N4(tetragon.rotate(n)),\n        }\n    }\n}\n\nimpl<G> StaticArity for BoundedPolygon<G> {\n    type Static = (usize, usize);\n\n    const ARITY: Self::Static = (3, 4);\n}\n\nimpl<G> Topological for BoundedPolygon<G> {\n    type Vertex = G;\n\n    fn try_from_slice<I>(vertices: I) -> Option<Self>\n    where\n        Self::Vertex: Copy,\n        I: AsRef<[Self::Vertex]>,\n    {\n        let vertices = vertices.as_ref();\n        match vertices.len() {\n            3 => Some(BoundedPolygon::N3(NGon(vertices.try_into().unwrap()))),\n            4 => Some(BoundedPolygon::N4(NGon(vertices.try_into().unwrap()))),\n            _ => None,\n        }\n    }\n}\n\n/// Unbounded polymorphic $n$-gon.\n///\n/// `UnboundedPolygon` represents an $n$-gon with three or more edges. Unlike\n/// [`BoundedPolygon`], there is no limit to the arity of polygons that\n/// `UnboundedPolygon` may represent.\n///\n/// It is not possible to trivially convert an [`UnboundedPolygon`] into other\n/// topological types like [`NGon`]. See the [module][`primitive`] documentation\n/// for more information.\n///\n/// [`primitive`]: crate::primitive\n/// [`BoundedPolygon`]: crate::primitive::BoundedPolygon\n/// [`NGon`]: crate::primitive::NGon\n#[derive(Clone, Debug, Eq, PartialEq)]\npub struct UnboundedPolygon<G>(SmallVec<[G; 4]>);\n\nimpl<G> UnboundedPolygon<G> {\n    pub fn trigon(a: G, b: G, c: G) -> Self {\n        UnboundedPolygon(smallvec![a, b, c])\n    }\n\n    pub fn tetragon(a: G, b: G, c: G, d: G) -> Self {\n        UnboundedPolygon(smallvec![a, b, c, d])\n    }\n\n    pub fn positions(&self) -> UnboundedPolygon<&Position<G>>\n    where\n        G: AsPosition,\n    {\n        UnboundedPolygon(self.0.iter().map(|vertex| vertex.as_position()).collect())\n    }\n}\n\nimpl<G> UnboundedPolygon<&'_ G>\nwhere\n    G: Clone,\n{\n    pub fn cloned(self) -> UnboundedPolygon<G> {\n        self.map(|vertex| vertex.clone())\n    }\n}\n\nimpl<G> Adjunct for UnboundedPolygon<G> {\n    type Item = G;\n}\n\nimpl<G> AsRef<[G]> for UnboundedPolygon<G> {\n    fn as_ref(&self) -> &[G] {\n        self.0.as_ref()\n    }\n}\n\nimpl<G> AsMut<[G]> for UnboundedPolygon<G> {\n    fn as_mut(&mut self) -> &mut [G] {\n        self.0.as_mut()\n    }\n}\n\nimpl<G> DynamicArity for UnboundedPolygon<G> {\n    type Dynamic = usize;\n\n    fn arity(&self) -> Self::Dynamic {\n        self.0.len()\n    }\n}\n\nimpl<G> From<BoundedPolygon<G>> for UnboundedPolygon<G>\nwhere\n    G: Clone,\n{\n    fn from(polygon: BoundedPolygon<G>) -> Self {\n        UnboundedPolygon(SmallVec::from(polygon.as_ref()))\n    }\n}\n\nimpl<G, const N: usize> From<NGon<G, N>> for UnboundedPolygon<G>\nwhere\n    Constant<N>: ToType,\n    TypeOf<N>: Cmp<U2, Output = Greater>,\n    G: Clone,\n{\n    fn from(ngon: NGon<G, N>) -> Self {\n        UnboundedPolygon(SmallVec::from(ngon.as_ref()))\n    }\n}\n\nimpl<G> FromItems for UnboundedPolygon<G> {\n    fn from_items<I>(items: I) -> Option<Self>\n    where\n        I: IntoIterator<Item = Self::Item>,\n    {\n        items.into_iter().try_collect().ok()\n    }\n}\n\nimpl<G> Index<usize> for UnboundedPolygon<G> {\n    type Output = G;\n\n    fn index(&self, index: usize) -> &Self::Output {\n        self.0.index(index)\n    }\n}\n\nimpl<G> IndexMut<usize> for UnboundedPolygon<G> {\n    fn index_mut(&mut self, index: usize) -> &mut Self::Output {\n        self.0.index_mut(index)\n    }\n}\n\nimpl<G> IntoItems for UnboundedPolygon<G> {\n    type Output = SmallVec<[G; 4]>;\n\n    fn into_items(self) -> Self::Output {\n        self.0\n    }\n}\n\nimpl<G> IntoIterator for UnboundedPolygon<G> {\n    type IntoIter = <SmallVec<[G; 4]> as IntoIterator>::IntoIter;\n    type Item = G;\n\n    fn into_iter(self) -> Self::IntoIter {\n        self.0.into_iter()\n    }\n}\n\nimpl<T, U> Map<U> for UnboundedPolygon<T> {\n    type Output = UnboundedPolygon<U>;\n\n    fn map<F>(self, f: F) -> Self::Output\n    where\n        F: FnMut(Self::Item) -> U,\n    {\n        UnboundedPolygon(self.0.into_iter().map(f).collect())\n    }\n}\n\nimpl<G> Polygonal for UnboundedPolygon<G> {}\n\nimpl<G> StaticArity for UnboundedPolygon<G> {\n    type Static = (usize, Option<usize>);\n\n    const ARITY: Self::Static = (3, None);\n}\n\nimpl<G> Topological for UnboundedPolygon<G> {\n    type Vertex = G;\n\n    fn try_from_slice<I>(vertices: I) -> Option<Self>\n    where\n        Self::Vertex: Copy,\n        I: AsRef<[Self::Vertex]>,\n    {\n        let vertices = vertices.as_ref();\n        if vertices.len() > 2 {\n            Some(UnboundedPolygon(SmallVec::from(vertices)))\n        }\n        else {\n            None\n        }\n    }\n}\n\nimpl<G> TryFromIterator<G> for UnboundedPolygon<G> {\n    type Error = ();\n\n    fn try_from_iter<I>(vertices: I) -> Result<Self, Self::Error>\n    where\n        I: Iterator<Item = G>,\n    {\n        vertices\n            .has_at_least(3)\n            .map(|items| UnboundedPolygon(items.collect()))\n            .ok_or(())\n    }\n}\n\n/// Zips the vertices of [`Topological`] types from multiple iterators into a\n/// single iterator.\n///\n/// This is useful for zipping different geometric attributes of a\n/// [generator][`generate`].  For example, it can be used to combine position,\n/// plane, and normal data data of a [`Cube`] into a single topology iterator.\n///\n/// # Examples\n///\n/// Zip position, normal, and plane attributes of a [cube][`Cube`]:\n///\n/// ```rust\n/// # extern crate decorum;\n/// # extern crate nalgebra;\n/// # extern crate plexus;\n/// #\n/// use decorum::R32;\n/// use nalgebra::Point3;\n/// use plexus::prelude::*;\n/// use plexus::primitive;\n/// use plexus::primitive::cube::{Cube, Plane};\n/// use plexus::primitive::generate::{Normal, Position};\n///\n/// type E3 = Point3<R32>;\n///\n/// let cube = Cube::new();\n/// // Zip positions and texture coordinates into each vertex.\n/// let polygons = primitive::zip_vertices((\n///     cube.polygons::<Position<E3>>(),\n///     cube.polygons::<Normal<E3>>(),\n///     cube.polygons::<Plane>(),\n/// ))\n/// .triangulate()\n/// .collect::<Vec<_>>();\n/// ```\n///\n/// [`Cube`]: crate::primitive::cube::Cube\n/// [`generate`]: crate::primitive::generate\n/// [`Topological`]: crate::primitive::Topological\npub fn zip_vertices<T, U>(\n    tuple: U,\n) -> impl Iterator<Item = <<OuterZip<T> as Iterator>::Item as Zip>::Output>\nwhere\n    OuterZip<T>: From<U> + Iterator,\n    <OuterZip<T> as Iterator>::Item: Zip,\n{\n    OuterZip::from(tuple).map(|item| item.zip())\n}\n\n/// Gets the relative angles between adjacent edges in a [`Polygonal`] type with\n/// positional data in $\\Reals^2$.\n///\n/// Computes the angle between edges at each vertex in order. The angles are\n/// wrapped into the interval $(-\\pi,\\pi]$. The sign of each angle specifies the\n/// orientation of adjacent edges. Given a square, exactly four angles of\n/// $\\plusmn\\frac{\\pi}{2}$ will be returned, with the sign depending on the\n/// winding of the square.\n///\n/// Adjacent vertices with the same position are ignored, as there is no\n/// meaningful edge between such vertices. Because of this, it is possible that\n/// the number of angles returned by this function disagrees with the arity of\n/// the polygon.\n///\n/// [`Polygonal`]: crate::primitive::Polygonal\nfn angles<P>(polygon: &P) -> impl '_ + Clone + Iterator<Item = Scalar<Position<P::Vertex>>>\nwhere\n    P: Polygonal,\n    P::Vertex: AsPosition,\n    Position<P::Vertex>: EuclideanSpace + FiniteDimensional<N = U2>,\n    Scalar<Position<P::Vertex>>: FloatConst,\n{\n    polygon\n        .as_ref()\n        .iter()\n        .map(|vertex| vertex.as_position())\n        .perimeter()\n        .map(|(a, b)| *b - *a)\n        .filter(|vector| !vector.is_zero()) // Reject like positions.\n        .map(|vector| vector.into_xy())\n        .map(|(x, y)| Real::atan2(x, y)) // Absolute angle.\n        .perimeter()\n        .map(|(t1, t2)| t2 - t1) // Relative angle (between segments).\n        .map(|t| {\n            // Wrap the angle into the interval `(-pi, pi]`.\n            let pi = <Scalar<Position<P::Vertex>> as FloatConst>::PI();\n            if t <= -pi {\n                t + (pi + pi)\n            }\n            else if t > pi {\n                t - (pi + pi)\n            }\n            else {\n                t\n            }\n        })\n}\n\nfn umod<T>(n: T, m: T) -> T\nwhere\n    T: Copy + Integer,\n{\n    ((n % m) + m) % m\n}\n\n#[cfg(test)]\nmod tests {\n    use nalgebra::Point2;\n    use theon::adjunct::Converged;\n    use theon::space::EuclideanSpace;\n\n    use crate::primitive::{NGon, Polygonal, Tetragon, Trigon};\n\n    type E2 = Point2<f64>;\n\n    #[test]\n    fn convexity() {\n        // Convex triangle.\n        let trigon = Trigon::new(\n            E2::from_xy(0.0, 1.0),\n            E2::from_xy(1.0, 0.0),\n            E2::from_xy(-1.0, 0.0),\n        );\n        assert!(trigon.is_convex());\n\n        // Convex quadrilateral.\n        let tetragon = Tetragon::new(\n            E2::from_xy(1.0, 1.0),\n            E2::from_xy(1.0, -1.0),\n            E2::from_xy(-1.0, -1.0),\n            E2::from_xy(-1.0, 1.0),\n        );\n        assert!(tetragon.is_convex());\n\n        // Degenerate (collinear) triangle. Not convex.\n        let trigon = Trigon::new(\n            E2::from_xy(0.0, 0.0),\n            E2::from_xy(0.0, 1.0),\n            E2::from_xy(0.0, 2.0),\n        );\n        assert!(!trigon.is_convex());\n\n        // Degenerate (converged) triangle. Not convex.\n        let trigon = Trigon::converged(E2::origin());\n        assert!(!trigon.is_convex());\n\n        // Self-intersecting pentagon. Not convex.\n        let pentagon = NGon::from([\n            E2::from_xy(1.0, 1.0),\n            E2::from_xy(1.0, -1.0),\n            E2::from_xy(-1.0, -1.0),\n            E2::from_xy(-1.0, 1.0),\n            E2::from_xy(0.0, -2.0), // Self-intersecting vertex.\n        ]);\n        assert!(!pentagon.is_convex());\n    }\n}\n"
  },
  {
    "path": "plexus/src/primitive/sphere.rs",
    "content": "//! Sphere primitives.\n//!\n//! # Examples\n//!\n//! Generating a graph from the positional data of a $uv$-sphere.\n//!\n//! ```rust\n//! # extern crate decorum;\n//! # extern crate nalgebra;\n//! # extern crate plexus;\n//! #\n//! use decorum::R64;\n//! use nalgebra::Point3;\n//! use plexus::graph::MeshGraph;\n//! use plexus::index::HashIndexer;\n//! use plexus::prelude::*;\n//! use plexus::primitive::generate::Position;\n//! use plexus::primitive::sphere::UvSphere;\n//!\n//! type E3 = Point3<R64>;\n//!\n//! let mut graph = UvSphere::new(16, 8)\n//!     .polygons::<Position<E3>>()\n//!     .collect_with_indexer::<MeshGraph<E3>, _>(HashIndexer::default())\n//!     .unwrap();\n//! ```\n\nuse num::traits::real::Real;\nuse num::traits::FloatConst;\nuse num::{NumCast, One, ToPrimitive};\nuse std::cmp;\nuse theon::adjunct::Map;\nuse theon::query::Unit;\nuse theon::space::{EuclideanSpace, FiniteDimensional, Scalar, Vector};\nuse typenum::U3;\n\nuse crate::primitive::generate::{\n    AttributeGenerator, AttributePolygonGenerator, AttributeVertexGenerator, Generator,\n    IndexingPolygonGenerator, Normal, PolygonGenerator, Position,\n};\nuse crate::primitive::{BoundedPolygon, Tetragon, Trigon};\n\n#[derive(Clone, Copy)]\npub struct Bounds<S>\nwhere\n    S: EuclideanSpace,\n{\n    radius: Scalar<S>,\n}\n\nimpl<S> Bounds<S>\nwhere\n    S: EuclideanSpace,\n{\n    pub fn with_radius(radius: Scalar<S>) -> Self {\n        Bounds { radius }\n    }\n\n    pub fn with_width(width: Scalar<S>) -> Self {\n        Self::with_radius(width / (Scalar::<S>::one() + One::one()))\n    }\n\n    pub fn unit_radius() -> Self {\n        Self::with_radius(One::one())\n    }\n\n    pub fn unit_width() -> Self {\n        Self::with_width(One::one())\n    }\n}\n\nimpl<S> Default for Bounds<S>\nwhere\n    S: EuclideanSpace,\n{\n    fn default() -> Self {\n        Self::unit_radius()\n    }\n}\n\n#[derive(Clone, Copy)]\npub struct UvSphere {\n    nu: usize, // Meridians.\n    nv: usize, // Parallels.\n}\n\nimpl UvSphere {\n    pub fn new(nu: usize, nv: usize) -> Self {\n        UvSphere {\n            nu: cmp::max(3, nu),\n            nv: cmp::max(2, nv),\n        }\n    }\n\n    fn vertex_with_position_from<S>(\n        &self,\n        state: &<Self as AttributeGenerator<Position<S>>>::State,\n        u: usize,\n        v: usize,\n    ) -> S\n    where\n        Self: AttributeGenerator<Position<S>, State = Bounds<S>>,\n        S: EuclideanSpace + FiniteDimensional<N = U3>,\n        Scalar<S>: FloatConst,\n    {\n        let one = Scalar::<S>::one();\n        let pi = FloatConst::PI();\n        let u = (into_scalar::<_, S>(u) / into_scalar::<_, S>(self.nu)) * pi * (one + one);\n        let v = (into_scalar::<_, S>(v) / into_scalar::<_, S>(self.nv)) * pi;\n        S::from_xyz(\n            state.radius * u.cos() * v.sin(),\n            state.radius * u.sin() * v.sin(),\n            state.radius * v.cos(),\n        )\n    }\n\n    fn index_for_position(&self, u: usize, v: usize) -> usize {\n        if v == 0 {\n            0\n        }\n        else if v == self.nv {\n            ((self.nv - 1) * self.nu) + 1\n        }\n        else {\n            ((v - 1) * self.nu) + (u % self.nu) + 1\n        }\n    }\n\n    fn map_polygon_index(&self, index: usize) -> (usize, usize) {\n        (index % self.nu, index / self.nu)\n    }\n}\n\nimpl Default for UvSphere {\n    fn default() -> Self {\n        UvSphere::new(16, 16)\n    }\n}\n\nimpl PolygonGenerator for UvSphere {\n    fn polygon_count(&self) -> usize {\n        self.nu * self.nv\n    }\n}\n\nimpl<S> AttributeGenerator<Normal<S>> for UvSphere\nwhere\n    S: EuclideanSpace + FiniteDimensional<N = U3>,\n{\n    type State = ();\n}\n\nimpl<S> AttributeVertexGenerator<Normal<S>> for UvSphere\nwhere\n    S: EuclideanSpace + FiniteDimensional<N = U3>,\n    Scalar<S>: FloatConst,\n{\n    type Output = Unit<Vector<S>>;\n\n    fn vertex_count(&self) -> usize {\n        (self.nv - 1) * self.nu + 2\n    }\n\n    fn vertex_from(&self, _: &Self::State, index: usize) -> Self::Output {\n        let position =\n            AttributeVertexGenerator::<Position<S>>::vertex_from(self, &Default::default(), index);\n        Unit::try_from_inner(position.into_coordinates()).expect(\"non-zero vector\")\n    }\n}\n\nimpl<S> AttributePolygonGenerator<Normal<S>> for UvSphere\nwhere\n    S: EuclideanSpace + FiniteDimensional<N = U3>,\n    Scalar<S>: FloatConst,\n{\n    type Output = BoundedPolygon<Unit<Vector<S>>>;\n\n    fn polygon_from(&self, _: &Self::State, index: usize) -> Self::Output {\n        AttributePolygonGenerator::<Position<S>>::polygon_from(self, &Default::default(), index)\n            .map(|position| {\n                Unit::try_from_inner(position.into_coordinates()).expect(\"non-zero vector\")\n            })\n    }\n}\n\nimpl<S> IndexingPolygonGenerator<Normal<S>> for UvSphere {\n    type Output = BoundedPolygon<usize>;\n\n    fn indexing_polygon(&self, index: usize) -> Self::Output {\n        IndexingPolygonGenerator::<Position<S>>::indexing_polygon(self, index)\n    }\n}\n\nimpl<S> AttributeGenerator<Position<S>> for UvSphere\nwhere\n    S: EuclideanSpace + FiniteDimensional<N = U3>,\n{\n    type State = Bounds<S>;\n}\n\nimpl<S> AttributeVertexGenerator<Position<S>> for UvSphere\nwhere\n    S: EuclideanSpace + FiniteDimensional<N = U3>,\n    Scalar<S>: FloatConst,\n{\n    type Output = S;\n\n    fn vertex_count(&self) -> usize {\n        (self.nv - 1) * self.nu + 2\n    }\n\n    fn vertex_from(&self, state: &Self::State, index: usize) -> Self::Output {\n        let count = AttributeVertexGenerator::<Position<S>>::vertex_count(self);\n        if index == 0 {\n            self.vertex_with_position_from::<S>(state, 0, 0)\n        }\n        else if index == (count - 1) {\n            self.vertex_with_position_from::<S>(state, 0, self.nv)\n        }\n        else {\n            let index = index - 1;\n            self.vertex_with_position_from::<S>(state, index % self.nu, (index / self.nu) + 1)\n        }\n    }\n}\n\nimpl<S> AttributePolygonGenerator<Position<S>> for UvSphere\nwhere\n    S: EuclideanSpace + FiniteDimensional<N = U3>,\n    Scalar<S>: FloatConst,\n{\n    type Output = BoundedPolygon<S>;\n\n    fn polygon_from(&self, state: &Self::State, index: usize) -> Self::Output {\n        // Prevent floating point rounding errors by wrapping the incremented\n        // values for `(u, v)` into `(p, q)`. This is important for indexing\n        // geometry, because small differences in the computation of spatial\n        // vertices will produce redundant output vertices. There should be\n        // exactly `(nv - 1) * nu + 2` unique values of `(u, v)` used to\n        // generate positions.\n        //\n        // There are two important observations:\n        //\n        //   1. `u` must wrap, but `v` need not. There are `nu` meridians of\n        //      points and polygons, but there are `nv` parallels of polygons\n        //      and `nv + 1` parallels of points.\n        //   2. `u`, which represents a meridian, is meaningless at the poles,\n        //      and can be normalized to zero.\n        let (u, v) = self.map_polygon_index(index);\n        let (p, q) = ((u + 1) % self.nu, v + 1);\n\n        // Generate the vertices at the requested meridian and parallel. The\n        // lower bound of `(u, v)` is always used, so compute that in advance\n        // (`lower`). Emit triangles at the poles, otherwise quadrilaterals.\n        let lower = self.vertex_with_position_from(state, u, v);\n        if v == 0 {\n            Trigon::new(\n                lower,\n                self.vertex_with_position_from(state, u, q),\n                self.vertex_with_position_from(state, p, q),\n            )\n            .into()\n        }\n        else if v == self.nv - 1 {\n            Trigon::new(\n                // Normalize `u` at the pole, using `(0, nv)` in place of\n                // `(p, q)`.\n                self.vertex_with_position_from(state, 0, self.nv),\n                self.vertex_with_position_from(state, p, v),\n                lower,\n            )\n            .into()\n        }\n        else {\n            Tetragon::new(\n                lower,\n                self.vertex_with_position_from(state, u, q),\n                self.vertex_with_position_from(state, p, q),\n                self.vertex_with_position_from(state, p, v),\n            )\n            .into()\n        }\n    }\n}\n\nimpl<S> IndexingPolygonGenerator<Position<S>> for UvSphere {\n    type Output = BoundedPolygon<usize>;\n\n    fn indexing_polygon(&self, index: usize) -> Self::Output {\n        let (u, v) = self.map_polygon_index(index);\n        let (p, q) = (u + 1, v + 1);\n\n        let low = self.index_for_position(u, v);\n        let high = self.index_for_position(p, q);\n        if v == 0 {\n            Trigon::new(low, self.index_for_position(u, q), high).into()\n        }\n        else if v == self.nv - 1 {\n            Trigon::new(high, self.index_for_position(p, v), low).into()\n        }\n        else {\n            Tetragon::new(\n                low,\n                self.index_for_position(u, q),\n                high,\n                self.index_for_position(p, v),\n            )\n            .into()\n        }\n    }\n}\n\nimpl Generator for UvSphere {}\n\nfn into_scalar<T, S>(value: T) -> Scalar<S>\nwhere\n    T: ToPrimitive,\n    S: EuclideanSpace,\n{\n    <Scalar<S> as NumCast>::from(value).unwrap()\n}\n\n#[cfg(test)]\nmod tests {\n    use nalgebra::Point3;\n    use std::collections::BTreeSet;\n\n    use crate::prelude::*;\n    use crate::primitive::generate::Position;\n    use crate::primitive::sphere::UvSphere;\n\n    type E3 = Point3<f64>;\n\n    #[test]\n    fn vertex_count() {\n        assert_eq!(\n            5,\n            UvSphere::new(3, 2)\n                .vertices::<Position<E3>>() // 5 conjoint vertices.\n                .count()\n        );\n    }\n\n    #[test]\n    fn polygon_vertex_count() {\n        assert_eq!(\n            18,\n            UvSphere::new(3, 2)\n                .polygons::<Position<E3>>() // 6 triangles, 18 vertices.\n                .vertices()\n                .count()\n        );\n    }\n\n    #[test]\n    fn position_index_to_vertex_mapping() {\n        assert_eq!(\n            5,\n            UvSphere::new(3, 2)\n                .indexing_polygons::<Position>() // 18 vertices, 5 indices.\n                .vertices()\n                .collect::<BTreeSet<_>>()\n                .len()\n        )\n    }\n}\n"
  },
  {
    "path": "plexus/src/transact.rs",
    "content": "use std::fmt::Debug;\nuse std::mem;\n\npub trait Transact<T = ()>: Sized {\n    type Commit;\n    type Abort;\n    type Error: Debug;\n\n    fn commit(self) -> Result<Self::Commit, (Self::Abort, Self::Error)>;\n\n    // LINT: This is indeed a complex type, but refactoring into a type definition cannot be done\n    //       trivially (and may not reduce complexity).\n    #[expect(clippy::type_complexity)]\n    fn commit_with<F, U, E>(mut self, f: F) -> Result<(Self::Commit, U), (Self::Abort, Self::Error)>\n    where\n        F: FnOnce(&mut Self) -> Result<U, E>,\n        E: Into<Self::Error>,\n    {\n        match f(&mut self) {\n            Ok(value) => self.commit().map(|output| (output, value)),\n            Err(error) => Err((self.abort(), error.into())),\n        }\n    }\n\n    fn abort(self) -> Self::Abort;\n}\n\npub trait Bypass<T>: Transact<T> {\n    fn bypass(self) -> Self::Commit;\n}\n\npub trait BypassOrCommit<T>: Bypass<T> {\n    fn bypass_or_commit(self) -> Result<Self::Commit, (Self::Abort, Self::Error)>;\n\n    // LINT: This is indeed a complex type, but refactoring into a type definition cannot be done\n    //       trivially (and may not reduce complexity).\n    #[expect(clippy::type_complexity)]\n    fn bypass_or_commit_with<F, X, E>(\n        self,\n        f: F,\n    ) -> Result<(Self::Commit, X), (Self::Abort, Self::Error)>\n    where\n        F: FnOnce(&mut Self) -> Result<X, E>,\n        E: Into<Self::Error>;\n}\n\n#[cfg(test)]\nimpl<T, U> BypassOrCommit<U> for T\nwhere\n    T: Bypass<U>,\n{\n    fn bypass_or_commit(self) -> Result<T::Commit, (T::Abort, T::Error)> {\n        self.commit()\n    }\n\n    fn bypass_or_commit_with<F, X, E>(self, f: F) -> Result<(T::Commit, X), (T::Abort, T::Error)>\n    where\n        F: FnOnce(&mut T) -> Result<X, E>,\n        E: Into<T::Error>,\n    {\n        self.commit_with(f)\n    }\n}\n\n#[cfg(not(test))]\nimpl<T, U> BypassOrCommit<U> for T\nwhere\n    T: Bypass<U>,\n{\n    fn bypass_or_commit(self) -> Result<T::Commit, (T::Abort, T::Error)> {\n        Ok(self.bypass())\n    }\n\n    fn bypass_or_commit_with<F, X, E>(\n        mut self,\n        f: F,\n    ) -> Result<(T::Commit, X), (T::Abort, T::Error)>\n    where\n        F: FnOnce(&mut T) -> Result<X, E>,\n        E: Into<T::Error>,\n    {\n        match f(&mut self) {\n            Ok(value) => Ok((self.bypass(), value)),\n            Err(error) => Err((self.abort(), error.into())),\n        }\n    }\n}\n\npub trait Mutate<T>: Transact<T, Commit = T> {\n    fn replace(target: &mut T, replacement: T) -> Swapped<T, Self>\n    where\n        Self: From<T> + Transact<T>,\n    {\n        Swapped::replace(target, replacement)\n    }\n\n    fn take(target: &mut T) -> Swapped<T, Self>\n    where\n        Self: From<T> + Transact<T>,\n        T: Default,\n    {\n        Swapped::take(target)\n    }\n}\n\nimpl<T, U> Mutate<U> for T where T: Transact<U, Commit = U> {}\n\npub trait ClosedInput: Transact<<Self as ClosedInput>::Input> {\n    type Input;\n}\n\ntrait Drain<T> {\n    fn as_option_mut(&mut self) -> &mut Option<T>;\n\n    fn drain(&mut self) -> T {\n        self.as_option_mut().take().expect(\"drained\")\n    }\n\n    fn undrain(&mut self, value: T) {\n        let drained = self.as_option_mut();\n        if drained.is_some() {\n            panic!(\"undrained\");\n        }\n        else {\n            *drained = Some(value);\n        }\n    }\n\n    fn try_swap_or<F, U, E>(&mut self, value: T, mut f: F) -> Result<U, E>\n    where\n        F: FnMut(T) -> Result<(T, U), E>,\n    {\n        match f(self.drain()) {\n            Ok((value, output)) => {\n                self.undrain(value);\n                Ok(output)\n            }\n            Err(error) => {\n                self.undrain(value);\n                Err(error)\n            }\n        }\n    }\n}\n\npub struct Swapped<'a, T, M>\nwhere\n    M: From<T> + Mutate<T>,\n{\n    inner: Option<(&'a mut T, M)>,\n}\n\nimpl<'a, T, M> Swapped<'a, T, M>\nwhere\n    M: From<T> + Mutate<T>,\n{\n    pub fn replace(target: &'a mut T, replacement: T) -> Self {\n        let mutant = mem::replace(target, replacement);\n        Swapped {\n            inner: Some((target, M::from(mutant))),\n        }\n    }\n\n    pub fn take(target: &'a mut T) -> Self\n    where\n        T: Default,\n    {\n        Swapped::replace(target, T::default())\n    }\n\n    fn drain_and_commit(\n        &mut self,\n    ) -> Result<&'a mut T, (&'a mut T, <Self as Transact<&'a mut T>>::Error)> {\n        let (target, inner) = self.drain();\n        match inner.commit() {\n            Ok(mutant) => {\n                *target = mutant;\n                Ok(target)\n            }\n            Err((_, error)) => Err((target, error)),\n        }\n    }\n\n    fn drain_and_abort(&mut self) -> &'a mut T {\n        let (target, inner) = self.drain();\n        inner.abort();\n        target\n    }\n}\n\nimpl<'a, T, M> Swapped<'a, T, M>\nwhere\n    M: Bypass<T> + From<T> + Mutate<T>,\n{\n    pub fn drain_and_bypass(&mut self) -> &'a mut T {\n        let (target, inner) = self.drain();\n        *target = inner.bypass();\n        target\n    }\n}\n\nimpl<T, M> AsRef<M> for Swapped<'_, T, M>\nwhere\n    M: From<T> + Mutate<T>,\n{\n    fn as_ref(&self) -> &M {\n        &self.inner.as_ref().unwrap().1\n    }\n}\n\nimpl<T, M> AsMut<M> for Swapped<'_, T, M>\nwhere\n    M: From<T> + Mutate<T>,\n{\n    fn as_mut(&mut self) -> &mut M {\n        &mut self.inner.as_mut().unwrap().1\n    }\n}\n\nimpl<'a, T, M> Bypass<&'a mut T> for Swapped<'a, T, M>\nwhere\n    M: Bypass<T> + From<T> + Mutate<T>,\n{\n    fn bypass(mut self) -> Self::Commit {\n        let mutant = self.drain_and_bypass();\n        mem::forget(self);\n        mutant\n    }\n}\n\nimpl<'a, T, M> Drain<(&'a mut T, M)> for Swapped<'a, T, M>\nwhere\n    M: From<T> + Mutate<T>,\n{\n    fn as_option_mut(&mut self) -> &mut Option<(&'a mut T, M)> {\n        &mut self.inner\n    }\n}\n\nimpl<T, M> Drop for Swapped<'_, T, M>\nwhere\n    M: From<T> + Mutate<T>,\n{\n    fn drop(&mut self) {\n        self.drain_and_abort();\n    }\n}\n\nimpl<'a, T, M> From<&'a mut T> for Swapped<'a, T, M>\nwhere\n    T: Default,\n    M: From<T> + Mutate<T>,\n{\n    fn from(target: &'a mut T) -> Self {\n        Self::replace(target, Default::default())\n    }\n}\n\nimpl<'a, T, M> Transact<&'a mut T> for Swapped<'a, T, M>\nwhere\n    M: From<T> + Mutate<T>,\n{\n    type Commit = &'a mut T;\n    type Abort = &'a mut T;\n    type Error = <M as Transact<T>>::Error;\n\n    fn commit(mut self) -> Result<Self::Commit, (Self::Abort, Self::Error)> {\n        let mutant = self.drain_and_commit();\n        mem::forget(self);\n        mutant\n    }\n\n    fn abort(mut self) -> Self::Abort {\n        let mutant = self.drain_and_abort();\n        mem::forget(self);\n        mutant\n    }\n}\n"
  },
  {
    "path": "rustdoc.sh",
    "content": "#! /usr/bin/env bash\n\n# TODO: This script sets the `RUSTDOCFLAGS` environment variable to configure\n#       the KaTeX header for documentation. This cannot be accomplished with\n#       Cargo configuration yet.\n#\n#       See https://github.com/rust-lang/cargo/issues/8097\n\nset -e\n\nRUSTDOCFLAGS=--html-in-header=$(realpath ./doc/katex-header.html) \\\ncargo +nightly doc $@\n"
  },
  {
    "path": "rustfmt.toml",
    "content": "control_brace_style = \"ClosingNextLine\"\nformat_code_in_doc_comments = true\n"
  }
]