Import 'grid' crate
Request Document: go/android-rust-importing-crates
For CL Reviewers: go/android3p#cl-review
Bug: 395134064
Test: m libgrid -j
Change-Id: Ia0b4dc83c7f4d88991065ad45a1b491b85beb503
diff --git a/crates/grid/.android-checksum.json b/crates/grid/.android-checksum.json
new file mode 100644
index 0000000..6a36c50
--- /dev/null
+++ b/crates/grid/.android-checksum.json
@@ -0,0 +1 @@
+{"package":null,"files":{".cargo-checksum.json":"8b0d4f770e4717dfadc316449d56be8f25455b240c705988ebf48c4f248e4fc3","Android.bp":"bb317acfae50c8113d8c01c7b42cf1996fbf79e893a6a849bdd4e3134c912dff","Cargo.toml":"dd5e534a80da98507c3e49ac93ea203787a77d75b546be06dce55ccafa6e2c88","LICENSE":"d59b3f573f9e3f7318d9c24f042f710e1184bc5522cef96be7954dc6ba77c927","METADATA":"956d838673e3619c2126e1eb50588b65839984b2fa822aa952fa2906ace3317b","MODULE_LICENSE_MIT":"0d6f8afa3940b7f06bebee651376d43bc8b0d5b437337be2696d30377451e93a","README.md":"349942b55ac9eaf352b1ccaf8a67b15fa9d953fffc9ab08348af57c7f7654476","benches/benches.rs":"acb1661440bbfec83b267be4fa8d1a8de22dd2c2467ff01b587891a9fc3674d2","cargo_embargo.json":"0be745f01ba4955b20f2cb5011168c4d8cd396af75c007035ec693c67b17bce7","src/lib.rs":"99633cf7f4fb283046c49513c7ba451cf08374d506dc1df5d1ebc38d117ca454"}}
\ No newline at end of file
diff --git a/crates/grid/.cargo-checksum.json b/crates/grid/.cargo-checksum.json
new file mode 100644
index 0000000..381356b
--- /dev/null
+++ b/crates/grid/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"69fec42da5d88c7c01abb0e2482d0dbb7dfaf16495fb4e83da3df64b91566b77","LICENSE":"965116a3d1e412221d5ff2e58edfab30a62fe112f0f6bf13136a946907869da9","README.md":"7291a0c7fce70323458500e07eb8822213a851600d8b00aef45b05c1209929fb","benches/benches.rs":"d492daebc19d65853c8a1baee99e9f1a09d182413121f23f465357706c9d9698","src/lib.rs":"9d86db518aa0585f064e2c283099e1e4f76c57e857f19193b32dd2bd7764927b"},"package":"fb6ae361963ea5fe52038156ea1729f3b4e4ccc0711c362ab2b2d2c0a259e7c3"}
\ No newline at end of file
diff --git a/crates/grid/Android.bp b/crates/grid/Android.bp
new file mode 100644
index 0000000..bb1aa23
--- /dev/null
+++ b/crates/grid/Android.bp
@@ -0,0 +1,34 @@
+// This file is generated by cargo_embargo.
+// Do not modify this file because the changes will be overridden on upgrade.
+
+package {
+ default_applicable_licenses: ["external_rust_crates_grid_license"],
+ default_team: "trendy_team_android_rust",
+}
+
+license {
+ name: "external_rust_crates_grid_license",
+ visibility: [":__subpackages__"],
+ license_kinds: ["SPDX-license-identifier-MIT"],
+ license_text: ["LICENSE"],
+}
+
+rust_library {
+ name: "libgrid",
+ host_supported: true,
+ crate_name: "grid",
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.16.1",
+ crate_root: "src/lib.rs",
+ edition: "2018",
+ features: [
+ "default",
+ "std",
+ ],
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
+ product_available: true,
+ vendor_available: true,
+}
diff --git a/crates/grid/Cargo.toml b/crates/grid/Cargo.toml
new file mode 100644
index 0000000..f074895
--- /dev/null
+++ b/crates/grid/Cargo.toml
@@ -0,0 +1,77 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+rust-version = "1.51"
+name = "grid"
+version = "0.16.1"
+authors = ["Armin Becher <armin.becher@gmai.com>"]
+build = false
+autolib = false
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
+description = "Dynamic generic 2D data structure."
+documentation = "https://docs.rs/grid"
+readme = "README.md"
+keywords = [
+ "2D",
+ "array",
+ "matrix",
+ "data-structure",
+ "2D-vector",
+]
+categories = [
+ "science",
+ "data-structures",
+]
+license = "MIT"
+repository = "https://github.com/becheran/grid"
+
+[lib]
+name = "grid"
+path = "src/lib.rs"
+
+[[bench]]
+name = "benches"
+path = "benches/benches.rs"
+harness = false
+
+[dependencies.serde]
+version = "1.0.217"
+features = ["derive"]
+optional = true
+
+[dev-dependencies.criterion]
+version = "0.5.1"
+
+[dev-dependencies.rand]
+version = "0.9.0"
+
+[dev-dependencies.serde_json]
+version = "1.0.138"
+
+[features]
+default = ["std"]
+serde = [
+ "std",
+ "dep:serde",
+]
+std = []
+
+[badges.gitlab]
+branch = "master"
+repository = "becheran/grid_ci"
+
+[badges.maintenance]
+status = "actively-developed"
diff --git a/crates/grid/LICENSE b/crates/grid/LICENSE
new file mode 100644
index 0000000..9ffd7ce
--- /dev/null
+++ b/crates/grid/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 Armin Becher
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/crates/grid/METADATA b/crates/grid/METADATA
new file mode 100644
index 0000000..0c1c6bb
--- /dev/null
+++ b/crates/grid/METADATA
@@ -0,0 +1,17 @@
+name: "grid"
+description: "Dynamic generic 2D data structure."
+third_party {
+ version: "0.16.1"
+ license_type: NOTICE
+ last_upgrade_date {
+ year: 2025
+ month: 2
+ day: 11
+ }
+ homepage: "https://crates.io/crates/grid"
+ identifier {
+ type: "Archive"
+ value: "https://static.crates.io/crates/grid/grid-0.16.1.crate"
+ version: "0.16.1"
+ }
+}
diff --git a/crates/grid/MODULE_LICENSE_MIT b/crates/grid/MODULE_LICENSE_MIT
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/crates/grid/MODULE_LICENSE_MIT
diff --git a/crates/grid/README.md b/crates/grid/README.md
new file mode 100644
index 0000000..6e9304f
--- /dev/null
+++ b/crates/grid/README.md
@@ -0,0 +1,19 @@
+# Grid
+
+[](https://docs.rs/grid)
+[](https://crates.io/crates/grid)
+[](https://github.com/becheran/grid/actions)
+[](https://opensource.org/licenses/MIT)
+
+Data structure grid for rust. Provide a two dimensional data structure for rust that is easy to use and fast.
+Most of the functionality provided by the [std::vec::Vec](https://doc.rust-lang.org/std/vec/struct.Vec.html) type for one dimensional vectors
+is implemented for two dimensions in this crate.
+
+To use *grid* with *no_std* import the library such as:
+
+``` toml
+grid = { version = "*", default-features = false }
+```
+
+- [documentation](https://docs.rs/grid/)
+- [library on crates.io](https://crates.io/crates/grid)
diff --git a/crates/grid/benches/benches.rs b/crates/grid/benches/benches.rs
new file mode 100644
index 0000000..a912b6a
--- /dev/null
+++ b/crates/grid/benches/benches.rs
@@ -0,0 +1,207 @@
+use criterion::{criterion_group, criterion_main, Criterion};
+use grid::grid;
+use grid::Grid;
+use rand::Rng;
+
+const SIZE: usize = 1_000;
+
+fn init_vec_vec() -> Vec<Vec<u8>> {
+ vec![vec![0; SIZE]; SIZE]
+}
+
+fn init_grid() -> Grid<u8> {
+ Grid::init(SIZE, SIZE, 0)
+}
+
+fn criterion_benchmark(c: &mut Criterion) {
+ let mut rng = rand::rng();
+ let mut rand = || rng.random_range(0..SIZE);
+
+ // Init macro
+ c.bench_function("vecvec_init_macro", |b| {
+ b.iter(|| {
+ vec![
+ vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
+ vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
+ vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
+ vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
+ vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
+ vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
+ vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
+ vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
+ vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
+ vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
+ ]
+ })
+ });
+ c.bench_function("grid_init_macro", |b| {
+ b.iter(|| {
+ grid![[0,1,2,3,4,5,6,7,8,9]
+ [0,1,2,3,4,5,6,7,8,9]
+ [0,1,2,3,4,5,6,7,8,9]
+ [0,1,2,3,4,5,6,7,8,9]
+ [0,1,2,3,4,5,6,7,8,9]
+ [0,1,2,3,4,5,6,7,8,9]
+ [0,1,2,3,4,5,6,7,8,9]
+ [0,1,2,3,4,5,6,7,8,9]
+ [0,1,2,3,4,5,6,7,8,9]
+ [0,1,2,3,4,5,6,7,8,9]]
+ })
+ });
+ c.bench_function("grid_from_vec", |b| {
+ b.iter(|| {
+ let vec = vec![
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3,
+ 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ ];
+ Grid::from_vec(vec, 10)
+ })
+ });
+
+ // Constructor
+ c.bench_function("vecvec_init", |b| b.iter(|| vec![vec![0; SIZE]; SIZE]));
+ c.bench_function("grid_init", |b| b.iter(|| Grid::init(SIZE, SIZE, 0)));
+
+ // Index
+ c.bench_function("vecvec_idx", |b| {
+ let vec_vec = init_vec_vec();
+ b.iter_batched(
+ || (rand(), rand()),
+ |(x, y)| {
+ let _v = vec_vec[x][y];
+ },
+ criterion::BatchSize::SmallInput,
+ )
+ });
+ c.bench_function("grid_idx", |b| {
+ let grid = init_grid();
+ b.iter_batched(
+ || (rand(), rand()),
+ |(x, y)| grid[(x, y)],
+ criterion::BatchSize::SmallInput,
+ )
+ });
+ c.bench_function("vecvec_get", |b| {
+ let vec_vec = init_vec_vec();
+ b.iter_batched(
+ || (rand(), rand()),
+ |(x, y)| {
+ let _v = vec_vec.get(x).unwrap().get(y).unwrap();
+ },
+ criterion::BatchSize::SmallInput,
+ )
+ });
+ c.bench_function("grid_get", |b| {
+ let grid = init_grid();
+ b.iter_batched(
+ || (rand(), rand()),
+ |(x, y)| {
+ let _v = grid.get(x, y).unwrap();
+ },
+ criterion::BatchSize::SmallInput,
+ )
+ });
+
+ //Set
+ c.bench_function("vecvec_set", |b| {
+ let mut vec_vec = init_vec_vec();
+ b.iter_batched(
+ || (rand(), rand()),
+ |(x, y)| vec_vec[x][y] = 42,
+ criterion::BatchSize::SmallInput,
+ )
+ });
+ c.bench_function("grid_set", |b| {
+ let mut g = init_grid();
+ b.iter_batched(
+ || (rand(), rand()),
+ |(x, y)| g[(x, y)] = 42,
+ criterion::BatchSize::SmallInput,
+ )
+ });
+
+ // Push
+ c.bench_function("grid_push_row", |b| {
+ let grid = init_grid();
+ b.iter_batched(
+ || grid.clone(),
+ |mut g| g.push_row(vec![0; SIZE]),
+ criterion::BatchSize::SmallInput,
+ )
+ });
+ c.bench_function("grid_push_col", |b| {
+ let grid = init_grid();
+ b.iter_batched(
+ || grid.clone(),
+ |mut g| g.push_col(vec![0; SIZE]),
+ criterion::BatchSize::SmallInput,
+ )
+ });
+
+ // Pop
+ c.bench_function("grid_pop_row", |b| {
+ let grid = init_grid();
+ b.iter_batched(
+ || grid.clone(),
+ |mut g| g.pop_row(),
+ criterion::BatchSize::SmallInput,
+ )
+ });
+ c.bench_function("grid_pop_col", |b| {
+ let grid = init_grid();
+ b.iter_batched(
+ || grid.clone(),
+ |mut g| g.pop_col(),
+ criterion::BatchSize::SmallInput,
+ )
+ });
+
+ // Remove
+ c.bench_function("grid_remove_row", |b| {
+ let grid = init_grid();
+ b.iter_batched(
+ || grid.clone(),
+ |mut g| g.remove_row(2),
+ criterion::BatchSize::SmallInput,
+ )
+ });
+ c.bench_function("grid_remove_col", |b| {
+ let grid = init_grid();
+ b.iter_batched(
+ || grid.clone(),
+ |mut g| g.remove_col(2),
+ criterion::BatchSize::SmallInput,
+ )
+ });
+
+ // Rotation
+ c.bench_function("grid_rotate_left", |b| {
+ let grid = init_grid();
+ b.iter_batched(
+ || grid.clone(),
+ |mut g| g.rotate_left(),
+ criterion::BatchSize::SmallInput,
+ )
+ });
+ c.bench_function("grid_rotate_right", |b| {
+ let grid = init_grid();
+ b.iter_batched(
+ || grid.clone(),
+ |mut g| g.rotate_right(),
+ criterion::BatchSize::SmallInput,
+ )
+ });
+ c.bench_function("grid_rotate_half", |b| {
+ let grid = init_grid();
+ b.iter_batched(
+ || grid.clone(),
+ |mut g| g.rotate_half(),
+ criterion::BatchSize::SmallInput,
+ )
+ });
+}
+
+criterion_group!(benches, criterion_benchmark);
+criterion_main!(benches);
diff --git a/crates/grid/cargo_embargo.json b/crates/grid/cargo_embargo.json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/crates/grid/cargo_embargo.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/crates/grid/src/lib.rs b/crates/grid/src/lib.rs
new file mode 100644
index 0000000..5cb6db7
--- /dev/null
+++ b/crates/grid/src/lib.rs
@@ -0,0 +1,3637 @@
+#![warn(clippy::all, clippy::pedantic, clippy::nursery)]
+/*!
+# Two Dimensional Grid
+Continuous growable 2D data structure.
+The purpose of this crate is to provide an universal data structure that is faster,
+uses less memory, and is easier to use than a naive `Vec<Vec<T>>` solution.
+
+This crate will always provide a 2D data structure. If you need three or more dimensions take a look at the
+[ndarray](https://docs.rs/ndarray/0.13.0/ndarray/) library. The `grid` crate is a container for all kind of data.
+If you need to perform matrix operations, you are better off with a linear algebra lib, such as
+[cgmath](https://docs.rs/cgmath/0.17.0/cgmath/) or [nalgebra](https://docs.rs/nalgebra/0.21.0/nalgebra/).
+No other dependencies except for the std lib are used.
+Most of the functions `std::Vec<T>` offer are also implemented in `grid` and slightly modified for a 2D data object.
+
+# Memory layout
+
+Similar to *C-like* arrays, `grid` uses a flat 1D `Vec<T>` data structure to have a continuous
+memory data layout. See also [this](https://stackoverflow.com/questions/17259877/1d-or-2d-array-whats-faster)
+explanation of why you should probably use a one-dimensional array approach.
+
+Note that this crate uses a [*row-major*](https://eli.thegreenplace.net/2015/memory-layout-of-multi-dimensional-arrays) memory layout by default.
+
+If you need a specific memory layout, please seek the `*_with_order` constructors. You should also take note that some transformation methods
+change the internal memory layout, like [`transpose`](Grid::transpose).
+
+This choice is important, because operations on rows are faster with a row-major memory layout.
+Likewise, operations on columns are faster with column-major memory layout.
+
+# Examples
+```
+use grid::*;
+let mut grid = grid![[1,2,3]
+ [4,5,6]];
+assert_eq!(grid, Grid::from_vec(vec![1,2,3,4,5,6],3));
+assert_eq!(grid.get(0, 2), Some(&3));
+assert_eq!(grid[(1, 1)], 5);
+assert_eq!(grid.size(), (2, 3));
+grid.push_row(vec![7,8,9]);
+assert_eq!(grid, grid![[1,2,3][4,5,6][7,8,9]])
+ ```
+*/
+
+#![cfg_attr(not(feature = "std"), no_std)]
+
+#[cfg(not(feature = "std"))]
+extern crate alloc;
+#[cfg(not(feature = "std"))]
+use alloc::{format, vec, vec::Vec};
+#[cfg(feature = "serde")]
+use serde::{
+ de::{self, Deserialize, Deserializer, MapAccess, SeqAccess, Visitor},
+ ser::{Serialize, SerializeStruct, Serializer},
+};
+
+use core::cmp::Eq;
+use core::fmt;
+use core::hash;
+use core::iter::StepBy;
+use core::ops::Index;
+use core::ops::IndexMut;
+use core::slice::Iter;
+use core::slice::IterMut;
+use core::{cmp, convert::TryInto};
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! count {
+ () => (0usize);
+ ( $x:tt $($xs:tt)* ) => (1usize + $crate::count!($($xs)*));
+}
+
+/// Init a grid with values.
+///
+/// Each array within `[]` represents a row starting from top to button.
+///
+/// # Examples
+///
+/// In this example a grid of numbers from 1 to 9 is created:
+///
+///
+/// ```
+/// use grid::grid;
+/// let grid = grid![[1, 2, 3]
+/// [4, 5, 6]
+/// [7, 8, 9]];
+/// assert_eq!(grid.size(), (3, 3))
+/// ```
+///
+/// Note that each row must be of the same length. The following example will not compile:
+///
+/// ``` ignore
+/// use grid::grid;
+/// let grid = grid![[1, 2, 3]
+/// [4, 5] // This does not work!
+/// [7, 8, 9]];
+/// ```
+#[macro_export]
+macro_rules! grid {
+ () => {
+ $crate::Grid::from_vec(vec![], 0)
+ };
+ ( [$( $x:expr ),* ]) => { {
+ let vec = vec![$($x),*];
+ let len = vec.len();
+ $crate::Grid::from_vec(vec, len)
+ } };
+ ( [$( $x0:expr ),*] $([$( $x:expr ),*])* ) => {
+ {
+ let mut _assert_width0 = [(); $crate::count!($($x0)*)];
+ let cols = $crate::count!($($x0)*);
+ let rows = 1usize;
+
+ $(
+ let _assert_width = [(); $crate::count!($($x)*)];
+ _assert_width0 = _assert_width;
+ let rows = rows + 1usize;
+ )*
+
+ let mut vec = Vec::with_capacity(rows.checked_mul(cols).unwrap());
+
+ $( vec.push($x0); )*
+ $( $( vec.push($x); )* )*
+
+ $crate::Grid::from_vec(vec, cols)
+ }
+ };
+}
+
+/// Init a column-major grid with values.
+///
+/// Each array within `[]` represents a row starting from top to button.
+///
+/// # Examples
+///
+/// In this example a grid of numbers from 1 to 9 is created:
+///
+/// ```
+/// use grid::grid_cm;
+/// let grid = grid_cm![[1, 2, 3]
+/// [4, 5, 6]
+/// [7, 8, 9]];
+/// assert_eq!(grid.size(), (3, 3));
+/// assert_eq!(grid[(1, 1)], 5);
+/// ```
+///
+/// Note that each row must be of the same length. The following example will not compile:
+///
+/// ``` ignore
+/// use grid::grid_cm;
+/// let grid = grid_cm![[1, 2, 3]
+/// [4, 5] // This does not work!
+/// [7, 8, 9]];
+/// ```
+#[macro_export]
+macro_rules! grid_cm {
+ () => {
+ $crate::Grid::from_vec_with_order(vec![], 0, $crate::Order::ColumnMajor)
+ };
+ ( [$( $x:expr ),* ]) => { {
+ let vec = vec![$($x),*];
+ let len = vec.len();
+ $crate::Grid::from_vec_with_order(vec, len, $crate::Order::ColumnMajor)
+ } };
+ ( [$( $x0:expr ),*] $([$( $x:expr ),*])* ) => {
+ {
+ let mut _assert_width0 = [(); $crate::count!($($x0)*)];
+ let cols = $crate::count!($($x0)*);
+ let rows = 1usize;
+
+ $(
+ let _assert_width = [(); $crate::count!($($x)*)];
+ _assert_width0 = _assert_width;
+ let rows = rows + 1usize;
+ )*
+
+ let vec = Vec::with_capacity(rows.checked_mul(cols).unwrap());
+ let mut grid = $crate::Grid::from_vec_with_order(vec, cols, $crate::Order::ColumnMajor);
+
+ grid.push_row(vec![$($x0),*]);
+ $( grid.push_row(vec![$($x),*]); )*
+
+ grid
+ }
+ };
+}
+
+/// Define the internal memory layout of the grid.
+#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum Order {
+ /// The data is ordered row by row.
+ #[default]
+ RowMajor,
+
+ /// The data is ordered column by column.
+ ColumnMajor,
+}
+
+impl Order {
+ const fn counterpart(self) -> Self {
+ match self {
+ Self::RowMajor => Self::ColumnMajor,
+ Self::ColumnMajor => Self::RowMajor,
+ }
+ }
+}
+
+/// Stores elements of a certain type in a 2D grid structure.
+///
+/// Uses a rust `Vec<T>` type to reference the grid data on the heap.
+/// Also the internal memory layout as well as the number of
+/// rows and columns are stored in the grid data structure.
+///
+/// The size limit of a grid is `rows * cols < usize`.
+pub struct Grid<T> {
+ data: Vec<T>,
+ cols: usize,
+ rows: usize,
+ order: Order,
+}
+
+#[cfg(feature = "serde")]
+impl<'de, T: Deserialize<'de>> Deserialize<'de> for Grid<T> {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ use std::marker::PhantomData;
+ #[derive(serde::Deserialize)]
+ #[serde(field_identifier, rename_all = "lowercase")]
+ enum Field {
+ Data,
+ Cols,
+ Order,
+ }
+
+ struct GridVisitor<T> {
+ _p: PhantomData<T>,
+ }
+
+ impl<'de, T: Deserialize<'de>> Visitor<'de> for GridVisitor<T> {
+ type Value = Grid<T>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("struct Grid")
+ }
+
+ fn visit_seq<V>(self, mut seq: V) -> Result<Grid<T>, V::Error>
+ where
+ V: SeqAccess<'de>,
+ {
+ let cols = seq
+ .next_element()?
+ .ok_or_else(|| de::Error::invalid_length(0, &self))?;
+ let data = seq
+ .next_element()?
+ .ok_or_else(|| de::Error::invalid_length(1, &self))?;
+ let order = seq.next_element()?.unwrap_or_default();
+ Ok(Grid::from_vec_with_order(data, cols, order))
+ }
+
+ fn visit_map<V>(self, mut map: V) -> Result<Grid<T>, V::Error>
+ where
+ V: MapAccess<'de>,
+ {
+ let mut cols = None;
+ let mut data = None;
+ let mut order = None;
+ while let Some(key) = map.next_key()? {
+ match key {
+ Field::Data => {
+ if data.is_some() {
+ return Err(de::Error::duplicate_field("data"));
+ }
+ data = Some(map.next_value()?);
+ }
+ Field::Cols => {
+ if cols.is_some() {
+ return Err(de::Error::duplicate_field("cols"));
+ }
+ cols = Some(map.next_value()?);
+ }
+ Field::Order => {
+ if order.is_some() {
+ return Err(de::Error::duplicate_field("order"));
+ }
+ order = Some(map.next_value()?);
+ }
+ }
+ }
+ let cols = cols.ok_or_else(|| de::Error::missing_field("cols"))?;
+ let data = data.ok_or_else(|| de::Error::missing_field("data"))?;
+ let order = order.unwrap_or_default();
+ Ok(Grid::from_vec_with_order(data, cols, order))
+ }
+ }
+
+ const FIELDS: &[&str] = &["cols", "data", "order"];
+ deserializer.deserialize_struct("Grid", FIELDS, GridVisitor { _p: PhantomData })
+ }
+}
+
+#[cfg(feature = "serde")]
+impl<T: Serialize> Serialize for Grid<T> {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ // 3 is the number of fields in the struct.
+ let mut state = serializer.serialize_struct("Grid", 3)?;
+ state.serialize_field("cols", &self.cols)?;
+ state.serialize_field("data", &self.data)?;
+ state.serialize_field("order", &self.order)?;
+ state.end()
+ }
+}
+
+impl<T> Grid<T> {
+ /// Init a grid of size rows x columns with default values of the given type.
+ /// For example this will generate a 2x3 grid of zeros:
+ ///
+ /// ```
+ /// use grid::Grid;
+ /// let grid : Grid<u8> = Grid::new(2,3);
+ /// assert_eq!(grid[(0, 0)], 0);
+ /// ```
+ ///
+ /// If `rows == 0` or `cols == 0` the grid will be empty with no cols and rows.
+ ///
+ /// This create a grid with a row-major memory layout.
+ /// If you need a column-major one, see [`new_with_order`](Grid::new_with_order).
+ ///
+ /// # Panics
+ ///
+ /// Panics if `rows * cols > usize::MAX`.
+ #[must_use]
+ #[inline]
+ pub fn new(rows: usize, cols: usize) -> Self
+ where
+ T: Default,
+ {
+ Self::new_with_order(rows, cols, Order::default())
+ }
+
+ /// Same as [`new`](Self::new) but with a specific [`Order`].
+ ///
+ /// # Panics
+ ///
+ /// Panics if `rows * cols > usize::MAX`.
+ pub fn new_with_order(rows: usize, cols: usize, order: Order) -> Self
+ where
+ T: Default,
+ {
+ if rows == 0 || cols == 0 {
+ return Self {
+ data: Vec::new(),
+ rows: 0,
+ cols: 0,
+ order,
+ };
+ }
+ let mut data = Vec::new();
+ data.resize_with(rows.checked_mul(cols).unwrap(), T::default);
+ Self {
+ data,
+ cols,
+ rows,
+ order,
+ }
+ }
+
+ /// Init a grid of size rows x columns with the given data element.
+ ///
+ /// If `rows == 0` or `cols == 0` the grid will be empty with no cols and rows.
+ ///
+ /// This create a grid with a row-major memory layout.
+ /// If you need a column-major one, see [`init_with_order`](Grid::init_with_order).
+ ///
+ /// # Panics
+ ///
+ /// Panics if `rows * cols > usize::MAX`.
+ #[inline]
+ pub fn init(rows: usize, cols: usize, data: T) -> Self
+ where
+ T: Clone,
+ {
+ Self::init_with_order(rows, cols, Order::default(), data)
+ }
+
+ /// Same as [`init`](Self::init) but with a specific [`Order`].
+ ///
+ /// # Panics
+ ///
+ /// Panics if `rows * cols > usize::MAX`.
+ pub fn init_with_order(rows: usize, cols: usize, order: Order, data: T) -> Self
+ where
+ T: Clone,
+ {
+ if rows == 0 || cols == 0 {
+ return Self {
+ data: Vec::new(),
+ rows: 0,
+ cols: 0,
+ order,
+ };
+ }
+ Self {
+ data: vec![data; rows.checked_mul(cols).unwrap()],
+ cols,
+ rows,
+ order,
+ }
+ }
+
+ /// Initialises an empty Grid with the capacity to store `cols * rows` elements.
+ /// Similar to `Vec::with_capacity`.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `rows * cols > usize::MAX` or if `rows * cols * size_of::<T>() > isize::MAX`
+ #[must_use]
+ pub fn with_capacity(rows: usize, cols: usize) -> Self {
+ Self::with_capacity_and_order(rows, cols, Order::default())
+ }
+
+ /// Same as [`with_capacity`](Self::with_capacity) but with a specified [`Order`]
+ ///
+ /// # Panics
+ ///
+ /// Panics if `rows * cols > usize::MAX` or if `rows * cols * size_of::<T>() > isize::MAX`
+ #[must_use]
+ pub fn with_capacity_and_order(rows: usize, cols: usize, order: Order) -> Self {
+ Self {
+ data: Vec::with_capacity(rows.checked_mul(cols).unwrap()),
+ cols: 0,
+ rows: 0,
+ order,
+ }
+ }
+
+ /// Returns a grid from a vector with a given column length.
+ /// The length of `vec` must be a multiple of `cols`.
+ ///
+ /// This create a grid with a row-major memory layout.
+ /// If you need a column-major one, see [`from_vec_with_order`](Grid::from_vec_with_order).
+ ///
+ /// For example:
+ ///
+ /// ```
+ /// use grid::Grid;
+ /// let grid = Grid::from_vec(vec![1,2,3,4,5,6], 3);
+ /// assert_eq!(grid.size(), (2, 3));
+ /// ```
+ ///
+ /// will create a grid with the following layout:
+ /// \[1,2,3\]
+ /// \[4,5,6\]
+ ///
+ /// This example will fail, because `vec.len()` is not a multiple of `cols`:
+ ///
+ /// ``` should_panic
+ /// use grid::Grid;
+ /// Grid::from_vec(vec![1,2,3,4,5], 3);
+ /// ```
+ ///
+ /// # Panics
+ ///
+ /// This panics if the vector length isn't a multiple of the number of columns.
+ #[must_use]
+ #[inline]
+ pub fn from_vec(vec: Vec<T>, cols: usize) -> Self {
+ Self::from_vec_with_order(vec, cols, Order::default())
+ }
+
+ /// Same as [`from_vec`](Self::from_vec) but with a specific [`Order`].
+ ///
+ /// # Panics
+ ///
+ /// This panics if the vector length isn't a multiple of the number of columns.
+ #[must_use]
+ pub fn from_vec_with_order(vec: Vec<T>, cols: usize, order: Order) -> Self {
+ let rows = vec.len().checked_div(cols).unwrap_or(0);
+ assert_eq!(
+ rows * cols,
+ vec.len(),
+ "Vector length {:?} should be a multiple of cols = {:?}",
+ vec.len(),
+ cols
+ );
+ if rows == 0 || cols == 0 {
+ Self {
+ data: vec,
+ rows: 0,
+ cols: 0,
+ order,
+ }
+ } else {
+ Self {
+ data: vec,
+ rows,
+ cols,
+ order,
+ }
+ }
+ }
+
+ /// Returns the index of the coordinates in the internal vector.
+ #[inline]
+ #[must_use]
+ const fn get_index(&self, row: usize, col: usize) -> usize {
+ match self.order {
+ Order::RowMajor => row * self.cols + col,
+ Order::ColumnMajor => col * self.rows + row,
+ }
+ }
+
+ /// Returns a reference to an element, without performing bound checks.
+ /// Generally not recommended, use with caution!
+ ///
+ /// # Safety
+ ///
+ /// Calling this method with an out-of-bounds index is undefined behavior even if the resulting reference is not used.
+ #[inline]
+ #[must_use]
+ pub unsafe fn get_unchecked(&self, row: impl Into<usize>, col: impl Into<usize>) -> &T {
+ let index = self.get_index(row.into(), col.into());
+ self.data.get_unchecked(index)
+ }
+
+ /// Returns a mutable reference to an element, without performing bound checks.
+ /// Generally not recommended, use with caution!
+ ///
+ /// # Safety
+ ///
+ /// Calling this method with an out-of-bounds index is undefined behavior even if the resulting reference is not used.
+ #[inline]
+ #[must_use]
+ pub unsafe fn get_unchecked_mut(
+ &mut self,
+ row: impl Into<usize>,
+ col: impl Into<usize>,
+ ) -> &mut T {
+ let index = self.get_index(row.into(), col.into());
+ self.data.get_unchecked_mut(index)
+ }
+
+ /// Access a certain element in the grid.
+ /// Returns `None` if an element beyond the grid bounds is tried to be accessed.
+ #[must_use]
+ pub fn get(&self, row: impl TryInto<usize>, col: impl TryInto<usize>) -> Option<&T> {
+ let row_usize = row.try_into().ok()?;
+ let col_usize = col.try_into().ok()?;
+ if row_usize < self.rows && col_usize < self.cols {
+ unsafe { Some(self.get_unchecked(row_usize, col_usize)) }
+ } else {
+ None
+ }
+ }
+
+ /// Mutable access to a certain element in the grid.
+ /// Returns `None` if an element beyond the grid bounds is tried to be accessed.
+ #[must_use]
+ pub fn get_mut(
+ &mut self,
+ row: impl TryInto<usize>,
+ col: impl TryInto<usize>,
+ ) -> Option<&mut T> {
+ let row_usize = row.try_into().ok()?;
+ let col_usize = col.try_into().ok()?;
+ if row_usize < self.rows && col_usize < self.cols {
+ unsafe { Some(self.get_unchecked_mut(row_usize, col_usize)) }
+ } else {
+ None
+ }
+ }
+
+ /// Returns the size of the grid as a two element tuple.
+ /// First element are the number of rows and the second the columns.
+ #[must_use]
+ pub const fn size(&self) -> (usize, usize) {
+ (self.rows, self.cols)
+ }
+
+ /// Returns the number of rows of the grid.
+ #[must_use]
+ pub const fn rows(&self) -> usize {
+ self.rows
+ }
+
+ /// Returns the number of columns of the grid.
+ #[must_use]
+ pub const fn cols(&self) -> usize {
+ self.cols
+ }
+
+ /// Returns the internal memory layout of the grid.
+ #[must_use]
+ pub const fn order(&self) -> Order {
+ self.order
+ }
+
+ /// Returns `true` if the grid contains no elements.
+ /// For example:
+ /// ```
+ /// use grid::*;
+ /// let grid : Grid<u8> = grid![];
+ /// assert!(grid.is_empty());
+ /// ```
+ #[must_use]
+ pub fn is_empty(&self) -> bool {
+ self.data.is_empty()
+ }
+
+ /// Clears the grid.
+ ///
+ /// This doesn't change the grid order.
+ pub fn clear(&mut self) {
+ self.rows = 0;
+ self.cols = 0;
+ self.data.clear();
+ }
+
+ /// Returns an iterator over the whole grid, starting from the first row and column.
+ ///
+ /// The iteration order is dependant on the internal memory layout.
+ /// If you need a specific order, see [`iter_rows`](Grid::iter_rows) or
+ /// [`iter_cols`](Grid::iter_cols).
+ ///
+ /// ```
+ /// use grid::*;
+ /// let grid: Grid<u8> = grid![[1,2][3,4]];
+ /// let mut iter = grid.iter();
+ /// assert_eq!(iter.next(), Some(&1));
+ /// assert_eq!(iter.next(), Some(&2));
+ /// assert_eq!(iter.next(), Some(&3));
+ /// assert_eq!(iter.next(), Some(&4));
+ /// assert_eq!(iter.next(), None);
+ /// ```
+ pub fn iter(&self) -> Iter<T> {
+ self.data.iter()
+ }
+
+ /// Returns an mutable iterator over the whole grid that allows modifying each value.
+ ///
+ /// The iteration order is dependant on the internal memory layout.
+ ///
+ /// ```
+ /// use grid::*;
+ /// let mut grid: Grid<u8> = grid![[1,2][3,4]];
+ /// let mut iter = grid.iter_mut();
+ /// let next = iter.next();
+ /// assert_eq!(next, Some(&mut 1));
+ /// *next.unwrap() = 10;
+ /// ```
+ pub fn iter_mut(&mut self) -> IterMut<T> {
+ self.data.iter_mut()
+ }
+
+ /// Returns an iterator over a column.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use grid::*;
+ /// let grid: Grid<u8> = grid![[1, 2, 3][3, 4, 5]];
+ /// let mut col_iter = grid.iter_col(1);
+ /// assert_eq!(col_iter.next(), Some(&2));
+ /// assert_eq!(col_iter.next(), Some(&4));
+ /// assert_eq!(col_iter.next(), None);
+ /// ```
+ ///
+ /// # Performance
+ ///
+ /// This method will be significantly slower if the grid uses a row-major memory layout,
+ /// which is the default.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the col index is out of bounds.
+ pub fn iter_col(&self, col: usize) -> StepBy<Iter<T>> {
+ assert!(
+ col < self.cols,
+ "out of bounds. Column must be less than {:?}, but is {:?}",
+ self.cols,
+ col
+ );
+ match self.order {
+ Order::RowMajor => self.data[col..].iter().step_by(self.cols),
+ Order::ColumnMajor => {
+ let start = col * self.rows;
+ self.data[start..(start + self.rows)].iter().step_by(1)
+ }
+ }
+ }
+
+ /// Returns a mutable iterator over a column.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use grid::*;
+ /// let mut grid: Grid<u8> = grid![[1, 2, 3][3, 4, 5]];
+ /// let mut col_iter = grid.iter_col_mut(1);
+ /// let next = col_iter.next();
+ /// assert_eq!(next, Some(&mut 2));
+ /// *next.unwrap() = 10;
+ /// assert_eq!(grid[(0, 1)], 10);
+ /// ```
+ ///
+ /// # Performance
+ ///
+ /// This method will be significantly slower if the grid uses a row-major memory layout,
+ /// which is the default.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the col index is out of bounds.
+ pub fn iter_col_mut(&mut self, col: usize) -> StepBy<IterMut<T>> {
+ assert!(
+ col < self.cols,
+ "out of bounds. Column must be less than {:?}, but is {:?}",
+ self.cols,
+ col
+ );
+ match self.order {
+ Order::RowMajor => self.data[col..].iter_mut().step_by(self.cols),
+ Order::ColumnMajor => {
+ let start = col * self.rows;
+ self.data[start..(start + self.rows)].iter_mut().step_by(1)
+ }
+ }
+ }
+
+ /// Returns an iterator over a row.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use grid::*;
+ /// let grid: Grid<u8> = grid![[1, 2, 3][3, 4, 5]];
+ /// let mut col_iter = grid.iter_row(1);
+ /// assert_eq!(col_iter.next(), Some(&3));
+ /// assert_eq!(col_iter.next(), Some(&4));
+ /// assert_eq!(col_iter.next(), Some(&5));
+ /// assert_eq!(col_iter.next(), None);
+ /// ```
+ ///
+ /// # Performance
+ ///
+ /// This method will be significantly slower if the grid uses a column-major memory layout.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the row index is out of bounds.
+ pub fn iter_row(&self, row: usize) -> StepBy<Iter<T>> {
+ assert!(
+ row < self.rows,
+ "out of bounds. Row must be less than {:?}, but is {:?}",
+ self.rows,
+ row
+ );
+ match self.order {
+ Order::RowMajor => {
+ let start = row * self.cols;
+ self.data[start..(start + self.cols)].iter().step_by(1)
+ }
+ Order::ColumnMajor => self.data[row..].iter().step_by(self.rows),
+ }
+ }
+
+ /// Returns a mutable iterator over a row.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use grid::*;
+ /// let mut grid: Grid<u8> = grid![[1, 2, 3][3, 4, 5]];
+ /// let mut col_iter = grid.iter_row_mut(1);
+ /// let next = col_iter.next();
+ /// *next.unwrap() = 10;
+ /// assert_eq!(grid[(1, 0)], 10);
+ /// ```
+ ///
+ /// # Performance
+ ///
+ /// This method will be significantly slower if the grid uses a column-major memory layout.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the row index is out of bounds.
+ pub fn iter_row_mut(&mut self, row: usize) -> StepBy<IterMut<T>> {
+ assert!(
+ row < self.rows,
+ "out of bounds. Row must be less than {:?}, but is {:?}",
+ self.rows,
+ row
+ );
+ match self.order {
+ Order::RowMajor => {
+ let start = row * self.cols;
+ self.data[start..(start + self.cols)].iter_mut().step_by(1)
+ }
+ Order::ColumnMajor => self.data[row..].iter_mut().step_by(self.rows),
+ }
+ }
+
+ /// Traverse the grid with row and column indexes.
+ ///
+ /// The iteration order is dependent on the internal memory layout,
+ /// but the indexes will be accurate either way.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use grid::*;
+ /// let grid: Grid<u8> = grid![[1,2][3,4]];
+ /// let mut iter = grid.indexed_iter();
+ /// assert_eq!(iter.next(), Some(((0, 0), &1)));
+ /// ```
+ ///
+ /// Or simply unpack in a `for` loop:
+ ///
+ /// ```
+ /// use grid::*;
+ /// let grid: Grid<u8> = grid![[1,2][3,4]];
+ /// for ((row, col), i) in grid.indexed_iter() {
+ /// println!("value at row {row} and column {col} is: {i}");
+ /// }
+ /// ```
+ pub fn indexed_iter(&self) -> impl Iterator<Item = ((usize, usize), &T)> {
+ self.data.iter().enumerate().map(move |(idx, i)| {
+ let position = match self.order {
+ Order::RowMajor => (idx / self.cols, idx % self.cols),
+ Order::ColumnMajor => (idx % self.rows, idx / self.rows),
+ };
+ (position, i)
+ })
+ }
+
+ /// Traverse the grid with row and column indexes,
+ /// and mutable access to each element.
+ ///
+ /// The iteration order is dependent on the internal memory layout,
+ /// but the indexes will be accurate either way.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use grid::*;
+ /// let mut grid: Grid<u8> = grid![[1,2][3,4]];
+ /// let mut iter = grid.indexed_iter_mut();
+ /// assert_eq!(iter.next(), Some(((0, 0), &mut 1)));
+ /// ```
+ ///
+ /// Or simply unpack in a `for` loop:
+ ///
+ /// ```
+ /// use grid::*;
+ /// let mut grid: Grid<u8> = grid![[1,2][3,4]];
+ /// for ((row, col), i) in grid.indexed_iter_mut() {
+ /// *i += 1;
+ /// println!("value at row {row} and column {col} is: {i}");
+ /// }
+ ///
+ /// assert_eq!(grid[(0, 0)], 2);
+ /// assert_eq!(grid[(0, 1)], 3);
+ /// assert_eq!(grid[(1, 0)], 4);
+ /// assert_eq!(grid[(1, 1)], 5);
+ /// ```
+ pub fn indexed_iter_mut(&mut self) -> impl Iterator<Item = ((usize, usize), &mut T)> {
+ let order = self.order;
+ let cols = self.cols;
+ let rows = self.rows;
+
+ self.data.iter_mut().enumerate().map(move |(idx, i)| {
+ let position = match order {
+ Order::RowMajor => (idx / cols, idx % cols),
+ Order::ColumnMajor => (idx % rows, idx / rows),
+ };
+ (position, i)
+ })
+ }
+
+ /// Add a new row to the grid.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use grid::*;
+ /// let mut grid: Grid<u8> = grid![[1, 2, 3][3, 4, 5]];
+ /// let row = vec![6,7,8];
+ /// grid.push_row(row);
+ /// assert_eq!(grid.rows(), 3);
+ /// assert_eq!(grid[(2, 0)], 6);
+ /// assert_eq!(grid[(2, 1)], 7);
+ /// assert_eq!(grid[(2, 2)], 8);
+ /// ```
+ ///
+ /// Can also be used to init an empty grid:
+ ///
+ /// ```
+ /// use grid::*;
+ /// let mut grid: Grid<u8> = grid![];
+ /// let row = vec![1,2,3];
+ /// grid.push_row(row);
+ /// assert_eq!(grid.size(), (1, 3));
+ /// ```
+ ///
+ /// # Performance
+ ///
+ /// This method will be significantly slower if the grid uses a column-major memory layout.
+ ///
+ /// # Panics
+ ///
+ /// Panics if:
+ /// - the grid is not empty and `row.len() != grid.cols()`
+ /// - `row.len() == 0`
+ pub fn push_row(&mut self, row: Vec<T>) {
+ assert_ne!(row.len(), 0);
+ assert!(
+ !(self.rows > 0 && row.len() != self.cols),
+ "pushed row does not match. Length must be {:?}, but was {:?}.",
+ self.cols,
+ row.len()
+ );
+ self.data.extend(row);
+ if self.order == Order::ColumnMajor {
+ for i in (1..self.cols).rev() {
+ let col_idx = i * self.rows;
+ self.data[col_idx..col_idx + self.rows + i].rotate_right(i);
+ }
+ }
+ self.rows += 1;
+ if self.cols == 0 {
+ self.cols = self.data.len();
+ }
+ }
+
+ /// Add a new column to the grid.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use grid::*;
+ /// let mut grid: Grid<u8> = grid![[1, 2, 3][3, 4, 5]];
+ /// let col = vec![4,6];
+ /// grid.push_col(col);
+ /// assert_eq!(grid.cols(), 4);
+ /// assert_eq!(grid[(0, 3)], 4);
+ /// assert_eq!(grid[(1, 3)], 6);
+ /// ```
+ ///
+ /// Can also be used to init an empty grid:
+ ///
+ /// ```
+ /// use grid::*;
+ /// let mut grid: Grid<u8> = grid![];
+ /// let col = vec![1,2,3];
+ /// grid.push_col(col);
+ /// assert_eq!(grid.size(), (3, 1));
+ /// ```
+ ///
+ /// # Performance
+ ///
+ /// This method will be significantly slower if the grid uses a row-major memory layout,
+ /// which is the default.
+ ///
+ /// # Panics
+ ///
+ /// Panics if:
+ /// - the grid is not empty and `col.len() != grid.rows()`
+ /// - `col.len() == 0`
+ pub fn push_col(&mut self, col: Vec<T>) {
+ assert_ne!(col.len(), 0);
+ assert!(
+ !(self.cols > 0 && col.len() != self.rows),
+ "pushed column does not match. Length must be {:?}, but was {:?}.",
+ self.rows,
+ col.len()
+ );
+ self.data.extend(col);
+ if self.order == Order::RowMajor {
+ for i in (1..self.rows).rev() {
+ let row_idx = i * self.cols;
+ self.data[row_idx..row_idx + self.cols + i].rotate_right(i);
+ }
+ }
+ self.cols += 1;
+ if self.rows == 0 {
+ self.rows = self.data.len();
+ }
+ }
+
+ /// Removes the last row from a grid and returns it, or None if it is empty.
+ ///
+ /// # Examples
+ /// ```
+ /// use grid::*;
+ /// let mut grid = grid![[1,2,3][4,5,6]];
+ /// assert_eq![grid.pop_row(), Some(vec![4,5,6])];
+ /// assert_eq![grid.pop_row(), Some(vec![1,2,3])];
+ /// assert_eq![grid.pop_row(), None];
+ /// ```
+ ///
+ /// # Performance
+ ///
+ /// This method will be significantly slower if the grid uses a column-major memory layout.
+ pub fn pop_row(&mut self) -> Option<Vec<T>> {
+ if self.rows == 0 {
+ return None;
+ }
+ if self.order == Order::ColumnMajor {
+ for i in 1..self.cols {
+ let col_idx = i * (self.rows - 1);
+ self.data[col_idx..col_idx + self.rows + i - 1].rotate_left(i);
+ }
+ }
+ let row = self.data.split_off(self.data.len() - self.cols);
+ self.rows -= 1;
+ if self.rows == 0 {
+ self.cols = 0;
+ }
+ Some(row)
+ }
+
+ /// Remove a Row at the index and return a vector of it.
+ ///
+ /// # Examples
+ /// ```
+ /// use grid::*;
+ /// let mut grid = grid![[1,2][3,4][5,6]];
+ /// assert_eq![grid.remove_row(1), Some(vec![3,4])];
+ /// assert_eq![grid.remove_row(0), Some(vec![1,2])];
+ /// assert_eq![grid.remove_row(0), Some(vec![5,6])];
+ /// assert_eq![grid.remove_row(0), None];
+ /// ```
+ ///
+ /// # Performance
+ ///
+ /// This method will be significantly slower if the grid uses a column-major memory layout.
+ pub fn remove_row(&mut self, row_index: usize) -> Option<Vec<T>> {
+ if self.cols == 0 || self.rows == 0 || row_index >= self.rows {
+ return None;
+ }
+ let row = match self.order {
+ Order::RowMajor => self
+ .data
+ .drain((row_index * self.cols)..((row_index + 1) * self.cols))
+ .collect(),
+ Order::ColumnMajor => {
+ for i in 0..self.cols {
+ let col_idx = row_index + i * (self.rows - 1);
+ let end = cmp::min(col_idx + self.rows + i, self.data.len());
+ self.data[col_idx..end].rotate_left(i + 1);
+ }
+ self.data.split_off(self.data.len() - self.cols)
+ }
+ };
+ self.rows -= 1;
+ if self.rows == 0 {
+ self.cols = 0;
+ }
+ Some(row)
+ }
+
+ /// Removes the last column from a grid and returns it, or None if it is empty.
+ ///
+ /// Note that this operation is much slower than the `pop_row()` because the memory layout
+ /// of `Grid` is row-major and removing a column requires a lot of move operations.
+ ///
+ /// # Examples
+ /// ```
+ /// use grid::*;
+ /// let mut grid = grid![[1,2,3][4,5,6]];
+ /// assert_eq![grid.pop_col(), Some(vec![3,6])];
+ /// assert_eq![grid.pop_col(), Some(vec![2,5])];
+ /// assert_eq![grid.pop_col(), Some(vec![1,4])];
+ /// assert_eq![grid.pop_col(), None];
+ /// ```
+ ///
+ /// # Performance
+ ///
+ /// This method will be significantly slower if the grid uses a row-major memory layout,
+ /// which is the default.
+ pub fn pop_col(&mut self) -> Option<Vec<T>> {
+ if self.cols == 0 {
+ return None;
+ }
+ if self.order == Order::RowMajor {
+ for i in 1..self.rows {
+ let row_idx = i * (self.cols - 1);
+ self.data[row_idx..row_idx + self.cols + i - 1].rotate_left(i);
+ }
+ }
+ let col = self.data.split_off(self.data.len() - self.rows);
+ self.cols -= 1;
+ if self.cols == 0 {
+ self.rows = 0;
+ }
+ Some(col)
+ }
+
+ /// Remove a column at the index and return a vector of it.
+ ///
+ /// # Examples
+ /// ```
+ /// use grid::*;
+ /// let mut grid = grid![[1,2,3,4][5,6,7,8][9,10,11,12][13,14,15,16]];
+ /// assert_eq![grid.remove_col(3), Some(vec![4,8,12,16])];
+ /// assert_eq![grid.remove_col(0), Some(vec![1,5,9,13])];
+ /// assert_eq![grid.remove_col(1), Some(vec![3,7,11,15])];
+ /// assert_eq![grid.remove_col(0), Some(vec![2,6,10,14])];
+ /// assert_eq![grid.remove_col(0), None];
+ /// ```
+ ///
+ /// # Performance
+ ///
+ /// This method will be significantly slower if the grid uses a row-major memory layout,
+ /// which is the default.
+ pub fn remove_col(&mut self, col_index: usize) -> Option<Vec<T>> {
+ if self.cols == 0 || self.rows == 0 || col_index >= self.cols {
+ return None;
+ }
+ let col = match self.order {
+ Order::RowMajor => {
+ for i in 0..self.rows {
+ let row_idx = col_index + i * (self.cols - 1);
+ let end = cmp::min(row_idx + self.cols + i, self.data.len());
+ self.data[row_idx..end].rotate_left(i + 1);
+ }
+ self.data.split_off(self.data.len() - self.rows)
+ }
+ Order::ColumnMajor => self
+ .data
+ .drain((col_index * self.rows)..((col_index + 1) * self.rows))
+ .collect(),
+ };
+ self.cols -= 1;
+ if self.cols == 0 {
+ self.rows = 0;
+ }
+ Some(col)
+ }
+
+ /// Insert a new row at the index and shifts all rows after down.
+ ///
+ /// # Examples
+ /// ```
+ /// use grid::*;
+ /// let mut grid = grid![[1,2,3][4,5,6]];
+ /// grid.insert_row(1, vec![7,8,9]);
+ /// assert_eq!(grid, grid![[1,2,3][7,8,9][4,5,6]]);
+ /// ```
+ ///
+ /// # Performance
+ ///
+ /// This method will be significantly slower if the grid uses a column-major memory layout.
+ ///
+ /// # Panics
+ ///
+ /// Panics if:
+ /// - the grid is not empty and `row.len() != grid.cols()`.
+ /// - the index is greater than the number of rows
+ pub fn insert_row(&mut self, index: usize, row: Vec<T>) {
+ let input_len = row.len();
+ assert!(
+ !(self.cols > 0 && input_len != self.cols),
+ "Inserted row must be of length {}, but was {}.",
+ self.cols,
+ row.len()
+ );
+ assert!(
+ index <= self.rows,
+ "Out of range. Index was {}, but must be less or equal to {}.",
+ index,
+ self.rows
+ );
+ match self.order {
+ Order::RowMajor => {
+ let data_idx = index * input_len;
+ self.data.splice(data_idx..data_idx, row);
+ }
+ Order::ColumnMajor => {
+ for (col_iter, row_val) in row.into_iter().enumerate() {
+ let data_idx = col_iter * self.rows + index + col_iter;
+ self.data.insert(data_idx, row_val);
+ }
+ }
+ }
+ self.cols = input_len;
+ self.rows += 1;
+ }
+
+ /// Insert a new column at the index.
+ ///
+ /// Important! Insertion of columns is a lot slower than the lines insertion.
+ /// This is because of the memory layout of the grid data structure.
+ ///
+ /// # Examples
+ /// ```
+ /// use grid::*;
+ /// let mut grid = grid![[1,2,3][4,5,6]];
+ /// grid.insert_col(1, vec![9,9]);
+ /// assert_eq!(grid, grid![[1,9,2,3][4,9,5,6]])
+ /// ```
+ ///
+ /// # Performance
+ ///
+ /// This method will be significantly slower if the grid uses a row-major memory layout,
+ /// which is the default.
+ ///
+ /// # Panics
+ ///
+ /// Panics if:
+ /// - the grid is not empty and `col.len() != grid.rows()`.
+ /// - the index is greater than the number of columns
+ pub fn insert_col(&mut self, index: usize, col: Vec<T>) {
+ let input_len = col.len();
+ assert!(
+ !(self.rows > 0 && input_len != self.rows),
+ "Inserted col must be of length {}, but was {}.",
+ self.rows,
+ col.len()
+ );
+ assert!(
+ index <= self.cols,
+ "Out of range. Index was {}, but must be less or equal to {}.",
+ index,
+ self.cols
+ );
+ match self.order {
+ Order::RowMajor => {
+ for (row_iter, col_val) in col.into_iter().enumerate() {
+ let data_idx = row_iter * self.cols + index + row_iter;
+ self.data.insert(data_idx, col_val);
+ }
+ }
+ Order::ColumnMajor => {
+ let data_idx = index * input_len;
+ self.data.splice(data_idx..data_idx, col);
+ }
+ }
+ self.rows = input_len;
+ self.cols += 1;
+ }
+
+ /// Returns a reference to the internal data structure of the grid.
+ ///
+ /// The order of the elements depends on the internal memory layout, which is
+ /// row-major by default.
+ ///
+ /// # Examples
+ /// ```
+ /// use grid::*;
+ /// let grid = grid![[1,2,3][4,5,6]];
+ /// let flat = grid.flatten();
+ /// assert_eq!(flat, &vec![1,2,3,4,5,6]);
+ /// ```
+ #[must_use]
+ pub const fn flatten(&self) -> &Vec<T> {
+ &self.data
+ }
+
+ /// Converts self into a vector without clones or allocation.
+ ///
+ /// The order of the elements depends on the internal memory layout, which is
+ /// row-major by default.
+ #[must_use]
+ pub fn into_vec(self) -> Vec<T> {
+ self.data
+ }
+
+ /// Transpose the grid so that columns become rows in new grid.
+ ///
+ /// This method changes the internal memory layout.
+ pub fn transpose(&mut self) {
+ self.order = self.order.counterpart();
+ core::mem::swap(&mut self.rows, &mut self.cols);
+ }
+
+ /// Flip (or mirrors) the columns.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use grid::*;
+ /// let mut grid = grid![[1,2,3][4,5,6]];
+ /// grid.flip_cols();
+ /// assert_eq!(grid, grid![[3,2,1][6,5,4]])
+ /// ```
+ ///
+ /// # Performance
+ ///
+ /// This method will be significantly slower if the grid uses a column-major memory layout.
+ pub fn flip_cols(&mut self) {
+ match self.order {
+ Order::RowMajor => {
+ for row in 0..self.rows {
+ let idx = row * self.cols;
+ self.data[idx..idx + self.cols].reverse();
+ }
+ }
+ Order::ColumnMajor => {
+ for col in 0..self.cols / 2 {
+ for row in 0..self.rows {
+ let cell1 = self.get_index(row, col);
+ let cell2 = self.get_index(row, self.cols - col - 1);
+ self.data.swap(cell1, cell2);
+ }
+ }
+ }
+ }
+ }
+
+ /// Flip (or mirrors) the rows.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use grid::*;
+ /// let mut grid = grid![[1,2,3][4,5,6]];
+ /// grid.flip_rows();
+ /// assert_eq!(grid, grid![[4,5,6][1,2,3]])
+ /// ```
+ ///
+ /// # Performance
+ ///
+ /// This method will be significantly slower if the grid uses a row-major memory layout,
+ /// which is the default.
+ pub fn flip_rows(&mut self) {
+ match self.order {
+ Order::RowMajor => {
+ for row in 0..self.rows / 2 {
+ for col in 0..self.cols {
+ let cell1 = self.get_index(row, col);
+ let cell2 = self.get_index(self.rows - row - 1, col);
+ self.data.swap(cell1, cell2);
+ }
+ }
+ }
+ Order::ColumnMajor => {
+ for col in 0..self.cols {
+ let idx = col * self.rows;
+ self.data[idx..idx + self.rows].reverse();
+ }
+ }
+ }
+ }
+
+ /// Rotate the grid 90° counter-clockwise.
+ ///
+ /// This method changes the internal memory layout.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use grid::*;
+ /// let mut grid = grid![[1,2][3,4]];
+ /// grid.rotate_left();
+ /// assert_eq!(grid, grid![[2,4][1,3]]);
+ /// ```
+ ///
+ /// # Performance
+ ///
+ /// This method will be significantly slower if the grid initialy uses a column-major memory layout,
+ /// which is the default.
+ pub fn rotate_left(&mut self) {
+ self.transpose();
+ self.flip_rows();
+ }
+
+ /// Rotate the grid 90° clockwise.
+ ///
+ /// This method changes the internal memory layout.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use grid::*;
+ /// let mut grid = grid![[1,2][3,4]];
+ /// grid.rotate_right();
+ /// assert_eq!(grid, grid![[3,1][4,2]]);
+ /// ```
+ ///
+ /// # Performance
+ ///
+ /// This method will be significantly slower if the grid initialy uses a row-major memory layout,
+ /// which is the default.
+ pub fn rotate_right(&mut self) {
+ self.transpose();
+ self.flip_cols();
+ }
+
+ /// Rotate the grid 180°.
+ ///
+ /// This method **doesn't** change the internal memory layout.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use grid::*;
+ /// let mut grid = grid![[1,2,3][4,5,6]];
+ /// grid.rotate_half();
+ /// assert_eq!(grid, grid![[6,5,4][3,2,1]]);
+ /// ```
+ ///
+ /// # Performance
+ ///
+ /// The performances of this method is not affected by the internal memory layout.
+ pub fn rotate_half(&mut self) {
+ self.data.reverse();
+ }
+
+ /// Fills the grid with elements by cloning `value`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use grid::*;
+ /// let mut grid = grid![[1,2,3][4,5,6]];
+ /// grid.fill(7);
+ /// assert_eq!(grid, grid![[7,7,7][7,7,7]]);
+ /// ```
+ pub fn fill(&mut self, value: T)
+ where
+ T: Clone,
+ {
+ self.data.fill(value);
+ }
+
+ /// Fills the grid with elements returned by calling a closure repeatedly.
+ ///
+ /// This method uses a closure to create new values. If you'd rather
+ /// [`Clone`] a given value, use [`fill`]. If you want to use the [`Default`]
+ /// trait to generate values, you can pass [`Default::default`] as the
+ /// argument.
+ ///
+ /// [`fill`]: Grid::fill
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use grid::*;
+ /// let mut grid = grid![[1,2,3][4,5,6]];
+ /// grid.fill_with(Default::default);
+ /// assert_eq!(grid, grid![[0,0,0][0,0,0]]);
+ /// ```
+ pub fn fill_with<F>(&mut self, f: F)
+ where
+ F: FnMut() -> T,
+ {
+ self.data.fill_with(f);
+ }
+
+ /// Returns a new grid with the same dimensions, but with each element transformed by the closure.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use grid::*;
+ /// let grid = grid![[1,2][3,4]];
+ /// let new_grid = grid.map(|x| x * 2);
+ /// assert_eq!(new_grid, grid![[2,4][6,8]]);
+ ///
+ /// let grid = grid![[1,2][3,4]];
+ /// let new_grid = grid.map(|x| x > 2);
+ /// assert_eq!(new_grid, grid![[false,false][true,true]]);
+ /// ```
+ pub fn map<U, F>(self, f: F) -> Grid<U>
+ where
+ F: FnMut(T) -> U,
+ {
+ Grid {
+ data: self.data.into_iter().map(f).collect(),
+ cols: self.cols,
+ rows: self.rows,
+ order: self.order,
+ }
+ }
+
+ /// Returns a new grid with the same dimensions, but with each element
+ /// transformed by the closure. Does not consume the grid.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use grid::*;
+ /// let grid = grid![[1,2][3,4]];
+ /// let new_grid = grid.map(|x| x * 2);
+ /// assert_eq!(new_grid, grid![[2,4][6,8]]);
+ ///
+ /// let grid = grid![[1,2][3,4]];
+ /// let new_grid = grid.map(|x| x > 2);
+ /// assert_eq!(new_grid, grid![[false,false][true,true]]);
+ /// ```
+ #[must_use]
+ pub fn map_ref<U, F>(&self, f: F) -> Grid<U>
+ where
+ F: Fn(&T) -> U,
+ {
+ Grid {
+ data: self.data.iter().map(f).collect(),
+ cols: self.cols,
+ rows: self.rows,
+ order: self.order,
+ }
+ }
+
+ /// Iterate over the rows of the grid. Each time an iterator over a single
+ /// row is returned.
+ ///
+ /// An item in this iterator is equal to a call to `Grid.iter_row(row_index)`
+ /// of the corresponding row.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use grid::*;
+ /// let mut grid = grid![[1,2,3][4,5,6]];
+ /// let sum_by_row: Vec<u8> = grid.iter_rows().map(|row| row.sum()).collect();
+ /// assert_eq!(sum_by_row, vec![1+2+3, 4+5+6])
+ /// ```
+ #[must_use]
+ pub const fn iter_rows(&self) -> GridRowIter<'_, T> {
+ GridRowIter {
+ grid: self,
+ row_start_index: 0,
+ row_end_index: self.rows,
+ }
+ }
+
+ /// Iterate over the columns of the grid. Each time an iterator over a single
+ /// column is returned.
+ ///
+ /// An item in this iterator is equal to a call to `Grid.iter_col(col_index)`
+ /// of the corresponding column.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use grid::*;
+ /// let mut grid = grid![[1,2,3][4,5,6]];
+ /// let sum_by_col: Vec<u8> = grid.iter_cols().map(|col| col.sum()).collect();
+ /// assert_eq!(sum_by_col, vec![1+4, 2+5, 3+6])
+ /// ```
+ #[must_use]
+ pub const fn iter_cols(&self) -> GridColIter<'_, T> {
+ GridColIter {
+ grid: self,
+ col_start_index: 0,
+ col_end_index: self.cols,
+ }
+ }
+
+ /// Swaps two elements in the Grid.
+ /// Similar to `Vec::swap()`.
+ ///
+ /// # Panics
+ ///
+ /// Panics if either index is out of bounds.
+ pub fn swap(&mut self, (row_a, col_a): (usize, usize), (row_b, col_b): (usize, usize)) {
+ assert!(
+ !(row_a >= self.rows || col_a >= self.cols),
+ "grid index out of bounds: ({row_a},{col_a}) out of ({},{})",
+ self.rows,
+ self.cols
+ );
+ assert!(
+ !(row_b >= self.rows || col_b >= self.cols),
+ "grid index out of bounds: ({row_b},{col_b}) out of ({},{})",
+ self.rows,
+ self.cols
+ );
+
+ let a_idx = self.get_index(row_a, col_a);
+ let b_idx = self.get_index(row_b, col_b);
+
+ self.data.swap(a_idx, b_idx);
+ }
+}
+
+impl<T> Default for Grid<T> {
+ fn default() -> Self {
+ Self {
+ data: Vec::default(),
+ cols: 0,
+ rows: 0,
+ order: Order::default(),
+ }
+ }
+}
+
+impl<T: Clone> Clone for Grid<T> {
+ fn clone(&self) -> Self {
+ Self {
+ rows: self.rows,
+ cols: self.cols,
+ data: self.data.clone(),
+ order: self.order,
+ }
+ }
+}
+
+impl<T: hash::Hash> hash::Hash for Grid<T> {
+ #[inline]
+ fn hash<H: hash::Hasher>(&self, state: &mut H) {
+ self.rows.hash(state);
+ self.cols.hash(state);
+ self.order.hash(state);
+ self.data.hash(state);
+ }
+}
+
+impl<T> Index<(usize, usize)> for Grid<T> {
+ type Output = T;
+
+ #[inline]
+ fn index(&self, (row, col): (usize, usize)) -> &T {
+ assert!(
+ !(row >= self.rows || col >= self.cols),
+ "grid index out of bounds: ({row},{col}) out of ({},{})",
+ self.rows,
+ self.cols
+ );
+ let index = self.get_index(row, col);
+ &self.data[index]
+ }
+}
+
+impl<T> IndexMut<(usize, usize)> for Grid<T> {
+ #[inline]
+ fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut T {
+ assert!(
+ !(row >= self.rows || col >= self.cols),
+ "grid index out of bounds: ({row},{col}) out of ({},{})",
+ self.rows,
+ self.cols
+ );
+ let index = self.get_index(row, col);
+ &mut self.data[index]
+ }
+}
+
+impl<'a, T> IntoIterator for &'a Grid<T> {
+ type IntoIter = core::slice::Iter<'a, T>;
+ type Item = &'a T;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter()
+ }
+}
+
+impl<'a, T> IntoIterator for &'a mut Grid<T> {
+ type IntoIter = core::slice::IterMut<'a, T>;
+ type Item = &'a mut T;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter_mut()
+ }
+}
+
+impl<T: fmt::Debug> fmt::Debug for Grid<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "[")?;
+ if self.cols > 0 {
+ if f.alternate() {
+ writeln!(f)?;
+ /*
+ WARNING
+
+ Compound types becoming enormous as the entire `fmt::Debug` width is applied to each item individually.
+ For tuples and structs define padding and precision arguments manually to improve readability.
+ */
+ let width = f.width().unwrap_or_else(|| {
+ // Conditionally calculate the longest item by default.
+ self.data
+ .iter()
+ .map(|i| format!("{i:?}").len())
+ .max()
+ .unwrap()
+ });
+ let precision = f.precision().unwrap_or(2);
+ for mut row in self.iter_rows().map(Iterator::peekable) {
+ write!(f, " [")?;
+ while let Some(item) = row.next() {
+ write!(f, " {item:width$.precision$?}")?;
+ if row.peek().is_some() {
+ write!(f, ",")?;
+ }
+ }
+ writeln!(f, "]")?;
+ }
+ } else {
+ for row in self.iter_rows() {
+ f.debug_list().entries(row).finish()?;
+ }
+ }
+ }
+ write!(f, "]")
+ }
+}
+
+impl<T: PartialEq> PartialEq for Grid<T> {
+ fn eq(&self, other: &Self) -> bool {
+ if self.rows != other.rows || self.cols != other.cols {
+ return false;
+ }
+ if self.order == other.order {
+ return self.data == other.data;
+ }
+ for (self_row, other_row) in core::iter::zip(self.iter_rows(), other.iter_rows()) {
+ if self_row.ne(other_row) {
+ return false;
+ }
+ }
+ true
+ }
+}
+
+impl<T: Eq> Eq for Grid<T> {}
+
+impl<T> From<Vec<Vec<T>>> for Grid<T> {
+ #[allow(clippy::redundant_closure_for_method_calls)]
+ fn from(vec: Vec<Vec<T>>) -> Self {
+ let cols = vec.first().map_or(0, |row| row.len());
+ Self::from_vec_with_order(vec.into_iter().flatten().collect(), cols, Order::default())
+ }
+}
+
+impl<T: Clone> From<&Vec<Vec<T>>> for Grid<T> {
+ #[allow(clippy::redundant_closure_for_method_calls)]
+ fn from(vec: &Vec<Vec<T>>) -> Self {
+ let cols = vec.first().map_or(0, |row| row.len());
+ Self::from_vec_with_order(
+ vec.clone().into_iter().flatten().collect(),
+ cols,
+ Order::default(),
+ )
+ }
+}
+
+impl<T: Clone> From<&Vec<&Vec<T>>> for Grid<T> {
+ #[allow(clippy::redundant_closure_for_method_calls)]
+ fn from(vec: &Vec<&Vec<T>>) -> Self {
+ let cols = vec.first().map_or(0, |row| row.len());
+ Self::from_vec_with_order(
+ vec.clone()
+ .into_iter()
+ .flat_map(|inner| inner.clone())
+ .collect(),
+ cols,
+ Order::default(),
+ )
+ }
+}
+
+impl<T> From<(Vec<T>, usize)> for Grid<T> {
+ fn from(value: (Vec<T>, usize)) -> Self {
+ Self::from_vec_with_order(value.0, value.1, Order::default())
+ }
+}
+
+impl<T: Clone> From<(&Vec<T>, usize)> for Grid<T> {
+ fn from(value: (&Vec<T>, usize)) -> Self {
+ Self::from_vec_with_order(value.0.clone(), value.1, Order::default())
+ }
+}
+
+impl<T: Clone> From<(&Vec<T>, &usize)> for Grid<T> {
+ fn from(value: (&Vec<T>, &usize)) -> Self {
+ Self::from_vec_with_order(value.0.clone(), *value.1, Order::default())
+ }
+}
+
+#[derive(Clone)]
+pub struct GridRowIter<'a, T> {
+ grid: &'a Grid<T>,
+ row_start_index: usize,
+ row_end_index: usize,
+}
+
+#[derive(Clone)]
+pub struct GridColIter<'a, T> {
+ grid: &'a Grid<T>,
+ col_start_index: usize,
+ col_end_index: usize,
+}
+
+impl<'a, T> Iterator for GridRowIter<'a, T> {
+ type Item = StepBy<Iter<'a, T>>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.row_start_index >= self.row_end_index {
+ return None;
+ }
+
+ let row_iter = self.grid.iter_row(self.row_start_index);
+ self.row_start_index += 1;
+ Some(row_iter)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let size = self.row_end_index - self.row_start_index;
+ (size, Some(size))
+ }
+}
+
+impl<T> ExactSizeIterator for GridRowIter<'_, T> {}
+
+impl<T> DoubleEndedIterator for GridRowIter<'_, T> {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ if self.row_start_index >= self.row_end_index {
+ return None;
+ }
+
+ let row_iter = self.grid.iter_row(self.row_end_index - 1);
+ self.row_end_index -= 1;
+ Some(row_iter)
+ }
+}
+
+impl<'a, T> Iterator for GridColIter<'a, T> {
+ type Item = StepBy<Iter<'a, T>>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.col_start_index >= self.col_end_index {
+ return None;
+ }
+
+ let col_iter = self.grid.iter_col(self.col_start_index);
+ self.col_start_index += 1;
+ Some(col_iter)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let size = self.col_end_index - self.col_start_index;
+ (size, Some(size))
+ }
+}
+
+impl<T> ExactSizeIterator for GridColIter<'_, T> {}
+
+impl<T> DoubleEndedIterator for GridColIter<'_, T> {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ if self.col_start_index >= self.col_end_index {
+ return None;
+ }
+
+ let col_iter = self.grid.iter_col(self.col_end_index - 1);
+ self.col_end_index -= 1;
+ Some(col_iter)
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ #[cfg(not(feature = "std"))]
+ use alloc::string::String;
+
+ fn test_grid<T>(grid: &Grid<T>, rows: usize, cols: usize, order: Order, data: &[T])
+ where
+ T: fmt::Debug + PartialEq,
+ {
+ assert_eq!(grid.rows, rows, "number of rows is unexpected");
+ assert_eq!(grid.cols, cols, "number of cols is unexpected");
+ assert_eq!(grid.order, order, "grid order is unexpected");
+ assert_eq!(grid.data, data, "internal data is unexpected");
+ }
+
+ #[test]
+ fn from_1d_vec() {
+ let grid: Grid<u8> = Grid::from((vec![1, 2, 3], 1));
+ test_grid(&grid, 3, 1, Order::RowMajor, &[1, 2, 3]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn from_1d_vec_panic() {
+ let _: Grid<u8> = Grid::from((vec![1, 2, 3], 2));
+ }
+
+ #[test]
+ fn from_1d_vec_reference() {
+ let vec = vec![1, 2, 3];
+ let grid: Grid<u8> = Grid::from((&vec, 1));
+ test_grid(&grid, 3, 1, Order::RowMajor, &[1, 2, 3]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn from_1d_vec_reference_panic() {
+ let vec = vec![1, 2, 3];
+ let _: Grid<u8> = Grid::from((&vec, 2));
+ }
+
+ #[test]
+ fn from_1d_vec_reference_and_reference() {
+ let vec = vec![1, 2, 3];
+ let cols = 1;
+ let grid: Grid<u8> = Grid::from((&vec, &cols));
+ test_grid(&grid, 3, 1, Order::RowMajor, &[1, 2, 3]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn from_1d_vec_reference_and_reference_panic() {
+ let vec = vec![1, 2, 3];
+ let cols = 2;
+ let _: Grid<u8> = Grid::from((&vec, &cols));
+ }
+
+ #[test]
+ fn from_2d_vec() {
+ let grid: Grid<u8> = Grid::from(vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]]);
+ test_grid(&grid, 3, 3, Order::RowMajor, &[1, 2, 3, 4, 5, 6, 7, 8, 9]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn from_2d_vec_panic() {
+ let _: Grid<u8> = Grid::from(vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8]]);
+ }
+
+ #[test]
+ fn from_2d_vec_reference() {
+ let vec = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];
+ let grid: Grid<u8> = Grid::from(&vec);
+ test_grid(&grid, 3, 3, Order::RowMajor, &[1, 2, 3, 4, 5, 6, 7, 8, 9]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn from_2d_vec_reference_panic() {
+ let vec = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8]];
+ let _: Grid<u8> = Grid::from(&vec);
+ }
+
+ #[test]
+ fn from_2d_vec_reference_of_references() {
+ let inner_vec1 = vec![1, 2, 3];
+ let inner_vec2 = vec![4, 5, 6];
+ let inner_vec3 = vec![7, 8, 9];
+ let vec = vec![&inner_vec1, &inner_vec2, &inner_vec3];
+ let grid: Grid<u8> = Grid::from(&vec);
+ test_grid(&grid, 3, 3, Order::RowMajor, &[1, 2, 3, 4, 5, 6, 7, 8, 9]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn from_2d_vec_reference_of_references_panic() {
+ let inner_vec1 = vec![1, 2, 3];
+ let inner_vec2 = vec![4, 5, 6];
+ let inner_vec3 = vec![7, 8];
+ let vec = vec![&inner_vec1, &inner_vec2, &inner_vec3];
+ let _: Grid<u8> = Grid::from(&vec);
+ }
+
+ #[test]
+ fn from_vec_zero_with_cols() {
+ let grid: Grid<u8> = Grid::from_vec(vec![], 1);
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+ }
+
+ #[test]
+ fn from_vec_zero() {
+ let grid: Grid<u8> = Grid::from_vec(vec![], 0);
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn from_vec_panics_1() {
+ let _: Grid<u8> = Grid::from_vec(vec![1, 2, 3], 0);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn from_vec_panics_2() {
+ let _: Grid<u8> = Grid::from_vec(vec![1, 2, 3], 2);
+ }
+
+ #[test]
+ fn from_vec_uses_original_vec() {
+ let capacity = 10_000_000;
+ let vec = Vec::with_capacity(capacity);
+ let grid: Grid<u8> = Grid::from_vec(vec, 0);
+ assert!(grid.into_vec().capacity() >= capacity);
+ }
+
+ #[test]
+ fn from_vec_with_order_zero_with_cols() {
+ let grid: Grid<u8> = Grid::from_vec_with_order(vec![], 1, Order::ColumnMajor);
+ test_grid(&grid, 0, 0, Order::ColumnMajor, &[]);
+ }
+
+ #[test]
+ fn from_vec_with_order_zero() {
+ let grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor);
+ test_grid(&grid, 0, 0, Order::ColumnMajor, &[]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn from_vec_with_order_panics_1() {
+ let _: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3], 0, Order::ColumnMajor);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn from_vec_with_order_panics_2() {
+ let _: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3], 2, Order::ColumnMajor);
+ }
+
+ #[test]
+ fn from_vec_with_order_uses_original_vec() {
+ let capacity = 10_000_000;
+ let vec = Vec::with_capacity(capacity);
+ let grid: Grid<u8> = Grid::from_vec_with_order(vec, 0, Order::ColumnMajor);
+ assert!(grid.into_vec().capacity() >= capacity);
+ }
+
+ #[test]
+ fn insert_col_at_end() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor);
+ grid.insert_col(2, vec![5, 6]);
+ test_grid(&grid, 2, 3, Order::RowMajor, &[1, 2, 5, 3, 4, 6]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn insert_col_out_of_idx() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor);
+ grid.insert_col(3, vec![4, 5]);
+ }
+
+ #[test]
+ fn insert_col_empty() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::RowMajor);
+ grid.insert_col(0, vec![1, 2, 3]);
+ test_grid(&grid, 3, 1, Order::RowMajor, &[1, 2, 3]);
+ }
+
+ #[test]
+ fn insert_col_at_end_column_major() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor);
+ grid.insert_col(2, vec![5, 6]);
+ test_grid(&grid, 2, 3, Order::ColumnMajor, &[1, 3, 2, 4, 5, 6]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn insert_col_out_of_idx_column_major() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor);
+ grid.insert_col(3, vec![4, 5]);
+ }
+
+ #[test]
+ fn insert_col_empty_column_major() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor);
+ grid.insert_col(0, vec![1, 2, 3]);
+ test_grid(&grid, 3, 1, Order::ColumnMajor, &[1, 2, 3]);
+ }
+
+ #[test]
+ fn insert_row_at_end() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor);
+ grid.insert_row(2, vec![5, 6]);
+ test_grid(&grid, 3, 2, Order::RowMajor, &[1, 2, 3, 4, 5, 6]);
+ }
+
+ #[test]
+ fn insert_row_empty() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::RowMajor);
+ grid.insert_row(0, vec![1, 2, 3]);
+ test_grid(&grid, 1, 3, Order::RowMajor, &[1, 2, 3]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn insert_row_out_of_idx() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor);
+ grid.insert_row(3, vec![4, 5]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn insert_row_wrong_size_of_idx() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor);
+ grid.insert_row(1, vec![4, 5, 4]);
+ }
+
+ #[test]
+ fn insert_row_start() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor);
+ grid.insert_row(1, vec![5, 6]);
+ test_grid(&grid, 3, 2, Order::RowMajor, &[1, 2, 5, 6, 3, 4]);
+ }
+
+ #[test]
+ fn insert_row_at_end_column_major() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor);
+ grid.insert_row(2, vec![5, 6]);
+ test_grid(&grid, 3, 2, Order::ColumnMajor, &[1, 3, 5, 2, 4, 6]);
+ }
+
+ #[test]
+ fn insert_row_empty_column_major() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor);
+ grid.insert_row(0, vec![1, 2, 3]);
+ test_grid(&grid, 1, 3, Order::ColumnMajor, &[1, 2, 3]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn insert_row_out_of_idx_column_major() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::ColumnMajor);
+ grid.insert_row(3, vec![4, 5]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn insert_row_wrong_size_of_idx_column_major() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::ColumnMajor);
+ grid.insert_row(1, vec![4, 5, 4]);
+ }
+
+ #[test]
+ fn insert_row_start_column_major() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor);
+ grid.insert_row(1, vec![5, 6]);
+ test_grid(&grid, 3, 2, Order::ColumnMajor, &[1, 5, 3, 2, 6, 4]);
+ }
+
+ #[test]
+ fn pop_col_1x3() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3], 3, Order::RowMajor);
+ assert_eq!(grid.pop_col(), Some(vec![3]));
+ test_grid(&grid, 1, 2, Order::RowMajor, &[1, 2]);
+ assert_eq!(grid.pop_col(), Some(vec![2]));
+ test_grid(&grid, 1, 1, Order::RowMajor, &[1]);
+ assert_eq!(grid.pop_col(), Some(vec![1]));
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+ assert_eq!(grid.pop_col(), None);
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+ }
+
+ #[test]
+ fn pop_col_3x1() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3], 1, Order::RowMajor);
+ assert_eq!(grid.pop_col(), Some(vec![1, 2, 3]));
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+ assert_eq!(grid.pop_col(), None);
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+ }
+
+ #[test]
+ fn pop_col_2x2() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor);
+ assert_eq!(grid.pop_col(), Some(vec![2, 4]));
+ assert_eq!(grid.size(), (2, 1));
+ test_grid(&grid, 2, 1, Order::RowMajor, &[1, 3]);
+ assert_eq!(grid.pop_col(), Some(vec![1, 3]));
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+ assert_eq!(grid.pop_col(), None);
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+ }
+
+ #[test]
+ fn pop_col_3x4() {
+ let internal = vec![1, 2, 3, 4, 11, 22, 33, 44, 111, 222, 333, 444];
+ let mut grid: Grid<u16> = Grid::from_vec_with_order(internal, 4, Order::RowMajor);
+ assert_eq!(grid.pop_col(), Some(vec![4, 44, 444]));
+ let expected = [1, 2, 3, 11, 22, 33, 111, 222, 333];
+ test_grid(&grid, 3, 3, Order::RowMajor, &expected);
+ assert_eq!(grid.pop_col(), Some(vec![3, 33, 333]));
+ test_grid(&grid, 3, 2, Order::RowMajor, &[1, 2, 11, 22, 111, 222]);
+ assert_eq!(grid.pop_col(), Some(vec![2, 22, 222]));
+ test_grid(&grid, 3, 1, Order::RowMajor, &[1, 11, 111]);
+ assert_eq!(grid.pop_col(), Some(vec![1, 11, 111]));
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+ assert_eq!(grid.pop_col(), None);
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+ }
+
+ #[test]
+ fn pop_col_empty() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::RowMajor);
+ assert_eq!(grid.pop_col(), None);
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+ }
+
+ #[test]
+ fn pop_col_1x3_column_major() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3], 3, Order::ColumnMajor);
+ assert_eq!(grid.pop_col(), Some(vec![3]));
+ test_grid(&grid, 1, 2, Order::ColumnMajor, &[1, 2]);
+ assert_eq!(grid.pop_col(), Some(vec![2]));
+ test_grid(&grid, 1, 1, Order::ColumnMajor, &[1]);
+ assert_eq!(grid.pop_col(), Some(vec![1]));
+ test_grid(&grid, 0, 0, Order::ColumnMajor, &[]);
+ assert_eq!(grid.pop_col(), None);
+ test_grid(&grid, 0, 0, Order::ColumnMajor, &[]);
+ }
+
+ #[test]
+ fn pop_col_3x1_column_major() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3], 1, Order::ColumnMajor);
+ assert_eq!(grid.pop_col(), Some(vec![1, 2, 3]));
+ test_grid(&grid, 0, 0, Order::ColumnMajor, &[]);
+ assert_eq!(grid.pop_col(), None);
+ test_grid(&grid, 0, 0, Order::ColumnMajor, &[]);
+ }
+
+ #[test]
+ fn pop_col_2x2_column_major() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor);
+ assert_eq!(grid.pop_col(), Some(vec![2, 4]));
+ assert_eq!(grid.size(), (2, 1));
+ test_grid(&grid, 2, 1, Order::ColumnMajor, &[1, 3]);
+ assert_eq!(grid.pop_col(), Some(vec![1, 3]));
+ test_grid(&grid, 0, 0, Order::ColumnMajor, &[]);
+ assert_eq!(grid.pop_col(), None);
+ test_grid(&grid, 0, 0, Order::ColumnMajor, &[]);
+ }
+
+ #[test]
+ fn pop_col_3x4_column_major() {
+ let internal = vec![1, 11, 111, 2, 22, 222, 3, 33, 333, 4, 44, 444];
+ let mut grid: Grid<u16> = Grid::from_vec_with_order(internal, 4, Order::ColumnMajor);
+ assert_eq!(grid.pop_col(), Some(vec![4, 44, 444]));
+ let expected = [1, 11, 111, 2, 22, 222, 3, 33, 333];
+ test_grid(&grid, 3, 3, Order::ColumnMajor, &expected);
+ assert_eq!(grid.pop_col(), Some(vec![3, 33, 333]));
+ test_grid(&grid, 3, 2, Order::ColumnMajor, &[1, 11, 111, 2, 22, 222]);
+ assert_eq!(grid.pop_col(), Some(vec![2, 22, 222]));
+ test_grid(&grid, 3, 1, Order::ColumnMajor, &[1, 11, 111]);
+ assert_eq!(grid.pop_col(), Some(vec![1, 11, 111]));
+ test_grid(&grid, 0, 0, Order::ColumnMajor, &[]);
+ assert_eq!(grid.pop_col(), None);
+ test_grid(&grid, 0, 0, Order::ColumnMajor, &[]);
+ }
+
+ #[test]
+ fn pop_col_empty_column_major() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor);
+ assert_eq!(grid.pop_col(), None);
+ test_grid(&grid, 0, 0, Order::ColumnMajor, &[]);
+ }
+
+ #[test]
+ fn pop_row_2x2() {
+ let mut grid: Grid<u8> = Grid::from_vec(vec![1, 2, 3, 4], 2);
+ assert_eq!(grid.pop_row(), Some(vec![3, 4]));
+ test_grid(&grid, 1, 2, Order::RowMajor, &[1, 2]);
+ assert_eq!(grid.pop_row(), Some(vec![1, 2]));
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+ assert_eq!(grid.pop_row(), None);
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+ }
+
+ #[test]
+ fn pop_row_empty() {
+ let mut grid: Grid<u8> = Grid::from_vec(vec![], 0);
+ assert_eq!(grid.pop_row(), None);
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+ }
+
+ #[test]
+ fn pop_row_2x2_column_major() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor);
+ assert_eq!(grid.pop_row(), Some(vec![3, 4]));
+ test_grid(&grid, 1, 2, Order::ColumnMajor, &[1, 2]);
+ assert_eq!(grid.pop_row(), Some(vec![1, 2]));
+ test_grid(&grid, 0, 0, Order::ColumnMajor, &[]);
+ assert_eq!(grid.pop_row(), None);
+ test_grid(&grid, 0, 0, Order::ColumnMajor, &[]);
+ }
+
+ #[test]
+ fn pop_row_empty_column_major() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor);
+ assert_eq!(grid.pop_row(), None);
+ test_grid(&grid, 0, 0, Order::ColumnMajor, &[]);
+ }
+
+ #[test]
+ fn ne_full_empty() {
+ let g1 = Grid::from_vec(vec![1, 2, 3, 4], 2);
+ let g2: Grid<u8> = grid![];
+ assert_ne!(g1, g2);
+ }
+
+ #[test]
+ fn ne() {
+ let g1 = Grid::from_vec(vec![1, 2, 3, 5], 2);
+ let g2 = Grid::from_vec(vec![1, 2, 3, 4], 2);
+ assert_ne!(g1, g2);
+ }
+
+ #[test]
+ fn ne_dif_rows() {
+ let g1 = Grid::from_vec(vec![1, 2, 3, 4], 2);
+ let g2 = Grid::from_vec(vec![1, 2, 3, 4], 1);
+ assert_ne!(g1, g2);
+ }
+
+ #[test]
+ fn equal_empty() {
+ let grid: Grid<char> = grid![];
+ let grid2: Grid<char> = grid![];
+ assert_eq!(grid, grid2);
+ }
+
+ #[test]
+ fn equal() {
+ let grid: Grid<char> = grid![['a', 'b', 'c', 'd']['a', 'b', 'c', 'd']['a', 'b', 'c', 'd']];
+ let grid2: Grid<char> = grid![['a', 'b', 'c', 'd']['a', 'b', 'c', 'd']['a', 'b', 'c', 'd']];
+ assert_eq!(grid, grid2);
+ }
+
+ #[test]
+ fn equal_different_order() {
+ let grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor);
+ let grid2 = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor);
+ assert_eq!(grid, grid2);
+ }
+
+ #[test]
+ fn equal_partial_eq() {
+ let grid = grid![[1.0]];
+ let grid2 = Grid::from_vec(vec![1.0], 1);
+ assert_eq!(grid, grid2);
+ }
+
+ #[test]
+ fn ne_partial_eq() {
+ let grid = grid![[f64::NAN]];
+ assert_ne!(grid, grid);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn idx_tup_out_of_col_bounds() {
+ let grid: Grid<char> = grid![['a', 'b', 'c', 'd']['a', 'b', 'c', 'd']['a', 'b', 'c', 'd']];
+ let _ = grid[(0, 5)];
+ }
+
+ #[test]
+ fn push_col_2x3() {
+ let mut grid: Grid<u8> = grid![
+ [0, 1, 2]
+ [10, 11, 12]];
+ grid.push_col(vec![3, 13]);
+ test_grid(&grid, 2, 4, Order::RowMajor, &[0, 1, 2, 3, 10, 11, 12, 13]);
+ }
+
+ #[test]
+ fn push_col_3x4() {
+ let mut grid: Grid<char> = grid![
+ ['a', 'b', 'c', 'd']
+ ['a', 'b', 'c', 'd']
+ ['a', 'b', 'c', 'd']];
+ grid.push_col(vec!['x', 'y', 'z']);
+ let expected = [
+ 'a', 'b', 'c', 'd', 'x', 'a', 'b', 'c', 'd', 'y', 'a', 'b', 'c', 'd', 'z',
+ ];
+ test_grid(&grid, 3, 5, Order::RowMajor, &expected);
+ }
+
+ #[test]
+ fn push_col_1x3() {
+ let mut grid: Grid<char> = grid![['a', 'b', 'c']];
+ grid.push_col(vec!['d']);
+ test_grid(&grid, 1, 4, Order::RowMajor, &['a', 'b', 'c', 'd']);
+ }
+
+ #[test]
+ fn push_col_empty() {
+ let mut grid: Grid<char> = grid![];
+ grid.push_col(vec!['b', 'b', 'b', 'b']);
+ test_grid(&grid, 4, 1, Order::RowMajor, &['b', 'b', 'b', 'b']);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn push_col_wrong_size() {
+ let mut grid: Grid<char> = grid![['a','a','a']['a','a','a']];
+ grid.push_col(vec!['b']);
+ grid.push_col(vec!['b', 'b']);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn push_col_zero_len() {
+ let mut grid: Grid<char> = grid![];
+ grid.push_col(vec![]);
+ }
+
+ #[test]
+ fn push_col_2x3_column_major() {
+ let internal = vec![0, 10, 1, 11, 2, 12];
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(internal, 3, Order::ColumnMajor);
+ grid.push_col(vec![3, 13]);
+ let expected = [0, 10, 1, 11, 2, 12, 3, 13];
+ test_grid(&grid, 2, 4, Order::ColumnMajor, &expected);
+ }
+
+ #[test]
+ fn push_col_3x4_column_major() {
+ let internal = vec!['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd'];
+ let mut grid: Grid<char> = Grid::from_vec_with_order(internal, 4, Order::ColumnMajor);
+ grid.push_col(vec!['x', 'y', 'z']);
+ let expected = [
+ 'a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd', 'x', 'y', 'z',
+ ];
+ test_grid(&grid, 3, 5, Order::ColumnMajor, &expected);
+ }
+
+ #[test]
+ fn push_col_1x3_column_major() {
+ let mut grid: Grid<char> =
+ Grid::from_vec_with_order(vec!['a', 'b', 'c'], 3, Order::ColumnMajor);
+ grid.push_col(vec!['d']);
+ test_grid(&grid, 1, 4, Order::ColumnMajor, &['a', 'b', 'c', 'd']);
+ }
+
+ #[test]
+ fn push_col_empty_column_major() {
+ let mut grid: Grid<char> = Grid::new_with_order(0, 0, Order::ColumnMajor);
+ grid.push_col(vec!['b', 'b', 'b', 'b']);
+ test_grid(&grid, 4, 1, Order::ColumnMajor, &['b', 'b', 'b', 'b']);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn push_col_wrong_size_column_major() {
+ let mut grid: Grid<char> = Grid::init_with_order(2, 3, Order::ColumnMajor, 'a');
+ grid.push_col(vec!['b']);
+ grid.push_col(vec!['b', 'b']);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn push_col_zero_len_column_major() {
+ let mut grid: Grid<char> = Grid::new_with_order(0, 0, Order::ColumnMajor);
+ grid.push_col(vec![]);
+ }
+
+ #[test]
+ fn push_row() {
+ let mut grid: Grid<u8> = grid![[1, 2][3, 4]];
+ grid.push_row(vec![5, 6]);
+ test_grid(&grid, 3, 2, Order::RowMajor, &[1, 2, 3, 4, 5, 6]);
+ }
+
+ #[test]
+ fn push_row_empty() {
+ let mut grid: Grid<char> = grid![];
+ grid.push_row(vec!['b', 'b', 'b', 'b']);
+ test_grid(&grid, 1, 4, Order::RowMajor, &['b', 'b', 'b', 'b']);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn push_empty_row() {
+ let mut grid = Grid::init(0, 1, 0);
+ grid.push_row(vec![]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn push_row_wrong_size() {
+ let mut grid: Grid<char> = grid![['a','a','a']['a','a','a']];
+ grid.push_row(vec!['b']);
+ grid.push_row(vec!['b', 'b', 'b', 'b']);
+ }
+
+ #[test]
+ fn push_row_column_major() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor);
+ grid.push_row(vec![5, 6]);
+ test_grid(&grid, 3, 2, Order::ColumnMajor, &[1, 3, 5, 2, 4, 6]);
+ }
+
+ #[test]
+ fn push_row_empty_column_major() {
+ let mut grid: Grid<char> = Grid::new_with_order(0, 0, Order::ColumnMajor);
+ grid.push_row(vec!['b', 'b', 'b', 'b']);
+ test_grid(&grid, 1, 4, Order::ColumnMajor, &['b', 'b', 'b', 'b']);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn push_empty_row_column_major() {
+ let mut grid = Grid::init_with_order(0, 1, Order::ColumnMajor, 0);
+ grid.push_row(vec![]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn push_row_wrong_size_column_major() {
+ let mut grid: Grid<char> =
+ Grid::from_vec_with_order(vec!['a', 'a', 'a', 'a', 'a', 'a'], 3, Order::ColumnMajor);
+ grid.push_row(vec!['b']);
+ grid.push_row(vec!['b', 'b', 'b', 'b']);
+ }
+
+ #[test]
+ fn iter_row() {
+ let grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor);
+ let row: Vec<_> = grid.iter_row(1).collect();
+ assert_eq!(row, [&4, &5, &6]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn iter_row_out_of_bound() {
+ let grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor);
+ let _ = grid.iter_row(3);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn iter_row_zero() {
+ let grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::RowMajor);
+ let _ = grid.iter_row(0);
+ }
+
+ #[test]
+ fn iter_row_rowumn_major() {
+ let grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor);
+ let row: Vec<_> = grid.iter_row(1).collect();
+ assert_eq!(row, [&4, &5, &6]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn iter_row_rowumn_major_out_of_bound() {
+ let grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor);
+ let _ = grid.iter_row(3);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn iter_row_rowumn_major_zero() {
+ let grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor);
+ let _ = grid.iter_row(0);
+ }
+
+ #[test]
+ fn iter_row_mut() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor);
+ let row: Vec<_> = grid.iter_row_mut(1).collect();
+ assert_eq!(row, [&mut 4, &mut 5, &mut 6]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn iter_row_mut_out_of_bound() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor);
+ let _ = grid.iter_row_mut(3);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn iter_row_mut_zero() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::RowMajor);
+ let _ = grid.iter_row_mut(0);
+ }
+
+ #[test]
+ fn iter_row_mut_rowumn_major() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor);
+ let row: Vec<_> = grid.iter_row_mut(1).collect();
+ assert_eq!(row, [&mut 4, &mut 5, &mut 6]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn iter_row_mut_rowumn_major_out_of_bound() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor);
+ let _ = grid.iter_row_mut(3);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn iter_row_mut_rowumn_major_zero() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor);
+ let _ = grid.iter_row_mut(0);
+ }
+
+ #[test]
+ fn iter_col() {
+ let grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor);
+ let col: Vec<_> = grid.iter_col(1).collect();
+ assert_eq!(col, [&2, &5]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn iter_col_out_of_bound() {
+ let grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor);
+ let _ = grid.iter_col(3);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn iter_col_zero() {
+ let grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::RowMajor);
+ let _ = grid.iter_col(0);
+ }
+
+ #[test]
+ fn iter_col_column_major() {
+ let grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor);
+ let col: Vec<_> = grid.iter_col(1).collect();
+ assert_eq!(col, [&2, &5]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn iter_col_column_major_out_of_bound() {
+ let grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor);
+ let _ = grid.iter_col(3);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn iter_col_column_major_zero() {
+ let grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor);
+ let _ = grid.iter_col(0);
+ }
+
+ #[test]
+ fn iter_col_mut() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor);
+ let col: Vec<_> = grid.iter_col_mut(1).collect();
+ assert_eq!(col, [&mut 2, &mut 5]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn iter_col_mut_out_of_bound() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor);
+ let _ = grid.iter_col_mut(3);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn iter_col_mut_zero() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::RowMajor);
+ let _ = grid.iter_col_mut(0);
+ }
+
+ #[test]
+ fn iter_col_mut_column_major() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor);
+ let col: Vec<_> = grid.iter_col_mut(1).collect();
+ assert_eq!(col, [&mut 2, &mut 5]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn iter_col_mut_column_major_out_of_bound() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor);
+ let _ = grid.iter_col_mut(3);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn iter_col_mut_column_major_zero() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor);
+ let _ = grid.iter_col_mut(0);
+ }
+
+ #[test]
+ fn iter() {
+ let grid: Grid<u8> = grid![[1,2][3,4]];
+ let mut iter = grid.iter();
+ assert_eq!(iter.next(), Some(&1));
+ assert_eq!(iter.next(), Some(&2));
+ assert_eq!(iter.next(), Some(&3));
+ assert_eq!(iter.next(), Some(&4));
+ assert_eq!(iter.next(), None);
+ }
+
+ #[test]
+ fn into_iter() {
+ let grid: Grid<u8> = grid![[1,1][1,1]];
+ for val in &grid {
+ assert_eq!(val, &1);
+ }
+ }
+
+ #[test]
+ fn into_iter_mut() {
+ let mut grid: Grid<u8> = grid![[1,1][1,1]];
+ for val in &mut grid {
+ *val = 2;
+ }
+ assert_eq!(grid, grid![[2, 2][2, 2]]);
+ }
+
+ #[test]
+ fn indexed_iter() {
+ let grid: Grid<u8> = grid![[1,2][3,4]];
+ let mut iter = grid.indexed_iter();
+ assert_eq!(iter.next(), Some(((0, 0), &1)));
+ assert_eq!(iter.next(), Some(((0, 1), &2)));
+ assert_eq!(iter.next(), Some(((1, 0), &3)));
+ assert_eq!(iter.next(), Some(((1, 1), &4)));
+ assert_eq!(iter.next(), None);
+ }
+
+ #[test]
+ fn indexed_iter_empty() {
+ let grid: Grid<u8> = Grid::new(0, 0);
+ let mut iter = grid.indexed_iter();
+ assert_eq!(iter.next(), None);
+ }
+
+ #[test]
+ fn indexed_iter_column_major() {
+ let grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor);
+ let mut iter = grid.indexed_iter();
+ assert_eq!(iter.next(), Some(((0, 0), &1)));
+ assert_eq!(iter.next(), Some(((1, 0), &3)));
+ assert_eq!(iter.next(), Some(((0, 1), &2)));
+ assert_eq!(iter.next(), Some(((1, 1), &4)));
+ assert_eq!(iter.next(), None);
+ }
+
+ #[test]
+ fn indexed_iter_empty_column_major() {
+ let grid: Grid<u8> = Grid::new_with_order(0, 0, Order::ColumnMajor);
+ let mut iter = grid.indexed_iter();
+ assert_eq!(iter.next(), None);
+ }
+
+ #[test]
+ fn indexed_iter_mut() {
+ let mut grid: Grid<u8> = grid![[1,2][3,4]];
+ let mut iter = grid.indexed_iter_mut();
+ assert_eq!(iter.next(), Some(((0, 0), &mut 1)));
+ assert_eq!(iter.next(), Some(((0, 1), &mut 2)));
+ assert_eq!(iter.next(), Some(((1, 0), &mut 3)));
+ assert_eq!(iter.next(), Some(((1, 1), &mut 4)));
+ assert_eq!(iter.next(), None);
+ }
+
+ #[test]
+ fn indexed_iter_mut_empty() {
+ let mut grid: Grid<u8> = Grid::new(0, 0);
+ let mut iter = grid.indexed_iter_mut();
+ assert_eq!(iter.next(), None);
+ }
+
+ #[test]
+ fn indexed_iter_mut_column_major() {
+ let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor);
+ let mut iter = grid.indexed_iter_mut();
+ assert_eq!(iter.next(), Some(((0, 0), &mut 1)));
+ assert_eq!(iter.next(), Some(((1, 0), &mut 3)));
+ assert_eq!(iter.next(), Some(((0, 1), &mut 2)));
+ assert_eq!(iter.next(), Some(((1, 1), &mut 4)));
+ assert_eq!(iter.next(), None);
+ }
+
+ #[test]
+ fn indexed_iter_mut_empty_column_major() {
+ let mut grid: Grid<u8> = Grid::new_with_order(0, 0, Order::ColumnMajor);
+ let mut iter = grid.indexed_iter_mut();
+ assert_eq!(iter.next(), None);
+ }
+
+ #[test]
+ fn clear() {
+ let mut grid: Grid<u8> = grid![[1, 2, 3]];
+ assert!(!grid.is_empty());
+ grid.clear();
+ assert!(grid.is_empty());
+ }
+
+ #[test]
+ fn is_empty_false() {
+ let grid: Grid<u8> = grid![[1, 2, 3]];
+ assert!(!grid.is_empty());
+ }
+
+ #[test]
+ fn is_empty() {
+ let mut g: Grid<u8> = grid![[]];
+ assert!(g.is_empty());
+ g = grid![];
+ assert!(g.is_empty());
+ g = Grid::from_vec(vec![], 0);
+ assert!(g.is_empty());
+ g = Grid::new(0, 0);
+ assert!(g.is_empty());
+ g = Grid::new(0, 1);
+ assert!(g.is_empty());
+ g = Grid::new(1, 0);
+ assert!(g.is_empty());
+ g = Grid::init(0, 0, 10);
+ assert!(g.is_empty());
+ }
+
+ #[test]
+ fn fmt_empty() {
+ let grid: Grid<u8> = grid![];
+ assert_eq!(format!("{grid:?}"), "[]");
+ }
+
+ #[test]
+ fn fmt_row() {
+ let grid: Grid<u8> = grid![[1, 2, 3]];
+ assert_eq!(format!("{grid:?}"), "[[1, 2, 3]]");
+ }
+
+ #[test]
+ fn fmt_grid() {
+ let grid: Grid<u8> = grid![[1,2,3][4,5,6][7,8,9]];
+ assert_eq!(format!("{grid:?}"), "[[1, 2, 3][4, 5, 6][7, 8, 9]]");
+ }
+
+ #[test]
+ fn fmt_column_major() {
+ let grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor);
+ assert_eq!(format!("{grid:?}"), "[[1, 2, 3][4, 5, 6]]");
+ }
+
+ #[test]
+ fn fmt_pretty_empty() {
+ let grid: Grid<f32> = grid![];
+ assert_eq!(format!("{grid:#?}"), "[]");
+ }
+
+ #[test]
+ fn fmt_pretty_int() {
+ let grid: Grid<u8> = grid![
+ [1,2,3]
+ [4,5,6]
+ [7,8,95]
+ ];
+
+ let expected_output = r"[
+ [ 1, 2, 3]
+ [ 4, 5, 6]
+ [ 7, 8, 95]
+]";
+
+ assert_eq!(format!("{grid:#?}"), expected_output);
+
+ let expected_output = r"[
+ [ 1, 2, 3]
+ [ 4, 5, 6]
+ [ 7, 8, 95]
+]";
+
+ assert_eq!(format!("{grid:#3?}"), expected_output);
+ }
+
+ #[test]
+ fn fmt_pretty_float() {
+ let grid: Grid<f32> = grid![
+ [1.5,2.6,3.44]
+ [4.775,5.,6.]
+ [7.1,8.23444,95.55]
+ ];
+
+ let expected_output = r"[
+ [ 1.5, 2.6, 3.4]
+ [ 4.8, 5.0, 6.0]
+ [ 7.1, 8.2, 95.6]
+]";
+
+ assert_eq!(format!("{grid:#5.1?}"), expected_output);
+
+ let expected_output = r"[
+ [ 1.50000, 2.60000, 3.44000]
+ [ 4.77500, 5.00000, 6.00000]
+ [ 7.10000, 8.23444, 95.55000]
+]";
+
+ assert_eq!(format!("{grid:#8.5?}"), expected_output);
+ }
+
+ #[test]
+ fn fmt_pretty_tuple() {
+ let grid: Grid<(i32, i32)> = grid![
+ [(5,66), (432, 55)]
+ [(80, 90), (5, 6)]
+ ];
+
+ let expected_output = r"[
+ [ ( 5, 66), ( 432, 55)]
+ [ ( 80, 90), ( 5, 6)]
+]";
+
+ assert_eq!(format!("{grid:#?}"), expected_output);
+
+ let expected_output = r"[
+ [ ( 5, 66), (432, 55)]
+ [ ( 80, 90), ( 5, 6)]
+]";
+
+ assert_eq!(format!("{grid:#3?}"), expected_output);
+ }
+
+ #[test]
+ fn fmt_pretty_struct_derived() {
+ #[derive(Debug)]
+ struct Person {
+ _name: String,
+ _precise_age: f32,
+ }
+
+ impl Person {
+ fn new(name: &str, precise_age: f32) -> Self {
+ Self {
+ _name: name.into(),
+ _precise_age: precise_age,
+ }
+ }
+ }
+
+ let grid: Grid<Person> = grid![
+ [Person::new("Vic", 24.5), Person::new("Mr. Very Long Name", 1955.)]
+ [Person::new("Sam", 8.9995), Person::new("John Doe", 40.14)]
+ ];
+
+ let expected_output = r#"[
+ [ Person { _name: "Vic", _precise_age: 24.50000 }, Person { _name: "Mr. Very Long Name", _precise_age: 1955.00000 }]
+ [ Person { _name: "Sam", _precise_age: 8.99950 }, Person { _name: "John Doe", _precise_age: 40.14000 }]
+]"#;
+
+ assert_eq!(format!("{grid:#5.5?}"), expected_output);
+ }
+
+ #[test]
+ fn fmt_pretty_column_major() {
+ let grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor);
+ let expected_output = r"[
+ [ 1, 2, 3]
+ [ 4, 5, 6]
+]";
+ assert_eq!(format!("{grid:#?}"), expected_output);
+ }
+
+ #[test]
+ fn clone() {
+ let grid = grid![[1, 2, 3][4, 5, 6]];
+ let mut clone = grid.clone();
+ clone[(0, 2)] = 10;
+ test_grid(&grid, 2, 3, Order::RowMajor, &[1, 2, 3, 4, 5, 6]);
+ test_grid(&clone, 2, 3, Order::RowMajor, &[1, 2, 10, 4, 5, 6]);
+ }
+
+ #[cfg(feature = "std")]
+ #[test]
+ fn hash_std() {
+ let mut set = std::collections::HashSet::new();
+ set.insert(grid![[1,2,3][4,5,6]]);
+ set.insert(grid![[1,3,3][4,5,6]]);
+ set.insert(grid![[1,2,3][4,5,6]]);
+ assert_eq!(set.len(), 2);
+ }
+
+ #[test]
+ fn macro_init() {
+ let grid = grid![[1, 2, 3][4, 5, 6]];
+ test_grid(&grid, 2, 3, Order::RowMajor, &[1, 2, 3, 4, 5, 6]);
+ }
+
+ #[test]
+ fn macro_init_2() {
+ let grid = grid![[1, 2, 3]
+ [4, 5, 6]
+ [7, 8, 9]];
+ test_grid(&grid, 3, 3, Order::RowMajor, &[1, 2, 3, 4, 5, 6, 7, 8, 9]);
+ }
+
+ #[test]
+ fn macro_init_char() {
+ let grid = grid![['a', 'b', 'c']
+ ['a', 'b', 'c']
+ ['a', 'b', 'c']];
+ let expected = ['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c'];
+ test_grid(&grid, 3, 3, Order::RowMajor, &expected);
+ }
+
+ #[test]
+ fn macro_one_row() {
+ let grid: Grid<usize> = grid![[1, 2, 3, 4]];
+ test_grid(&grid, 1, 4, Order::RowMajor, &[1, 2, 3, 4]);
+ }
+
+ #[test]
+ fn macro2_empty() {
+ let grid: Grid<u8> = grid_cm![];
+ test_grid(&grid, 0, 0, Order::ColumnMajor, &[]);
+ }
+
+ #[test]
+ fn macro2_init() {
+ let grid = grid_cm![[1, 2, 3]
+ [4, 5, 6]
+ [7, 8, 9]];
+ let expected = [1, 4, 7, 2, 5, 8, 3, 6, 9];
+ test_grid(&grid, 3, 3, Order::ColumnMajor, &expected);
+ }
+
+ #[test]
+ fn macro2_init_char() {
+ let grid = grid_cm![['a', 'b']['c', 'd']];
+ test_grid(&grid, 2, 2, Order::ColumnMajor, &['a', 'c', 'b', 'd']);
+ }
+
+ #[test]
+ fn macro2_one_row() {
+ let grid = grid_cm![[1, 2, 3, 4]];
+ test_grid(&grid, 1, 4, Order::ColumnMajor, &[1, 2, 3, 4]);
+ }
+
+ #[test]
+ fn init() {
+ let grid = Grid::init(1, 2, 3);
+ test_grid(&grid, 1, 2, Order::RowMajor, &[3, 3]);
+
+ let grid = Grid::init(1, 2, 1.2);
+ test_grid(&grid, 1, 2, Order::RowMajor, &[1.2, 1.2]);
+
+ let grid = Grid::init(1, 2, 'a');
+ test_grid(&grid, 1, 2, Order::RowMajor, &['a', 'a']);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn init_panics() {
+ Grid::init(usize::MAX, 2, 3);
+ }
+
+ #[test]
+ fn init_empty() {
+ let grid = Grid::init(0, 1, 0);
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+
+ let grid = Grid::init(1, 0, -1);
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+ }
+
+ #[test]
+ fn init_with_order() {
+ let grid = Grid::init_with_order(1, 2, Order::RowMajor, 3);
+ test_grid(&grid, 1, 2, Order::RowMajor, &[3, 3]);
+
+ let grid = Grid::init_with_order(1, 2, Order::ColumnMajor, 1.2);
+ test_grid(&grid, 1, 2, Order::ColumnMajor, &[1.2, 1.2]);
+
+ let grid = Grid::init_with_order(1, 2, Order::ColumnMajor, 'a');
+ test_grid(&grid, 1, 2, Order::ColumnMajor, &['a', 'a']);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn init_with_order_panics() {
+ Grid::init_with_order(usize::MAX, 2, Order::ColumnMajor, 3);
+ }
+
+ #[test]
+ fn init_with_order_empty() {
+ let grid = Grid::init_with_order(0, 1, Order::ColumnMajor, 0);
+ test_grid(&grid, 0, 0, Order::ColumnMajor, &[]);
+
+ let grid = Grid::init_with_order(1, 0, Order::RowMajor, -1);
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+ }
+
+ #[test]
+ fn new() {
+ let grid: Grid<u8> = Grid::new(1, 2);
+ test_grid(&grid, 1, 2, Order::RowMajor, &[0, 0]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn new_panics() {
+ let _: Grid<u8> = Grid::new(usize::MAX, 2);
+ }
+
+ #[test]
+ fn new_empty() {
+ let grid: Grid<u8> = Grid::new(0, 1);
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+
+ let grid: Grid<u8> = Grid::new(1, 0);
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+ }
+
+ #[test]
+ fn new_with_order() {
+ let grid: Grid<u8> = Grid::new_with_order(2, 2, Order::ColumnMajor);
+ test_grid(&grid, 2, 2, Order::ColumnMajor, &[0, 0, 0, 0]);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn new_with_order_panics() {
+ let _: Grid<u8> = Grid::new_with_order(usize::MAX, 2, Order::ColumnMajor);
+ }
+
+ #[test]
+ fn new_with_order_empty() {
+ let grid: Grid<u8> = Grid::new_with_order(0, 3, Order::RowMajor);
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+
+ let grid: Grid<u8> = Grid::new_with_order(3, 0, Order::ColumnMajor);
+ test_grid(&grid, 0, 0, Order::ColumnMajor, &[]);
+ }
+
+ #[test]
+ fn with_capacity() {
+ // doesn't impl Default
+ struct Foo();
+
+ let grid: Grid<Foo> = Grid::with_capacity(20, 20);
+ assert!(grid.is_empty());
+ assert_eq!(grid.order(), Order::default());
+ }
+
+ #[test]
+ fn with_capacity_and_order() {
+ // doesn't impl Default
+ struct Foo();
+
+ let grid: Grid<Foo> = Grid::with_capacity_and_order(20, 20, Order::ColumnMajor);
+ assert!(grid.is_empty());
+ assert_eq!(grid.order(), Order::ColumnMajor);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn with_capacity_panics_internal() {
+ // doesn't impl Default
+ struct Foo();
+
+ let _grid: Grid<Foo> = Grid::with_capacity_and_order(usize::MAX, 2, Order::RowMajor);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn with_capacity_panics_vec() {
+ let rows: usize = isize::MAX.try_into().expect("isize::MAX is positive");
+ assert!(
+ core::mem::size_of::<u8>() * rows < usize::MAX,
+ "shows that panic is from Vec::with_capacity, not internal check"
+ );
+
+ let _grid: Grid<u8> = Grid::with_capacity_and_order(rows, 2, Order::RowMajor);
+ }
+
+ #[test]
+ fn get() {
+ let grid = Grid::from_vec_with_order(vec![1, 2], 2, Order::RowMajor);
+ assert_eq!(grid.get(0_i64, 1_i32), Some(&2));
+ }
+
+ #[test]
+ fn get_column_major() {
+ let grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::ColumnMajor);
+ assert_eq!(grid.get(1, 0), Some(&2));
+ }
+
+ #[test]
+ fn get_none() {
+ let grid = Grid::from_vec_with_order(vec![1, 2], 2, Order::RowMajor);
+ assert_eq!(grid.get(1, 0), None);
+ }
+
+ #[test]
+ fn get_none_column_major() {
+ let grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::ColumnMajor);
+ assert_eq!(grid.get(0, 1), None);
+ }
+
+ #[test]
+ fn get_mut() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 2], 2, Order::RowMajor);
+ assert_eq!(grid.get_mut(0_i64, 1_i32), Some(&mut 2));
+ }
+
+ #[test]
+ fn get_mut_column_major() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::ColumnMajor);
+ assert_eq!(grid.get_mut(1, 0), Some(&mut 2));
+ }
+
+ #[test]
+ fn get_mut_none() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 2], 2, Order::RowMajor);
+ assert_eq!(grid.get_mut(1, 0), None);
+ }
+
+ #[test]
+ fn get_mut_none_column_major() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::ColumnMajor);
+ assert_eq!(grid.get_mut(0, 1), None);
+ }
+
+ #[test]
+ fn idx_tup() {
+ let grid: Grid<u8> = Grid::from_vec(vec![1, 2, 3, 4], 2);
+ assert_eq!(grid[(0, 0)], 1);
+ assert_eq!(grid[(0, 1)], 2);
+ assert_eq!(grid[(1, 0)], 3);
+ assert_eq!(grid[(1, 1)], 4);
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn idx_tup_panic_1() {
+ let grid = Grid::init(1, 2, 3);
+ let _ = grid[(20, 0)];
+ }
+
+ #[test]
+ #[should_panic]
+ #[allow(clippy::should_panic_without_expect)]
+ fn idx_tup_panic_2() {
+ let grid = Grid::init(1, 2, 3);
+ let _ = grid[(0, 20)];
+ }
+
+ #[test]
+ fn idx_tup_set() {
+ let mut grid = Grid::init(1, 2, 3);
+ grid[(0, 0)] = 4;
+ assert_eq!(grid[(0, 0)], 4);
+ }
+
+ #[test]
+ fn size() {
+ let grid = Grid::init(1, 2, 3);
+ assert_eq!(grid.size(), (1, 2));
+ }
+
+ #[test]
+ fn transpose() {
+ let mut grid: Grid<u8> = grid![[1,2,3][4,5,6]];
+ grid.transpose();
+ assert_eq!(grid, grid![[1,4][2,5][3,6]]);
+ }
+
+ #[test]
+ fn fill() {
+ let mut grid: Grid<u8> = grid![[1,2,3][4,5,6]];
+ grid.fill(7);
+ test_grid(&grid, 2, 3, Order::RowMajor, &[7, 7, 7, 7, 7, 7]);
+ }
+
+ #[test]
+ fn fill_with() {
+ let mut grid: Grid<u8> = grid![[1,2,3][4,5,6]];
+ grid.fill_with(Default::default);
+ test_grid(&grid, 2, 3, Order::RowMajor, &[0, 0, 0, 0, 0, 0]);
+ }
+
+ #[test]
+ fn map() {
+ let grid: Grid<u8> = grid![[1,2,3][4,5,6]];
+ let mapped = grid.map(|x| x * 2);
+ test_grid(&mapped, 2, 3, Order::RowMajor, &[2, 4, 6, 8, 10, 12]);
+ }
+
+ #[test]
+ fn map_ref() {
+ let grid: Grid<u8> = grid![[1,2,3][4,5,6]];
+ let mapped = grid.map_ref(|x| *x * 2);
+ test_grid(&mapped, 2, 3, Order::RowMajor, &[2, 4, 6, 8, 10, 12]);
+ }
+
+ #[test]
+ #[allow(clippy::redundant_closure_for_method_calls)]
+ fn iter_rows() {
+ let grid: Grid<u8> = grid![[1,2,3][4,5,6]];
+ let max_by_row: Vec<u8> = grid
+ .iter_rows()
+ .map(|row| row.max().unwrap())
+ .copied()
+ .collect();
+ assert_eq!(max_by_row, vec![3, 6]);
+
+ let sum_by_row: Vec<u8> = grid.iter_rows().map(|row| row.sum()).collect();
+ assert_eq!(sum_by_row, vec![1 + 2 + 3, 4 + 5 + 6]);
+ }
+
+ #[test]
+ #[allow(clippy::redundant_closure_for_method_calls)]
+ fn iter_rows_rev() {
+ let grid: Grid<u8> = grid![[1,2,3][4,5,6]];
+ let max_by_row: Vec<u8> = grid
+ .iter_rows()
+ .rev()
+ .map(|row| row.max().unwrap())
+ .copied()
+ .collect();
+ assert_eq!(max_by_row, vec![6, 3]);
+
+ let sum_by_row: Vec<u8> = grid.iter_rows().rev().map(|row| row.sum()).collect();
+ assert_eq!(sum_by_row, vec![4 + 5 + 6, 1 + 2 + 3]);
+ }
+
+ #[test]
+ fn iter_rows_exact_size() {
+ let grid: Grid<u8> = grid![[1,2,3][4,5,6]];
+ let mut row_iter = grid.iter_rows();
+ assert_eq!(row_iter.len(), 2);
+ assert!(row_iter.next().is_some());
+ assert_eq!(row_iter.len(), 1);
+ assert!(row_iter.next().is_some());
+ assert_eq!(row_iter.len(), 0);
+ assert!(row_iter.next().is_none());
+ }
+
+ #[test]
+ #[allow(clippy::redundant_closure_for_method_calls)]
+ fn iter_cols() {
+ let grid: Grid<u8> = grid![[1,2,3][4,5,6]];
+ let max_by_col: Vec<u8> = grid
+ .iter_cols()
+ .map(|col| col.max().unwrap())
+ .copied()
+ .collect();
+
+ assert_eq!(max_by_col, vec![4, 5, 6]);
+
+ let sum_by_col: Vec<u8> = grid.iter_cols().map(|row| row.sum()).collect();
+ assert_eq!(sum_by_col, vec![1 + 4, 2 + 5, 3 + 6]);
+ }
+
+ #[test]
+ #[allow(clippy::redundant_closure_for_method_calls)]
+ fn iter_cols_rev() {
+ let grid: Grid<u8> = grid![[1,2,3][4,5,6]];
+ let max_by_col: Vec<u8> = grid
+ .iter_cols()
+ .rev()
+ .map(|col| col.max().unwrap())
+ .copied()
+ .collect();
+
+ assert_eq!(max_by_col, vec![6, 5, 4]);
+
+ let sum_by_col: Vec<u8> = grid.iter_cols().rev().map(|row| row.sum()).collect();
+ assert_eq!(sum_by_col, vec![3 + 6, 2 + 5, 1 + 4]);
+ }
+
+ #[test]
+ fn iter_cols_exact_size() {
+ let grid: Grid<u8> = grid![[1,2,3][4,5,6]];
+ let mut col_iter = grid.iter_cols();
+ assert_eq!(col_iter.len(), 3);
+ assert!(col_iter.next().is_some());
+ assert_eq!(col_iter.len(), 2);
+ assert!(col_iter.next().is_some());
+ assert_eq!(col_iter.len(), 1);
+ assert!(col_iter.next().is_some());
+ assert_eq!(col_iter.len(), 0);
+ assert!(col_iter.next().is_none());
+ }
+
+ #[test]
+ fn remove_row() {
+ let mut grid = grid![[1,2][3,4][5,6]];
+ assert_eq![grid.remove_row(1), Some(vec![3, 4])];
+ test_grid(&grid, 2, 2, Order::RowMajor, &[1, 2, 5, 6]);
+ assert_eq![grid.remove_row(0), Some(vec![1, 2])];
+ test_grid(&grid, 1, 2, Order::RowMajor, &[5, 6]);
+ assert_eq![grid.remove_row(0), Some(vec![5, 6])];
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+ assert_eq![grid.remove_row(0), None];
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+ }
+
+ #[test]
+ fn remove_row_out_of_bound() {
+ let mut grid = grid![[1, 2][3, 4]];
+ assert_eq![grid.remove_row(5), None];
+ test_grid(&grid, 2, 2, Order::RowMajor, &[1, 2, 3, 4]);
+ assert_eq![grid.remove_row(1), Some(vec![3, 4])];
+ test_grid(&grid, 1, 2, Order::RowMajor, &[1, 2]);
+ }
+
+ #[test]
+ fn remove_row_column_major() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 3, 5, 2, 4, 6], 2, Order::ColumnMajor);
+ assert_eq![grid.remove_row(1), Some(vec![3, 4])];
+ test_grid(&grid, 2, 2, Order::ColumnMajor, &[1, 5, 2, 6]);
+ assert_eq![grid.remove_row(0), Some(vec![1, 2])];
+ test_grid(&grid, 1, 2, Order::ColumnMajor, &[5, 6]);
+ assert_eq![grid.remove_row(0), Some(vec![5, 6])];
+ test_grid(&grid, 0, 0, Order::ColumnMajor, &[]);
+ assert_eq![grid.remove_row(0), None];
+ test_grid(&grid, 0, 0, Order::ColumnMajor, &[]);
+ }
+
+ #[test]
+ fn remove_row_out_of_bound_column_major() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor);
+ assert_eq![grid.remove_row(5), None];
+ test_grid(&grid, 2, 2, Order::ColumnMajor, &[1, 3, 2, 4]);
+ assert_eq![grid.remove_row(1), Some(vec![3, 4])];
+ test_grid(&grid, 1, 2, Order::ColumnMajor, &[1, 2]);
+ }
+
+ #[test]
+ fn remove_col() {
+ let mut grid = grid![[1,2,3,4][5,6,7,8][9,10,11,12][13,14,15,16]];
+ assert_eq![grid.remove_col(3), Some(vec![4, 8, 12, 16])];
+ let expected = [1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15];
+ test_grid(&grid, 4, 3, Order::RowMajor, &expected);
+ assert_eq![grid.remove_col(0), Some(vec![1, 5, 9, 13])];
+ test_grid(&grid, 4, 2, Order::RowMajor, &[2, 3, 6, 7, 10, 11, 14, 15]);
+ assert_eq![grid.remove_col(1), Some(vec![3, 7, 11, 15])];
+ test_grid(&grid, 4, 1, Order::RowMajor, &[2, 6, 10, 14]);
+ assert_eq![grid.remove_col(0), Some(vec![2, 6, 10, 14])];
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+ assert_eq![grid.remove_col(0), None];
+ test_grid(&grid, 0, 0, Order::RowMajor, &[]);
+ }
+
+ #[test]
+ fn remove_col_out_of_bound() {
+ let mut grid = grid![[1, 2][3, 4]];
+ assert_eq!(grid.remove_col(5), None);
+ test_grid(&grid, 2, 2, Order::RowMajor, &[1, 2, 3, 4]);
+ assert_eq!(grid.remove_col(1), Some(vec![2, 4]));
+ test_grid(&grid, 2, 1, Order::RowMajor, &[1, 3]);
+ }
+
+ #[test]
+ fn remove_col_column_major() {
+ let internal = vec![1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16];
+ let mut grid = Grid::from_vec_with_order(internal, 4, Order::ColumnMajor);
+ assert_eq![grid.remove_col(3), Some(vec![4, 8, 12, 16])];
+ let expected = [1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15];
+ test_grid(&grid, 4, 3, Order::ColumnMajor, &expected);
+ assert_eq![grid.remove_col(0), Some(vec![1, 5, 9, 13])];
+ let expected = [2, 6, 10, 14, 3, 7, 11, 15];
+ test_grid(&grid, 4, 2, Order::ColumnMajor, &expected);
+ assert_eq![grid.remove_col(1), Some(vec![3, 7, 11, 15])];
+ test_grid(&grid, 4, 1, Order::ColumnMajor, &[2, 6, 10, 14]);
+ assert_eq![grid.remove_col(0), Some(vec![2, 6, 10, 14])];
+ test_grid(&grid, 0, 0, Order::ColumnMajor, &[]);
+ assert_eq![grid.remove_col(0), None];
+ test_grid(&grid, 0, 0, Order::ColumnMajor, &[]);
+ }
+
+ #[test]
+ fn remove_col_out_of_bound_column_major() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor);
+ assert_eq!(grid.remove_col(5), None);
+ test_grid(&grid, 2, 2, Order::ColumnMajor, &[1, 3, 2, 4]);
+ assert_eq!(grid.remove_col(1), Some(vec![2, 4]));
+ test_grid(&grid, 2, 1, Order::ColumnMajor, &[1, 3]);
+ }
+
+ #[test]
+ fn flip_cols() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor);
+ grid.flip_cols();
+ test_grid(&grid, 2, 2, Order::RowMajor, &[2, 1, 4, 3]);
+ }
+
+ #[test]
+ fn flip_cols_column_major() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor);
+ grid.flip_cols();
+ test_grid(&grid, 2, 2, Order::ColumnMajor, &[2, 4, 1, 3]);
+ }
+
+ #[test]
+ fn flip_rows() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor);
+ grid.flip_rows();
+ test_grid(&grid, 2, 2, Order::RowMajor, &[3, 4, 1, 2]);
+ }
+
+ #[test]
+ fn flip_rows_column_major() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor);
+ grid.flip_rows();
+ test_grid(&grid, 2, 2, Order::ColumnMajor, &[3, 1, 4, 2]);
+ }
+
+ #[test]
+ fn rotate_left() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor);
+ grid.rotate_left();
+ test_grid(&grid, 3, 2, Order::ColumnMajor, &[3, 2, 1, 6, 5, 4]);
+ assert_eq!(grid, grid![[3,6][2,5][1,4]]);
+ }
+
+ #[test]
+ fn rotate_left_column_major() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor);
+ grid.rotate_left();
+ test_grid(&grid, 3, 2, Order::RowMajor, &[3, 6, 2, 5, 1, 4]);
+ assert_eq!(grid, grid![[3,6][2,5][1,4]]);
+ }
+
+ #[test]
+ fn rotate_right() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor);
+ grid.rotate_right();
+ test_grid(&grid, 3, 2, Order::ColumnMajor, &[4, 5, 6, 1, 2, 3]);
+ assert_eq!(grid, grid![[4,1][5,2][6,3]]);
+ }
+
+ #[test]
+ fn rotate_right_column_major() {
+ let mut grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor);
+ grid.rotate_right();
+ test_grid(&grid, 3, 2, Order::RowMajor, &[4, 1, 5, 2, 6, 3]);
+ assert_eq!(grid, grid![[4,1][5,2][6,3]]);
+ }
+
+ #[test]
+ fn iter_cols_clone() {
+ let grid = grid![[1,2,3][4,5,6]];
+ let mut cols = grid.iter_cols().skip(1);
+ let c3: u8 = cols.clone().nth(1).unwrap().sum();
+ let c2: u8 = cols.next().unwrap().sum();
+ assert_eq!(c2, 2 + 5);
+ assert_eq!(c3, 3 + 6);
+ }
+
+ #[test]
+ fn iter_rows_clone() {
+ let grid = grid![[1,2,3][4,5,6][7,8,9]];
+ let mut rows = grid.iter_rows().skip(1);
+ let r3: u8 = rows.clone().nth(1).unwrap().sum();
+ let r2: u8 = rows.next().unwrap().sum();
+ assert_eq!(r2, 4 + 5 + 6);
+ assert_eq!(r3, 7 + 8 + 9);
+ }
+
+ #[test]
+ fn swap() {
+ let mut grid = grid![[1,2][4,5]];
+ grid.swap((0, 0), (1, 0));
+ let end_grid = grid![[4,2][1,5]];
+ assert_eq!(grid, end_grid);
+ }
+
+ #[test]
+ #[should_panic(expected = "grid index out of bounds: (2,0) out of (2,2)")]
+ fn swap_out_of_bounds() {
+ let mut grid = grid![[1,2][4,5]];
+ grid.swap((0, 0), (2, 0));
+ }
+
+ #[cfg(feature = "serde")]
+ mod serde_tests {
+ use super::*;
+
+ #[test]
+ fn serialize() {
+ let grid: Grid<u8> = grid![[1, 2][3, 4]];
+ let s = serde_json::to_string(&grid).unwrap();
+ assert_eq!(s, r#"{"cols":2,"data":[1,2,3,4],"order":"RowMajor"}"#);
+ }
+
+ #[test]
+ fn deserialize() {
+ let s = "{ \"cols\": 2, \"data\": [1, 2, 3, 4] }";
+ let grid: Grid<u8> = serde_json::from_str(s).unwrap();
+ assert_eq!(grid, grid![[1, 2][3, 4]]);
+ }
+
+ #[test]
+ fn deserialize_with_order() {
+ let s = "{ \"cols\": 2, \"data\": [1, 3, 2, 4], \"order\": \"ColumnMajor\" }";
+ let grid: Grid<u8> = serde_json::from_str(s).unwrap();
+ test_grid(&grid, 2, 2, Order::ColumnMajor, &[1, 3, 2, 4]);
+ }
+ }
+}
diff --git a/pseudo_crate/Cargo.lock b/pseudo_crate/Cargo.lock
index 6fc1d93..6ba88bb 100644
--- a/pseudo_crate/Cargo.lock
+++ b/pseudo_crate/Cargo.lock
@@ -234,6 +234,7 @@
"googletest",
"googletest_macro",
"gpio-cdev",
+ "grid",
"grpcio",
"grpcio-compiler",
"grpcio-sys",
@@ -2560,6 +2561,12 @@
]
[[package]]
+name = "grid"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb6ae361963ea5fe52038156ea1729f3b4e4ccc0711c362ab2b2d2c0a259e7c3"
+
+[[package]]
name = "grpcio"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/pseudo_crate/Cargo.toml b/pseudo_crate/Cargo.toml
index 84d616a..76dbccc 100644
--- a/pseudo_crate/Cargo.toml
+++ b/pseudo_crate/Cargo.toml
@@ -143,6 +143,7 @@
googletest = "=0.13.0"
googletest_macro = "=0.13.0"
gpio-cdev = "=0.6.0"
+grid = "=0.16.1"
grpcio = "=0.13.0"
grpcio-compiler = "=0.13.0"
grpcio-sys = "=0.13.0"
diff --git a/pseudo_crate/crate-list.txt b/pseudo_crate/crate-list.txt
index 0f86736..81eb405 100644
--- a/pseudo_crate/crate-list.txt
+++ b/pseudo_crate/crate-list.txt
@@ -135,6 +135,7 @@
googletest
googletest_macro
gpio-cdev
+grid
grpcio
grpcio-compiler
grpcio-sys