diff --git a/Cargo.lock b/Cargo.lock index e61f3f591945..db1751e1cd7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4542,6 +4542,35 @@ dependencies = [ "thiserror", ] +[[package]] +name = "re_query2" +version = "0.15.0-alpha.5" +dependencies = [ + "ahash", + "anyhow", + "backtrace", + "criterion", + "document-features", + "itertools 0.12.0", + "mimalloc", + "nohash-hasher", + "rand", + "re_arrow2", + "re_data_store", + "re_format", + "re_log", + "re_log_types", + "re_tracing", + "re_tuid", + "re_types", + "re_types_core", + "serde", + "similar-asserts", + "smallvec", + "thiserror", + "unindent", +] + [[package]] name = "re_query_cache" version = "0.15.0-alpha.5" diff --git a/Cargo.toml b/Cargo.toml index e32cc1205c89..da3f2bc69b4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,9 +28,9 @@ version = "0.15.0-alpha.5" # In particular: if we compile rerun 0.3.0-alpha.0 we only want it to use # re_log_types 0.3.0-alpha.0, NOT 0.3.0-alpha.4 even though it is newer and semver-compatible. re_analytics = { path = "crates/re_analytics", version = "=0.15.0-alpha.5", default-features = false } -re_build_search_index = { path = "crates/re_build_search_index", version = "=0.15.0-alpha.5", default-features = false } re_build_examples = { path = "crates/re_build_examples", version = "=0.15.0-alpha.5", default-features = false } re_build_info = { path = "crates/re_build_info", version = "=0.15.0-alpha.5", default-features = false } +re_build_search_index = { path = "crates/re_build_search_index", version = "=0.15.0-alpha.5", default-features = false } re_build_tools = { path = "crates/re_build_tools", version = "=0.15.0-alpha.5", default-features = false } re_build_web_viewer = { path = "crates/re_build_web_viewer", version = "=0.15.0-alpha.5", default-features = false } re_crash_handler = { path = "crates/re_crash_handler", version = "=0.15.0-alpha.5", default-features = false } @@ -46,6 +46,7 @@ re_log_encoding = { path = "crates/re_log_encoding", version = "=0.15.0-alpha.5" re_log_types = { path = "crates/re_log_types", version = "=0.15.0-alpha.5", default-features = false } re_memory = { path = "crates/re_memory", version = "=0.15.0-alpha.5", default-features = false } re_query = { path = "crates/re_query", version = "=0.15.0-alpha.5", default-features = false } +re_query2 = { path = "crates/re_query2", version = "=0.15.0-alpha.5", default-features = false } re_query_cache = { path = "crates/re_query_cache", version = "=0.15.0-alpha.5", default-features = false } re_renderer = { path = "crates/re_renderer", version = "=0.15.0-alpha.5", default-features = false } re_sdk = { path = "crates/re_sdk", version = "=0.15.0-alpha.5", default-features = false } diff --git a/crates/re_query2/Cargo.toml b/crates/re_query2/Cargo.toml new file mode 100644 index 000000000000..6f67f6a8d7dc --- /dev/null +++ b/crates/re_query2/Cargo.toml @@ -0,0 +1,72 @@ +[package] +name = "re_query2" +authors.workspace = true +description = "Temporary crate meant to replace re_query" +edition.workspace = true +homepage.workspace = true +include.workspace = true +license.workspace = true +# TODO(cmc): Replace re_query with this crate. Never publish this one. +publish = false +readme = "README.md" +repository.workspace = true +rust-version.workspace = true +version.workspace = true + +[package.metadata.docs.rs] +all-features = true + + +[features] +default = [] + +## Enable (de)serialization using serde. +serde = ["dep:serde"] + +## Enable codegen helper binaries (generates ClampedZip & RangeZip implementations). +codegen = ["unindent"] + + +[dependencies] +# Rerun dependencies: +re_data_store.workspace = true +re_format = { workspace = true, features = ["arrow"] } +re_log_types.workspace = true +re_types_core.workspace = true +re_log.workspace = true +re_tracing.workspace = true +re_tuid.workspace = true + +# External dependencies: +ahash.workspace = true +anyhow.workspace = true +arrow2.workspace = true +backtrace.workspace = true +document-features.workspace = true +itertools = { workspace = true } +nohash-hasher.workspace = true +serde = { workspace = true, features = ["derive", "rc"], optional = true } +smallvec.workspace = true +thiserror.workspace = true + +# Optional: +unindent = { workspace = true, optional = true } + + +[dev-dependencies] +re_types = { workspace = true, features = ["datagen"] } + +criterion.workspace = true +itertools = { workspace = true } +mimalloc.workspace = true +rand = { workspace = true, features = ["std", "std_rng"] } +similar-asserts.workspace = true + + +[lib] +bench = false + + +[[bin]] +name = "clamped_zip" +required-features = ["codegen"] diff --git a/crates/re_query2/README.md b/crates/re_query2/README.md new file mode 100644 index 000000000000..42bcc981d336 --- /dev/null +++ b/crates/re_query2/README.md @@ -0,0 +1,5 @@ +# re_query2 + +Temporary crate for implementing the new data APIs. Not published. + +Will replace `re_query` when ready. diff --git a/crates/re_query2/src/bin/clamped_zip.rs b/crates/re_query2/src/bin/clamped_zip.rs new file mode 100644 index 000000000000..bb4b642f4ac7 --- /dev/null +++ b/crates/re_query2/src/bin/clamped_zip.rs @@ -0,0 +1,354 @@ +//! CLI tool to generate `ClampedZip` implementations of different arities. + +use itertools::{izip, Itertools}; + +struct Params { + num_required: usize, + num_optional: usize, +} + +impl Params { + fn to_num_required(&self) -> String { + self.num_required.to_string() + } + + fn to_num_optional(&self) -> String { + self.num_optional.to_string() + } + + /// `1x3`, `2x2`… + fn to_suffix(&self) -> String { + format!("{}x{}", self.to_num_required(), self.to_num_optional()) + } + + /// `r0, r1, r2…`. + fn to_required_names(&self) -> Vec { + (0..self.num_required) + .map(|n| format!("r{n}")) + .collect_vec() + } + + /// `R0, R1, R2…`. + fn to_required_types(&self) -> Vec { + self.to_required_names() + .into_iter() + .map(|s| s.to_uppercase()) + .collect() + } + + /// `r0: R0, r1: R1, r2: R2…`. + fn to_required_params(&self) -> Vec { + izip!(self.to_required_names(), self.to_required_types()) + .map(|(n, t)| format!("{n}: {t}")) + .collect() + } + + /// `R0: (Into)Iterator, R1: (Into)Iterator, R2: (Into)Iterator…` + fn to_required_clauses(&self, into: bool) -> Vec { + let trait_name = if into { "IntoIterator" } else { "Iterator" }; + self.to_required_types() + .into_iter() + .map(|t| format!("{t}: {trait_name}")) + .collect() + } + + /// `o0, o1, o2…`. + fn to_optional_names(&self) -> Vec { + (0..self.num_optional) + .map(|n| format!("o{n}")) + .collect_vec() + } + + /// `O0, O1, O2…`. + fn to_optional_types(&self) -> Vec { + self.to_optional_names() + .into_iter() + .map(|s| s.to_uppercase()) + .collect() + } + + /// `o0: O0, o1: O1, o2: O2…`. + fn to_optional_params(&self) -> Vec { + izip!(self.to_optional_names(), self.to_optional_types()) + .map(|(n, t)| format!("{n}: {t}")) + .collect() + } + + /// `O0: IntoIterator, O0::Item: Clone, O1: IntoIterator, O1::Item: Clone…` + fn to_optional_clauses(&self, into: bool) -> Vec { + let trait_name = if into { "IntoIterator" } else { "Iterator" }; + self.to_optional_types() + .into_iter() + .map(|t| format!("{t}: {trait_name}, {t}::Item: Clone")) + .collect() + } + + /// `o0_default_fn, o1_default_fn, o2_default_fn…`. + fn to_optional_fn_names(&self) -> Vec { + (0..self.num_optional) + .map(|n| format!("o{n}_default_fn")) + .collect_vec() + } + + /// `D0, D1, D2…`. + fn to_optional_fn_types(&self) -> Vec { + (0..self.num_optional) + .map(|n| format!("D{n}")) + .collect_vec() + } + + /// `o0_default_fn: D0, o1_default_fn: D1…`. + fn to_optional_fn_params(&self) -> Vec { + izip!(self.to_optional_fn_names(), self.to_optional_fn_types()) + .map(|(n, t)| format!("{n}: {t}")) + .collect() + } + + /// `D0: Fn() -> O0::Item, D1: Fn() -> O1::Item…` + fn to_optional_fn_clauses(&self) -> Vec { + izip!(self.to_optional_fn_types(), self.to_optional_types()) + .map(|(tl, tr)| format!("{tl}: Fn() -> {tr}::Item")) + .collect() + } +} + +fn backticked(strs: impl IntoIterator) -> Vec { + strs.into_iter().map(|s| format!("`{s}`")).collect() +} + +fn generate_helper_func(params: &Params) -> String { + let suffix = params.to_suffix(); + let required_names = backticked(params.to_required_names()).join(", "); + let optional_names = backticked(params.to_optional_names()).join(", "); + let optional_fn_names = backticked(params.to_optional_fn_names()).join(", "); + let required_types = params.to_required_types().join(", "); + let optional_types = params.to_optional_types().join(", "); + let optional_fn_types = params.to_optional_fn_types().join(", "); + let required_clauses = params.to_required_clauses(true /* into */).join(", "); + let optional_clauses = params.to_optional_clauses(true /* into */).join(", "); + let optional_fn_clauses = params.to_optional_fn_clauses().join(", "); + let required_params = params.to_required_params().join(", "); + let optional_params = izip!(params.to_optional_params(), params.to_optional_fn_params()) + .map(|(o, d)| format!("{o}, {d}")) + .collect_vec() + .join(",\n"); + + let ret_clause = params + .to_required_types() + .into_iter() + .map(|r| format!("{r}::IntoIter")) + .chain( + params + .to_optional_types() + .into_iter() + .map(|o| format!("{o}::IntoIter")), + ) + .chain(params.to_optional_fn_types()) + .collect_vec() + .join(", "); + + let ret = params + .to_required_names() + .into_iter() + .map(|r| format!("{r}: {r}.into_iter()")) + .chain( + params + .to_optional_names() + .into_iter() + .map(|o| format!("{o}: {o}.into_iter()")), + ) + .chain(params.to_optional_fn_names()) + .chain( + params + .to_optional_names() + .into_iter() + .map(|o| format!("{o}_latest_value: None")), + ) + .collect_vec() + .join(",\n"); + + format!( + r#" + /// Returns a new [`ClampedZip{suffix}`] iterator. + /// + /// The number of elements in a clamped zip iterator corresponds to the number of elements in the + /// shortest of its required iterators ({required_names}). + /// + /// Optional iterators ({optional_names}) will repeat their latest values if they happen to be too short + /// to be zipped with the shortest of the required iterators. + /// + /// If an optional iterator is not only too short but actually empty, its associated default function + /// ({optional_fn_names}) will be executed and the resulting value repeated as necessary. + pub fn clamped_zip_{suffix}<{required_types}, {optional_types}, {optional_fn_types}>( + {required_params}, + {optional_params}, + ) -> ClampedZip{suffix}<{ret_clause}> + where + {required_clauses}, + {optional_clauses}, + {optional_fn_clauses}, + {{ + ClampedZip{suffix} {{ + {ret} + }} + }} + "# + ) +} + +fn generate_struct(params: &Params) -> String { + let suffix = params.to_suffix(); + let required_types = params.to_required_types().join(", "); + let optional_types = params.to_optional_types().join(", "); + let optional_fn_types = params.to_optional_fn_types().join(", "); + let required_clauses = params.to_required_clauses(false /* into */).join(", "); + let optional_clauses = params.to_optional_clauses(false /* into */).join(", "); + let optional_fn_clauses = params.to_optional_fn_clauses().join(", "); + let required_params = params.to_required_params().join(", "); + let optional_params = params.to_optional_params().join(", "); + let optional_fn_params = params.to_optional_fn_params().join(", "); + + let latest_values = izip!(params.to_optional_names(), params.to_optional_types()) + .map(|(n, t)| format!("{n}_latest_value: Option<{t}::Item>")) + .collect_vec() + .join(",\n"); + + format!( + r#" + /// Implements a clamped zip iterator combinator with 2 required iterators and 2 optional + /// iterators. + /// + /// See [`clamped_zip_{suffix}`] for more information. + pub struct ClampedZip{suffix}<{required_types}, {optional_types}, {optional_fn_types}> + where + {required_clauses}, + {optional_clauses}, + {optional_fn_clauses}, + {{ + {required_params}, + {optional_params}, + {optional_fn_params}, + + {latest_values} + }} + "# + ) +} + +fn generate_impl(params: &Params) -> String { + let suffix = params.to_suffix(); + let required_types = params.to_required_types().join(", "); + let optional_types = params.to_optional_types().join(", "); + let optional_fn_types = params.to_optional_fn_types().join(", "); + let required_clauses = params.to_required_clauses(false /* into */).join(", "); + let optional_clauses = params.to_optional_clauses(false /* into */).join(", "); + let optional_fn_clauses = params.to_optional_fn_clauses().join(", "); + + let items = params + .to_required_types() + .into_iter() + .map(|r| format!("{r}::Item")) + .chain( + params + .to_optional_types() + .into_iter() + .map(|o| format!("{o}::Item")), + ) + .collect_vec() + .join(", "); + + let next = + params + .to_required_names() + .into_iter() + .map(|r| format!("let {r}_next = self.{r}.next()?;")) + .chain(params.to_optional_names().into_iter().map(|o| { + format!("let {o}_next = self.{o}.next().or(self.{o}_latest_value.take());") + })) + .collect_vec() + .join("\n"); + + let update_latest = params + .to_optional_names() + .into_iter() + .map(|o| format!("self.{o}_latest_value = {o}_next.clone();")) + .collect_vec() + .join("\n"); + + let ret = params + .to_required_names() + .into_iter() + .map(|r| format!("{r}_next")) + .chain( + params + .to_optional_names() + .into_iter() + .map(|o| format!("{o}_next.unwrap_or_else(|| (self.{o}_default_fn)())")), + ) + .collect_vec() + .join(",\n"); + + format!( + r#" + impl<{required_types}, {optional_types}, {optional_fn_types}> Iterator for ClampedZip{suffix}<{required_types}, {optional_types}, {optional_fn_types}> + where + {required_clauses}, + {optional_clauses}, + {optional_fn_clauses}, + {{ + type Item = ({items}); + + #[inline] + fn next(&mut self) -> Option {{ + {next} + + {update_latest} + + Some(( + {ret} + )) + }} + }} + "# + ) +} + +fn main() { + let num_required = 1..3; + let num_optional = 1..10; + + let output = num_required + .flat_map(|num_required| { + num_optional + .clone() + .map(move |num_optional| (num_required, num_optional)) + }) + .flat_map(|(num_required, num_optional)| { + let params = Params { + num_required, + num_optional, + }; + + [ + generate_helper_func(¶ms), + generate_struct(¶ms), + generate_impl(¶ms), + ] + }) + .collect_vec() + .join("\n"); + + println!( + " + // This file was generated using `cargo r -p re_query2 --all-features --bin clamped_zip`. + // DO NOT EDIT. + + // --- + + #![allow(clippy::too_many_arguments)] + #![allow(clippy::type_complexity)] + + {output} + " + ); +} diff --git a/crates/re_query2/src/clamped_zip/.gitattributes b/crates/re_query2/src/clamped_zip/.gitattributes new file mode 100644 index 000000000000..30d202506064 --- /dev/null +++ b/crates/re_query2/src/clamped_zip/.gitattributes @@ -0,0 +1 @@ +generated.rs linguist-generated=true diff --git a/crates/re_query2/src/clamped_zip/generated.rs b/crates/re_query2/src/clamped_zip/generated.rs new file mode 100644 index 000000000000..7a5c2222b40a --- /dev/null +++ b/crates/re_query2/src/clamped_zip/generated.rs @@ -0,0 +1,3124 @@ +// This file was generated using `cargo r -p re_query2 --all-features --bin clamped_zip`. +// DO NOT EDIT. + +// --- + +#![allow(clippy::too_many_arguments)] +#![allow(clippy::type_complexity)] + +/// Returns a new [`ClampedZip1x1`] iterator. +/// +/// The number of elements in a clamped zip iterator corresponds to the number of elements in the +/// shortest of its required iterators (`r0`). +/// +/// Optional iterators (`o0`) will repeat their latest values if they happen to be too short +/// to be zipped with the shortest of the required iterators. +/// +/// If an optional iterator is not only too short but actually empty, its associated default function +/// (`o0_default_fn`) will be executed and the resulting value repeated as necessary. +pub fn clamped_zip_1x1( + r0: R0, + o0: O0, + o0_default_fn: D0, +) -> ClampedZip1x1 +where + R0: IntoIterator, + O0: IntoIterator, + O0::Item: Clone, + D0: Fn() -> O0::Item, +{ + ClampedZip1x1 { + r0: r0.into_iter(), + o0: o0.into_iter(), + o0_default_fn, + o0_latest_value: None, + } +} + +/// Implements a clamped zip iterator combinator with 2 required iterators and 2 optional +/// iterators. +/// +/// See [`clamped_zip_1x1`] for more information. +pub struct ClampedZip1x1 +where + R0: Iterator, + O0: Iterator, + O0::Item: Clone, + D0: Fn() -> O0::Item, +{ + r0: R0, + o0: O0, + o0_default_fn: D0, + + o0_latest_value: Option, +} + +impl Iterator for ClampedZip1x1 +where + R0: Iterator, + O0: Iterator, + O0::Item: Clone, + D0: Fn() -> O0::Item, +{ + type Item = (R0::Item, O0::Item); + + #[inline] + fn next(&mut self) -> Option { + let r0_next = self.r0.next()?; + let o0_next = self.o0.next().or(self.o0_latest_value.take()); + + self.o0_latest_value = o0_next.clone(); + + Some((r0_next, o0_next.unwrap_or_else(|| (self.o0_default_fn)()))) + } +} + +/// Returns a new [`ClampedZip1x2`] iterator. +/// +/// The number of elements in a clamped zip iterator corresponds to the number of elements in the +/// shortest of its required iterators (`r0`). +/// +/// Optional iterators (`o0`, `o1`) will repeat their latest values if they happen to be too short +/// to be zipped with the shortest of the required iterators. +/// +/// If an optional iterator is not only too short but actually empty, its associated default function +/// (`o0_default_fn`, `o1_default_fn`) will be executed and the resulting value repeated as necessary. +pub fn clamped_zip_1x2( + r0: R0, + o0: O0, + o0_default_fn: D0, + o1: O1, + o1_default_fn: D1, +) -> ClampedZip1x2 +where + R0: IntoIterator, + O0: IntoIterator, + O0::Item: Clone, + O1: IntoIterator, + O1::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, +{ + ClampedZip1x2 { + r0: r0.into_iter(), + o0: o0.into_iter(), + o1: o1.into_iter(), + o0_default_fn, + o1_default_fn, + o0_latest_value: None, + o1_latest_value: None, + } +} + +/// Implements a clamped zip iterator combinator with 2 required iterators and 2 optional +/// iterators. +/// +/// See [`clamped_zip_1x2`] for more information. +pub struct ClampedZip1x2 +where + R0: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, +{ + r0: R0, + o0: O0, + o1: O1, + o0_default_fn: D0, + o1_default_fn: D1, + + o0_latest_value: Option, + o1_latest_value: Option, +} + +impl Iterator for ClampedZip1x2 +where + R0: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, +{ + type Item = (R0::Item, O0::Item, O1::Item); + + #[inline] + fn next(&mut self) -> Option { + let r0_next = self.r0.next()?; + let o0_next = self.o0.next().or(self.o0_latest_value.take()); + let o1_next = self.o1.next().or(self.o1_latest_value.take()); + + self.o0_latest_value = o0_next.clone(); + self.o1_latest_value = o1_next.clone(); + + Some(( + r0_next, + o0_next.unwrap_or_else(|| (self.o0_default_fn)()), + o1_next.unwrap_or_else(|| (self.o1_default_fn)()), + )) + } +} + +/// Returns a new [`ClampedZip1x3`] iterator. +/// +/// The number of elements in a clamped zip iterator corresponds to the number of elements in the +/// shortest of its required iterators (`r0`). +/// +/// Optional iterators (`o0`, `o1`, `o2`) will repeat their latest values if they happen to be too short +/// to be zipped with the shortest of the required iterators. +/// +/// If an optional iterator is not only too short but actually empty, its associated default function +/// (`o0_default_fn`, `o1_default_fn`, `o2_default_fn`) will be executed and the resulting value repeated as necessary. +pub fn clamped_zip_1x3( + r0: R0, + o0: O0, + o0_default_fn: D0, + o1: O1, + o1_default_fn: D1, + o2: O2, + o2_default_fn: D2, +) -> ClampedZip1x3 +where + R0: IntoIterator, + O0: IntoIterator, + O0::Item: Clone, + O1: IntoIterator, + O1::Item: Clone, + O2: IntoIterator, + O2::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, +{ + ClampedZip1x3 { + r0: r0.into_iter(), + o0: o0.into_iter(), + o1: o1.into_iter(), + o2: o2.into_iter(), + o0_default_fn, + o1_default_fn, + o2_default_fn, + o0_latest_value: None, + o1_latest_value: None, + o2_latest_value: None, + } +} + +/// Implements a clamped zip iterator combinator with 2 required iterators and 2 optional +/// iterators. +/// +/// See [`clamped_zip_1x3`] for more information. +pub struct ClampedZip1x3 +where + R0: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, +{ + r0: R0, + o0: O0, + o1: O1, + o2: O2, + o0_default_fn: D0, + o1_default_fn: D1, + o2_default_fn: D2, + + o0_latest_value: Option, + o1_latest_value: Option, + o2_latest_value: Option, +} + +impl Iterator for ClampedZip1x3 +where + R0: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, +{ + type Item = (R0::Item, O0::Item, O1::Item, O2::Item); + + #[inline] + fn next(&mut self) -> Option { + let r0_next = self.r0.next()?; + let o0_next = self.o0.next().or(self.o0_latest_value.take()); + let o1_next = self.o1.next().or(self.o1_latest_value.take()); + let o2_next = self.o2.next().or(self.o2_latest_value.take()); + + self.o0_latest_value = o0_next.clone(); + self.o1_latest_value = o1_next.clone(); + self.o2_latest_value = o2_next.clone(); + + Some(( + r0_next, + o0_next.unwrap_or_else(|| (self.o0_default_fn)()), + o1_next.unwrap_or_else(|| (self.o1_default_fn)()), + o2_next.unwrap_or_else(|| (self.o2_default_fn)()), + )) + } +} + +/// Returns a new [`ClampedZip1x4`] iterator. +/// +/// The number of elements in a clamped zip iterator corresponds to the number of elements in the +/// shortest of its required iterators (`r0`). +/// +/// Optional iterators (`o0`, `o1`, `o2`, `o3`) will repeat their latest values if they happen to be too short +/// to be zipped with the shortest of the required iterators. +/// +/// If an optional iterator is not only too short but actually empty, its associated default function +/// (`o0_default_fn`, `o1_default_fn`, `o2_default_fn`, `o3_default_fn`) will be executed and the resulting value repeated as necessary. +pub fn clamped_zip_1x4( + r0: R0, + o0: O0, + o0_default_fn: D0, + o1: O1, + o1_default_fn: D1, + o2: O2, + o2_default_fn: D2, + o3: O3, + o3_default_fn: D3, +) -> ClampedZip1x4< + R0::IntoIter, + O0::IntoIter, + O1::IntoIter, + O2::IntoIter, + O3::IntoIter, + D0, + D1, + D2, + D3, +> +where + R0: IntoIterator, + O0: IntoIterator, + O0::Item: Clone, + O1: IntoIterator, + O1::Item: Clone, + O2: IntoIterator, + O2::Item: Clone, + O3: IntoIterator, + O3::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, +{ + ClampedZip1x4 { + r0: r0.into_iter(), + o0: o0.into_iter(), + o1: o1.into_iter(), + o2: o2.into_iter(), + o3: o3.into_iter(), + o0_default_fn, + o1_default_fn, + o2_default_fn, + o3_default_fn, + o0_latest_value: None, + o1_latest_value: None, + o2_latest_value: None, + o3_latest_value: None, + } +} + +/// Implements a clamped zip iterator combinator with 2 required iterators and 2 optional +/// iterators. +/// +/// See [`clamped_zip_1x4`] for more information. +pub struct ClampedZip1x4 +where + R0: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, +{ + r0: R0, + o0: O0, + o1: O1, + o2: O2, + o3: O3, + o0_default_fn: D0, + o1_default_fn: D1, + o2_default_fn: D2, + o3_default_fn: D3, + + o0_latest_value: Option, + o1_latest_value: Option, + o2_latest_value: Option, + o3_latest_value: Option, +} + +impl Iterator + for ClampedZip1x4 +where + R0: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, +{ + type Item = (R0::Item, O0::Item, O1::Item, O2::Item, O3::Item); + + #[inline] + fn next(&mut self) -> Option { + let r0_next = self.r0.next()?; + let o0_next = self.o0.next().or(self.o0_latest_value.take()); + let o1_next = self.o1.next().or(self.o1_latest_value.take()); + let o2_next = self.o2.next().or(self.o2_latest_value.take()); + let o3_next = self.o3.next().or(self.o3_latest_value.take()); + + self.o0_latest_value = o0_next.clone(); + self.o1_latest_value = o1_next.clone(); + self.o2_latest_value = o2_next.clone(); + self.o3_latest_value = o3_next.clone(); + + Some(( + r0_next, + o0_next.unwrap_or_else(|| (self.o0_default_fn)()), + o1_next.unwrap_or_else(|| (self.o1_default_fn)()), + o2_next.unwrap_or_else(|| (self.o2_default_fn)()), + o3_next.unwrap_or_else(|| (self.o3_default_fn)()), + )) + } +} + +/// Returns a new [`ClampedZip1x5`] iterator. +/// +/// The number of elements in a clamped zip iterator corresponds to the number of elements in the +/// shortest of its required iterators (`r0`). +/// +/// Optional iterators (`o0`, `o1`, `o2`, `o3`, `o4`) will repeat their latest values if they happen to be too short +/// to be zipped with the shortest of the required iterators. +/// +/// If an optional iterator is not only too short but actually empty, its associated default function +/// (`o0_default_fn`, `o1_default_fn`, `o2_default_fn`, `o3_default_fn`, `o4_default_fn`) will be executed and the resulting value repeated as necessary. +pub fn clamped_zip_1x5( + r0: R0, + o0: O0, + o0_default_fn: D0, + o1: O1, + o1_default_fn: D1, + o2: O2, + o2_default_fn: D2, + o3: O3, + o3_default_fn: D3, + o4: O4, + o4_default_fn: D4, +) -> ClampedZip1x5< + R0::IntoIter, + O0::IntoIter, + O1::IntoIter, + O2::IntoIter, + O3::IntoIter, + O4::IntoIter, + D0, + D1, + D2, + D3, + D4, +> +where + R0: IntoIterator, + O0: IntoIterator, + O0::Item: Clone, + O1: IntoIterator, + O1::Item: Clone, + O2: IntoIterator, + O2::Item: Clone, + O3: IntoIterator, + O3::Item: Clone, + O4: IntoIterator, + O4::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, +{ + ClampedZip1x5 { + r0: r0.into_iter(), + o0: o0.into_iter(), + o1: o1.into_iter(), + o2: o2.into_iter(), + o3: o3.into_iter(), + o4: o4.into_iter(), + o0_default_fn, + o1_default_fn, + o2_default_fn, + o3_default_fn, + o4_default_fn, + o0_latest_value: None, + o1_latest_value: None, + o2_latest_value: None, + o3_latest_value: None, + o4_latest_value: None, + } +} + +/// Implements a clamped zip iterator combinator with 2 required iterators and 2 optional +/// iterators. +/// +/// See [`clamped_zip_1x5`] for more information. +pub struct ClampedZip1x5 +where + R0: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + O4: Iterator, + O4::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, +{ + r0: R0, + o0: O0, + o1: O1, + o2: O2, + o3: O3, + o4: O4, + o0_default_fn: D0, + o1_default_fn: D1, + o2_default_fn: D2, + o3_default_fn: D3, + o4_default_fn: D4, + + o0_latest_value: Option, + o1_latest_value: Option, + o2_latest_value: Option, + o3_latest_value: Option, + o4_latest_value: Option, +} + +impl Iterator + for ClampedZip1x5 +where + R0: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + O4: Iterator, + O4::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, +{ + type Item = (R0::Item, O0::Item, O1::Item, O2::Item, O3::Item, O4::Item); + + #[inline] + fn next(&mut self) -> Option { + let r0_next = self.r0.next()?; + let o0_next = self.o0.next().or(self.o0_latest_value.take()); + let o1_next = self.o1.next().or(self.o1_latest_value.take()); + let o2_next = self.o2.next().or(self.o2_latest_value.take()); + let o3_next = self.o3.next().or(self.o3_latest_value.take()); + let o4_next = self.o4.next().or(self.o4_latest_value.take()); + + self.o0_latest_value = o0_next.clone(); + self.o1_latest_value = o1_next.clone(); + self.o2_latest_value = o2_next.clone(); + self.o3_latest_value = o3_next.clone(); + self.o4_latest_value = o4_next.clone(); + + Some(( + r0_next, + o0_next.unwrap_or_else(|| (self.o0_default_fn)()), + o1_next.unwrap_or_else(|| (self.o1_default_fn)()), + o2_next.unwrap_or_else(|| (self.o2_default_fn)()), + o3_next.unwrap_or_else(|| (self.o3_default_fn)()), + o4_next.unwrap_or_else(|| (self.o4_default_fn)()), + )) + } +} + +/// Returns a new [`ClampedZip1x6`] iterator. +/// +/// The number of elements in a clamped zip iterator corresponds to the number of elements in the +/// shortest of its required iterators (`r0`). +/// +/// Optional iterators (`o0`, `o1`, `o2`, `o3`, `o4`, `o5`) will repeat their latest values if they happen to be too short +/// to be zipped with the shortest of the required iterators. +/// +/// If an optional iterator is not only too short but actually empty, its associated default function +/// (`o0_default_fn`, `o1_default_fn`, `o2_default_fn`, `o3_default_fn`, `o4_default_fn`, `o5_default_fn`) will be executed and the resulting value repeated as necessary. +pub fn clamped_zip_1x6( + r0: R0, + o0: O0, + o0_default_fn: D0, + o1: O1, + o1_default_fn: D1, + o2: O2, + o2_default_fn: D2, + o3: O3, + o3_default_fn: D3, + o4: O4, + o4_default_fn: D4, + o5: O5, + o5_default_fn: D5, +) -> ClampedZip1x6< + R0::IntoIter, + O0::IntoIter, + O1::IntoIter, + O2::IntoIter, + O3::IntoIter, + O4::IntoIter, + O5::IntoIter, + D0, + D1, + D2, + D3, + D4, + D5, +> +where + R0: IntoIterator, + O0: IntoIterator, + O0::Item: Clone, + O1: IntoIterator, + O1::Item: Clone, + O2: IntoIterator, + O2::Item: Clone, + O3: IntoIterator, + O3::Item: Clone, + O4: IntoIterator, + O4::Item: Clone, + O5: IntoIterator, + O5::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, +{ + ClampedZip1x6 { + r0: r0.into_iter(), + o0: o0.into_iter(), + o1: o1.into_iter(), + o2: o2.into_iter(), + o3: o3.into_iter(), + o4: o4.into_iter(), + o5: o5.into_iter(), + o0_default_fn, + o1_default_fn, + o2_default_fn, + o3_default_fn, + o4_default_fn, + o5_default_fn, + o0_latest_value: None, + o1_latest_value: None, + o2_latest_value: None, + o3_latest_value: None, + o4_latest_value: None, + o5_latest_value: None, + } +} + +/// Implements a clamped zip iterator combinator with 2 required iterators and 2 optional +/// iterators. +/// +/// See [`clamped_zip_1x6`] for more information. +pub struct ClampedZip1x6 +where + R0: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + O4: Iterator, + O4::Item: Clone, + O5: Iterator, + O5::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, +{ + r0: R0, + o0: O0, + o1: O1, + o2: O2, + o3: O3, + o4: O4, + o5: O5, + o0_default_fn: D0, + o1_default_fn: D1, + o2_default_fn: D2, + o3_default_fn: D3, + o4_default_fn: D4, + o5_default_fn: D5, + + o0_latest_value: Option, + o1_latest_value: Option, + o2_latest_value: Option, + o3_latest_value: Option, + o4_latest_value: Option, + o5_latest_value: Option, +} + +impl Iterator + for ClampedZip1x6 +where + R0: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + O4: Iterator, + O4::Item: Clone, + O5: Iterator, + O5::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, +{ + type Item = ( + R0::Item, + O0::Item, + O1::Item, + O2::Item, + O3::Item, + O4::Item, + O5::Item, + ); + + #[inline] + fn next(&mut self) -> Option { + let r0_next = self.r0.next()?; + let o0_next = self.o0.next().or(self.o0_latest_value.take()); + let o1_next = self.o1.next().or(self.o1_latest_value.take()); + let o2_next = self.o2.next().or(self.o2_latest_value.take()); + let o3_next = self.o3.next().or(self.o3_latest_value.take()); + let o4_next = self.o4.next().or(self.o4_latest_value.take()); + let o5_next = self.o5.next().or(self.o5_latest_value.take()); + + self.o0_latest_value = o0_next.clone(); + self.o1_latest_value = o1_next.clone(); + self.o2_latest_value = o2_next.clone(); + self.o3_latest_value = o3_next.clone(); + self.o4_latest_value = o4_next.clone(); + self.o5_latest_value = o5_next.clone(); + + Some(( + r0_next, + o0_next.unwrap_or_else(|| (self.o0_default_fn)()), + o1_next.unwrap_or_else(|| (self.o1_default_fn)()), + o2_next.unwrap_or_else(|| (self.o2_default_fn)()), + o3_next.unwrap_or_else(|| (self.o3_default_fn)()), + o4_next.unwrap_or_else(|| (self.o4_default_fn)()), + o5_next.unwrap_or_else(|| (self.o5_default_fn)()), + )) + } +} + +/// Returns a new [`ClampedZip1x7`] iterator. +/// +/// The number of elements in a clamped zip iterator corresponds to the number of elements in the +/// shortest of its required iterators (`r0`). +/// +/// Optional iterators (`o0`, `o1`, `o2`, `o3`, `o4`, `o5`, `o6`) will repeat their latest values if they happen to be too short +/// to be zipped with the shortest of the required iterators. +/// +/// If an optional iterator is not only too short but actually empty, its associated default function +/// (`o0_default_fn`, `o1_default_fn`, `o2_default_fn`, `o3_default_fn`, `o4_default_fn`, `o5_default_fn`, `o6_default_fn`) will be executed and the resulting value repeated as necessary. +pub fn clamped_zip_1x7( + r0: R0, + o0: O0, + o0_default_fn: D0, + o1: O1, + o1_default_fn: D1, + o2: O2, + o2_default_fn: D2, + o3: O3, + o3_default_fn: D3, + o4: O4, + o4_default_fn: D4, + o5: O5, + o5_default_fn: D5, + o6: O6, + o6_default_fn: D6, +) -> ClampedZip1x7< + R0::IntoIter, + O0::IntoIter, + O1::IntoIter, + O2::IntoIter, + O3::IntoIter, + O4::IntoIter, + O5::IntoIter, + O6::IntoIter, + D0, + D1, + D2, + D3, + D4, + D5, + D6, +> +where + R0: IntoIterator, + O0: IntoIterator, + O0::Item: Clone, + O1: IntoIterator, + O1::Item: Clone, + O2: IntoIterator, + O2::Item: Clone, + O3: IntoIterator, + O3::Item: Clone, + O4: IntoIterator, + O4::Item: Clone, + O5: IntoIterator, + O5::Item: Clone, + O6: IntoIterator, + O6::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, + D6: Fn() -> O6::Item, +{ + ClampedZip1x7 { + r0: r0.into_iter(), + o0: o0.into_iter(), + o1: o1.into_iter(), + o2: o2.into_iter(), + o3: o3.into_iter(), + o4: o4.into_iter(), + o5: o5.into_iter(), + o6: o6.into_iter(), + o0_default_fn, + o1_default_fn, + o2_default_fn, + o3_default_fn, + o4_default_fn, + o5_default_fn, + o6_default_fn, + o0_latest_value: None, + o1_latest_value: None, + o2_latest_value: None, + o3_latest_value: None, + o4_latest_value: None, + o5_latest_value: None, + o6_latest_value: None, + } +} + +/// Implements a clamped zip iterator combinator with 2 required iterators and 2 optional +/// iterators. +/// +/// See [`clamped_zip_1x7`] for more information. +pub struct ClampedZip1x7 +where + R0: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + O4: Iterator, + O4::Item: Clone, + O5: Iterator, + O5::Item: Clone, + O6: Iterator, + O6::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, + D6: Fn() -> O6::Item, +{ + r0: R0, + o0: O0, + o1: O1, + o2: O2, + o3: O3, + o4: O4, + o5: O5, + o6: O6, + o0_default_fn: D0, + o1_default_fn: D1, + o2_default_fn: D2, + o3_default_fn: D3, + o4_default_fn: D4, + o5_default_fn: D5, + o6_default_fn: D6, + + o0_latest_value: Option, + o1_latest_value: Option, + o2_latest_value: Option, + o3_latest_value: Option, + o4_latest_value: Option, + o5_latest_value: Option, + o6_latest_value: Option, +} + +impl Iterator + for ClampedZip1x7 +where + R0: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + O4: Iterator, + O4::Item: Clone, + O5: Iterator, + O5::Item: Clone, + O6: Iterator, + O6::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, + D6: Fn() -> O6::Item, +{ + type Item = ( + R0::Item, + O0::Item, + O1::Item, + O2::Item, + O3::Item, + O4::Item, + O5::Item, + O6::Item, + ); + + #[inline] + fn next(&mut self) -> Option { + let r0_next = self.r0.next()?; + let o0_next = self.o0.next().or(self.o0_latest_value.take()); + let o1_next = self.o1.next().or(self.o1_latest_value.take()); + let o2_next = self.o2.next().or(self.o2_latest_value.take()); + let o3_next = self.o3.next().or(self.o3_latest_value.take()); + let o4_next = self.o4.next().or(self.o4_latest_value.take()); + let o5_next = self.o5.next().or(self.o5_latest_value.take()); + let o6_next = self.o6.next().or(self.o6_latest_value.take()); + + self.o0_latest_value = o0_next.clone(); + self.o1_latest_value = o1_next.clone(); + self.o2_latest_value = o2_next.clone(); + self.o3_latest_value = o3_next.clone(); + self.o4_latest_value = o4_next.clone(); + self.o5_latest_value = o5_next.clone(); + self.o6_latest_value = o6_next.clone(); + + Some(( + r0_next, + o0_next.unwrap_or_else(|| (self.o0_default_fn)()), + o1_next.unwrap_or_else(|| (self.o1_default_fn)()), + o2_next.unwrap_or_else(|| (self.o2_default_fn)()), + o3_next.unwrap_or_else(|| (self.o3_default_fn)()), + o4_next.unwrap_or_else(|| (self.o4_default_fn)()), + o5_next.unwrap_or_else(|| (self.o5_default_fn)()), + o6_next.unwrap_or_else(|| (self.o6_default_fn)()), + )) + } +} + +/// Returns a new [`ClampedZip1x8`] iterator. +/// +/// The number of elements in a clamped zip iterator corresponds to the number of elements in the +/// shortest of its required iterators (`r0`). +/// +/// Optional iterators (`o0`, `o1`, `o2`, `o3`, `o4`, `o5`, `o6`, `o7`) will repeat their latest values if they happen to be too short +/// to be zipped with the shortest of the required iterators. +/// +/// If an optional iterator is not only too short but actually empty, its associated default function +/// (`o0_default_fn`, `o1_default_fn`, `o2_default_fn`, `o3_default_fn`, `o4_default_fn`, `o5_default_fn`, `o6_default_fn`, `o7_default_fn`) will be executed and the resulting value repeated as necessary. +pub fn clamped_zip_1x8( + r0: R0, + o0: O0, + o0_default_fn: D0, + o1: O1, + o1_default_fn: D1, + o2: O2, + o2_default_fn: D2, + o3: O3, + o3_default_fn: D3, + o4: O4, + o4_default_fn: D4, + o5: O5, + o5_default_fn: D5, + o6: O6, + o6_default_fn: D6, + o7: O7, + o7_default_fn: D7, +) -> ClampedZip1x8< + R0::IntoIter, + O0::IntoIter, + O1::IntoIter, + O2::IntoIter, + O3::IntoIter, + O4::IntoIter, + O5::IntoIter, + O6::IntoIter, + O7::IntoIter, + D0, + D1, + D2, + D3, + D4, + D5, + D6, + D7, +> +where + R0: IntoIterator, + O0: IntoIterator, + O0::Item: Clone, + O1: IntoIterator, + O1::Item: Clone, + O2: IntoIterator, + O2::Item: Clone, + O3: IntoIterator, + O3::Item: Clone, + O4: IntoIterator, + O4::Item: Clone, + O5: IntoIterator, + O5::Item: Clone, + O6: IntoIterator, + O6::Item: Clone, + O7: IntoIterator, + O7::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, + D6: Fn() -> O6::Item, + D7: Fn() -> O7::Item, +{ + ClampedZip1x8 { + r0: r0.into_iter(), + o0: o0.into_iter(), + o1: o1.into_iter(), + o2: o2.into_iter(), + o3: o3.into_iter(), + o4: o4.into_iter(), + o5: o5.into_iter(), + o6: o6.into_iter(), + o7: o7.into_iter(), + o0_default_fn, + o1_default_fn, + o2_default_fn, + o3_default_fn, + o4_default_fn, + o5_default_fn, + o6_default_fn, + o7_default_fn, + o0_latest_value: None, + o1_latest_value: None, + o2_latest_value: None, + o3_latest_value: None, + o4_latest_value: None, + o5_latest_value: None, + o6_latest_value: None, + o7_latest_value: None, + } +} + +/// Implements a clamped zip iterator combinator with 2 required iterators and 2 optional +/// iterators. +/// +/// See [`clamped_zip_1x8`] for more information. +pub struct ClampedZip1x8 +where + R0: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + O4: Iterator, + O4::Item: Clone, + O5: Iterator, + O5::Item: Clone, + O6: Iterator, + O6::Item: Clone, + O7: Iterator, + O7::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, + D6: Fn() -> O6::Item, + D7: Fn() -> O7::Item, +{ + r0: R0, + o0: O0, + o1: O1, + o2: O2, + o3: O3, + o4: O4, + o5: O5, + o6: O6, + o7: O7, + o0_default_fn: D0, + o1_default_fn: D1, + o2_default_fn: D2, + o3_default_fn: D3, + o4_default_fn: D4, + o5_default_fn: D5, + o6_default_fn: D6, + o7_default_fn: D7, + + o0_latest_value: Option, + o1_latest_value: Option, + o2_latest_value: Option, + o3_latest_value: Option, + o4_latest_value: Option, + o5_latest_value: Option, + o6_latest_value: Option, + o7_latest_value: Option, +} + +impl Iterator + for ClampedZip1x8 +where + R0: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + O4: Iterator, + O4::Item: Clone, + O5: Iterator, + O5::Item: Clone, + O6: Iterator, + O6::Item: Clone, + O7: Iterator, + O7::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, + D6: Fn() -> O6::Item, + D7: Fn() -> O7::Item, +{ + type Item = ( + R0::Item, + O0::Item, + O1::Item, + O2::Item, + O3::Item, + O4::Item, + O5::Item, + O6::Item, + O7::Item, + ); + + #[inline] + fn next(&mut self) -> Option { + let r0_next = self.r0.next()?; + let o0_next = self.o0.next().or(self.o0_latest_value.take()); + let o1_next = self.o1.next().or(self.o1_latest_value.take()); + let o2_next = self.o2.next().or(self.o2_latest_value.take()); + let o3_next = self.o3.next().or(self.o3_latest_value.take()); + let o4_next = self.o4.next().or(self.o4_latest_value.take()); + let o5_next = self.o5.next().or(self.o5_latest_value.take()); + let o6_next = self.o6.next().or(self.o6_latest_value.take()); + let o7_next = self.o7.next().or(self.o7_latest_value.take()); + + self.o0_latest_value = o0_next.clone(); + self.o1_latest_value = o1_next.clone(); + self.o2_latest_value = o2_next.clone(); + self.o3_latest_value = o3_next.clone(); + self.o4_latest_value = o4_next.clone(); + self.o5_latest_value = o5_next.clone(); + self.o6_latest_value = o6_next.clone(); + self.o7_latest_value = o7_next.clone(); + + Some(( + r0_next, + o0_next.unwrap_or_else(|| (self.o0_default_fn)()), + o1_next.unwrap_or_else(|| (self.o1_default_fn)()), + o2_next.unwrap_or_else(|| (self.o2_default_fn)()), + o3_next.unwrap_or_else(|| (self.o3_default_fn)()), + o4_next.unwrap_or_else(|| (self.o4_default_fn)()), + o5_next.unwrap_or_else(|| (self.o5_default_fn)()), + o6_next.unwrap_or_else(|| (self.o6_default_fn)()), + o7_next.unwrap_or_else(|| (self.o7_default_fn)()), + )) + } +} + +/// Returns a new [`ClampedZip1x9`] iterator. +/// +/// The number of elements in a clamped zip iterator corresponds to the number of elements in the +/// shortest of its required iterators (`r0`). +/// +/// Optional iterators (`o0`, `o1`, `o2`, `o3`, `o4`, `o5`, `o6`, `o7`, `o8`) will repeat their latest values if they happen to be too short +/// to be zipped with the shortest of the required iterators. +/// +/// If an optional iterator is not only too short but actually empty, its associated default function +/// (`o0_default_fn`, `o1_default_fn`, `o2_default_fn`, `o3_default_fn`, `o4_default_fn`, `o5_default_fn`, `o6_default_fn`, `o7_default_fn`, `o8_default_fn`) will be executed and the resulting value repeated as necessary. +pub fn clamped_zip_1x9( + r0: R0, + o0: O0, + o0_default_fn: D0, + o1: O1, + o1_default_fn: D1, + o2: O2, + o2_default_fn: D2, + o3: O3, + o3_default_fn: D3, + o4: O4, + o4_default_fn: D4, + o5: O5, + o5_default_fn: D5, + o6: O6, + o6_default_fn: D6, + o7: O7, + o7_default_fn: D7, + o8: O8, + o8_default_fn: D8, +) -> ClampedZip1x9< + R0::IntoIter, + O0::IntoIter, + O1::IntoIter, + O2::IntoIter, + O3::IntoIter, + O4::IntoIter, + O5::IntoIter, + O6::IntoIter, + O7::IntoIter, + O8::IntoIter, + D0, + D1, + D2, + D3, + D4, + D5, + D6, + D7, + D8, +> +where + R0: IntoIterator, + O0: IntoIterator, + O0::Item: Clone, + O1: IntoIterator, + O1::Item: Clone, + O2: IntoIterator, + O2::Item: Clone, + O3: IntoIterator, + O3::Item: Clone, + O4: IntoIterator, + O4::Item: Clone, + O5: IntoIterator, + O5::Item: Clone, + O6: IntoIterator, + O6::Item: Clone, + O7: IntoIterator, + O7::Item: Clone, + O8: IntoIterator, + O8::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, + D6: Fn() -> O6::Item, + D7: Fn() -> O7::Item, + D8: Fn() -> O8::Item, +{ + ClampedZip1x9 { + r0: r0.into_iter(), + o0: o0.into_iter(), + o1: o1.into_iter(), + o2: o2.into_iter(), + o3: o3.into_iter(), + o4: o4.into_iter(), + o5: o5.into_iter(), + o6: o6.into_iter(), + o7: o7.into_iter(), + o8: o8.into_iter(), + o0_default_fn, + o1_default_fn, + o2_default_fn, + o3_default_fn, + o4_default_fn, + o5_default_fn, + o6_default_fn, + o7_default_fn, + o8_default_fn, + o0_latest_value: None, + o1_latest_value: None, + o2_latest_value: None, + o3_latest_value: None, + o4_latest_value: None, + o5_latest_value: None, + o6_latest_value: None, + o7_latest_value: None, + o8_latest_value: None, + } +} + +/// Implements a clamped zip iterator combinator with 2 required iterators and 2 optional +/// iterators. +/// +/// See [`clamped_zip_1x9`] for more information. +pub struct ClampedZip1x9 +where + R0: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + O4: Iterator, + O4::Item: Clone, + O5: Iterator, + O5::Item: Clone, + O6: Iterator, + O6::Item: Clone, + O7: Iterator, + O7::Item: Clone, + O8: Iterator, + O8::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, + D6: Fn() -> O6::Item, + D7: Fn() -> O7::Item, + D8: Fn() -> O8::Item, +{ + r0: R0, + o0: O0, + o1: O1, + o2: O2, + o3: O3, + o4: O4, + o5: O5, + o6: O6, + o7: O7, + o8: O8, + o0_default_fn: D0, + o1_default_fn: D1, + o2_default_fn: D2, + o3_default_fn: D3, + o4_default_fn: D4, + o5_default_fn: D5, + o6_default_fn: D6, + o7_default_fn: D7, + o8_default_fn: D8, + + o0_latest_value: Option, + o1_latest_value: Option, + o2_latest_value: Option, + o3_latest_value: Option, + o4_latest_value: Option, + o5_latest_value: Option, + o6_latest_value: Option, + o7_latest_value: Option, + o8_latest_value: Option, +} + +impl Iterator + for ClampedZip1x9 +where + R0: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + O4: Iterator, + O4::Item: Clone, + O5: Iterator, + O5::Item: Clone, + O6: Iterator, + O6::Item: Clone, + O7: Iterator, + O7::Item: Clone, + O8: Iterator, + O8::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, + D6: Fn() -> O6::Item, + D7: Fn() -> O7::Item, + D8: Fn() -> O8::Item, +{ + type Item = ( + R0::Item, + O0::Item, + O1::Item, + O2::Item, + O3::Item, + O4::Item, + O5::Item, + O6::Item, + O7::Item, + O8::Item, + ); + + #[inline] + fn next(&mut self) -> Option { + let r0_next = self.r0.next()?; + let o0_next = self.o0.next().or(self.o0_latest_value.take()); + let o1_next = self.o1.next().or(self.o1_latest_value.take()); + let o2_next = self.o2.next().or(self.o2_latest_value.take()); + let o3_next = self.o3.next().or(self.o3_latest_value.take()); + let o4_next = self.o4.next().or(self.o4_latest_value.take()); + let o5_next = self.o5.next().or(self.o5_latest_value.take()); + let o6_next = self.o6.next().or(self.o6_latest_value.take()); + let o7_next = self.o7.next().or(self.o7_latest_value.take()); + let o8_next = self.o8.next().or(self.o8_latest_value.take()); + + self.o0_latest_value = o0_next.clone(); + self.o1_latest_value = o1_next.clone(); + self.o2_latest_value = o2_next.clone(); + self.o3_latest_value = o3_next.clone(); + self.o4_latest_value = o4_next.clone(); + self.o5_latest_value = o5_next.clone(); + self.o6_latest_value = o6_next.clone(); + self.o7_latest_value = o7_next.clone(); + self.o8_latest_value = o8_next.clone(); + + Some(( + r0_next, + o0_next.unwrap_or_else(|| (self.o0_default_fn)()), + o1_next.unwrap_or_else(|| (self.o1_default_fn)()), + o2_next.unwrap_or_else(|| (self.o2_default_fn)()), + o3_next.unwrap_or_else(|| (self.o3_default_fn)()), + o4_next.unwrap_or_else(|| (self.o4_default_fn)()), + o5_next.unwrap_or_else(|| (self.o5_default_fn)()), + o6_next.unwrap_or_else(|| (self.o6_default_fn)()), + o7_next.unwrap_or_else(|| (self.o7_default_fn)()), + o8_next.unwrap_or_else(|| (self.o8_default_fn)()), + )) + } +} + +/// Returns a new [`ClampedZip2x1`] iterator. +/// +/// The number of elements in a clamped zip iterator corresponds to the number of elements in the +/// shortest of its required iterators (`r0`, `r1`). +/// +/// Optional iterators (`o0`) will repeat their latest values if they happen to be too short +/// to be zipped with the shortest of the required iterators. +/// +/// If an optional iterator is not only too short but actually empty, its associated default function +/// (`o0_default_fn`) will be executed and the resulting value repeated as necessary. +pub fn clamped_zip_2x1( + r0: R0, + r1: R1, + o0: O0, + o0_default_fn: D0, +) -> ClampedZip2x1 +where + R0: IntoIterator, + R1: IntoIterator, + O0: IntoIterator, + O0::Item: Clone, + D0: Fn() -> O0::Item, +{ + ClampedZip2x1 { + r0: r0.into_iter(), + r1: r1.into_iter(), + o0: o0.into_iter(), + o0_default_fn, + o0_latest_value: None, + } +} + +/// Implements a clamped zip iterator combinator with 2 required iterators and 2 optional +/// iterators. +/// +/// See [`clamped_zip_2x1`] for more information. +pub struct ClampedZip2x1 +where + R0: Iterator, + R1: Iterator, + O0: Iterator, + O0::Item: Clone, + D0: Fn() -> O0::Item, +{ + r0: R0, + r1: R1, + o0: O0, + o0_default_fn: D0, + + o0_latest_value: Option, +} + +impl Iterator for ClampedZip2x1 +where + R0: Iterator, + R1: Iterator, + O0: Iterator, + O0::Item: Clone, + D0: Fn() -> O0::Item, +{ + type Item = (R0::Item, R1::Item, O0::Item); + + #[inline] + fn next(&mut self) -> Option { + let r0_next = self.r0.next()?; + let r1_next = self.r1.next()?; + let o0_next = self.o0.next().or(self.o0_latest_value.take()); + + self.o0_latest_value = o0_next.clone(); + + Some(( + r0_next, + r1_next, + o0_next.unwrap_or_else(|| (self.o0_default_fn)()), + )) + } +} + +/// Returns a new [`ClampedZip2x2`] iterator. +/// +/// The number of elements in a clamped zip iterator corresponds to the number of elements in the +/// shortest of its required iterators (`r0`, `r1`). +/// +/// Optional iterators (`o0`, `o1`) will repeat their latest values if they happen to be too short +/// to be zipped with the shortest of the required iterators. +/// +/// If an optional iterator is not only too short but actually empty, its associated default function +/// (`o0_default_fn`, `o1_default_fn`) will be executed and the resulting value repeated as necessary. +pub fn clamped_zip_2x2( + r0: R0, + r1: R1, + o0: O0, + o0_default_fn: D0, + o1: O1, + o1_default_fn: D1, +) -> ClampedZip2x2 +where + R0: IntoIterator, + R1: IntoIterator, + O0: IntoIterator, + O0::Item: Clone, + O1: IntoIterator, + O1::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, +{ + ClampedZip2x2 { + r0: r0.into_iter(), + r1: r1.into_iter(), + o0: o0.into_iter(), + o1: o1.into_iter(), + o0_default_fn, + o1_default_fn, + o0_latest_value: None, + o1_latest_value: None, + } +} + +/// Implements a clamped zip iterator combinator with 2 required iterators and 2 optional +/// iterators. +/// +/// See [`clamped_zip_2x2`] for more information. +pub struct ClampedZip2x2 +where + R0: Iterator, + R1: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, +{ + r0: R0, + r1: R1, + o0: O0, + o1: O1, + o0_default_fn: D0, + o1_default_fn: D1, + + o0_latest_value: Option, + o1_latest_value: Option, +} + +impl Iterator for ClampedZip2x2 +where + R0: Iterator, + R1: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, +{ + type Item = (R0::Item, R1::Item, O0::Item, O1::Item); + + #[inline] + fn next(&mut self) -> Option { + let r0_next = self.r0.next()?; + let r1_next = self.r1.next()?; + let o0_next = self.o0.next().or(self.o0_latest_value.take()); + let o1_next = self.o1.next().or(self.o1_latest_value.take()); + + self.o0_latest_value = o0_next.clone(); + self.o1_latest_value = o1_next.clone(); + + Some(( + r0_next, + r1_next, + o0_next.unwrap_or_else(|| (self.o0_default_fn)()), + o1_next.unwrap_or_else(|| (self.o1_default_fn)()), + )) + } +} + +/// Returns a new [`ClampedZip2x3`] iterator. +/// +/// The number of elements in a clamped zip iterator corresponds to the number of elements in the +/// shortest of its required iterators (`r0`, `r1`). +/// +/// Optional iterators (`o0`, `o1`, `o2`) will repeat their latest values if they happen to be too short +/// to be zipped with the shortest of the required iterators. +/// +/// If an optional iterator is not only too short but actually empty, its associated default function +/// (`o0_default_fn`, `o1_default_fn`, `o2_default_fn`) will be executed and the resulting value repeated as necessary. +pub fn clamped_zip_2x3( + r0: R0, + r1: R1, + o0: O0, + o0_default_fn: D0, + o1: O1, + o1_default_fn: D1, + o2: O2, + o2_default_fn: D2, +) -> ClampedZip2x3 +where + R0: IntoIterator, + R1: IntoIterator, + O0: IntoIterator, + O0::Item: Clone, + O1: IntoIterator, + O1::Item: Clone, + O2: IntoIterator, + O2::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, +{ + ClampedZip2x3 { + r0: r0.into_iter(), + r1: r1.into_iter(), + o0: o0.into_iter(), + o1: o1.into_iter(), + o2: o2.into_iter(), + o0_default_fn, + o1_default_fn, + o2_default_fn, + o0_latest_value: None, + o1_latest_value: None, + o2_latest_value: None, + } +} + +/// Implements a clamped zip iterator combinator with 2 required iterators and 2 optional +/// iterators. +/// +/// See [`clamped_zip_2x3`] for more information. +pub struct ClampedZip2x3 +where + R0: Iterator, + R1: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, +{ + r0: R0, + r1: R1, + o0: O0, + o1: O1, + o2: O2, + o0_default_fn: D0, + o1_default_fn: D1, + o2_default_fn: D2, + + o0_latest_value: Option, + o1_latest_value: Option, + o2_latest_value: Option, +} + +impl Iterator for ClampedZip2x3 +where + R0: Iterator, + R1: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, +{ + type Item = (R0::Item, R1::Item, O0::Item, O1::Item, O2::Item); + + #[inline] + fn next(&mut self) -> Option { + let r0_next = self.r0.next()?; + let r1_next = self.r1.next()?; + let o0_next = self.o0.next().or(self.o0_latest_value.take()); + let o1_next = self.o1.next().or(self.o1_latest_value.take()); + let o2_next = self.o2.next().or(self.o2_latest_value.take()); + + self.o0_latest_value = o0_next.clone(); + self.o1_latest_value = o1_next.clone(); + self.o2_latest_value = o2_next.clone(); + + Some(( + r0_next, + r1_next, + o0_next.unwrap_or_else(|| (self.o0_default_fn)()), + o1_next.unwrap_or_else(|| (self.o1_default_fn)()), + o2_next.unwrap_or_else(|| (self.o2_default_fn)()), + )) + } +} + +/// Returns a new [`ClampedZip2x4`] iterator. +/// +/// The number of elements in a clamped zip iterator corresponds to the number of elements in the +/// shortest of its required iterators (`r0`, `r1`). +/// +/// Optional iterators (`o0`, `o1`, `o2`, `o3`) will repeat their latest values if they happen to be too short +/// to be zipped with the shortest of the required iterators. +/// +/// If an optional iterator is not only too short but actually empty, its associated default function +/// (`o0_default_fn`, `o1_default_fn`, `o2_default_fn`, `o3_default_fn`) will be executed and the resulting value repeated as necessary. +pub fn clamped_zip_2x4( + r0: R0, + r1: R1, + o0: O0, + o0_default_fn: D0, + o1: O1, + o1_default_fn: D1, + o2: O2, + o2_default_fn: D2, + o3: O3, + o3_default_fn: D3, +) -> ClampedZip2x4< + R0::IntoIter, + R1::IntoIter, + O0::IntoIter, + O1::IntoIter, + O2::IntoIter, + O3::IntoIter, + D0, + D1, + D2, + D3, +> +where + R0: IntoIterator, + R1: IntoIterator, + O0: IntoIterator, + O0::Item: Clone, + O1: IntoIterator, + O1::Item: Clone, + O2: IntoIterator, + O2::Item: Clone, + O3: IntoIterator, + O3::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, +{ + ClampedZip2x4 { + r0: r0.into_iter(), + r1: r1.into_iter(), + o0: o0.into_iter(), + o1: o1.into_iter(), + o2: o2.into_iter(), + o3: o3.into_iter(), + o0_default_fn, + o1_default_fn, + o2_default_fn, + o3_default_fn, + o0_latest_value: None, + o1_latest_value: None, + o2_latest_value: None, + o3_latest_value: None, + } +} + +/// Implements a clamped zip iterator combinator with 2 required iterators and 2 optional +/// iterators. +/// +/// See [`clamped_zip_2x4`] for more information. +pub struct ClampedZip2x4 +where + R0: Iterator, + R1: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, +{ + r0: R0, + r1: R1, + o0: O0, + o1: O1, + o2: O2, + o3: O3, + o0_default_fn: D0, + o1_default_fn: D1, + o2_default_fn: D2, + o3_default_fn: D3, + + o0_latest_value: Option, + o1_latest_value: Option, + o2_latest_value: Option, + o3_latest_value: Option, +} + +impl Iterator + for ClampedZip2x4 +where + R0: Iterator, + R1: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, +{ + type Item = (R0::Item, R1::Item, O0::Item, O1::Item, O2::Item, O3::Item); + + #[inline] + fn next(&mut self) -> Option { + let r0_next = self.r0.next()?; + let r1_next = self.r1.next()?; + let o0_next = self.o0.next().or(self.o0_latest_value.take()); + let o1_next = self.o1.next().or(self.o1_latest_value.take()); + let o2_next = self.o2.next().or(self.o2_latest_value.take()); + let o3_next = self.o3.next().or(self.o3_latest_value.take()); + + self.o0_latest_value = o0_next.clone(); + self.o1_latest_value = o1_next.clone(); + self.o2_latest_value = o2_next.clone(); + self.o3_latest_value = o3_next.clone(); + + Some(( + r0_next, + r1_next, + o0_next.unwrap_or_else(|| (self.o0_default_fn)()), + o1_next.unwrap_or_else(|| (self.o1_default_fn)()), + o2_next.unwrap_or_else(|| (self.o2_default_fn)()), + o3_next.unwrap_or_else(|| (self.o3_default_fn)()), + )) + } +} + +/// Returns a new [`ClampedZip2x5`] iterator. +/// +/// The number of elements in a clamped zip iterator corresponds to the number of elements in the +/// shortest of its required iterators (`r0`, `r1`). +/// +/// Optional iterators (`o0`, `o1`, `o2`, `o3`, `o4`) will repeat their latest values if they happen to be too short +/// to be zipped with the shortest of the required iterators. +/// +/// If an optional iterator is not only too short but actually empty, its associated default function +/// (`o0_default_fn`, `o1_default_fn`, `o2_default_fn`, `o3_default_fn`, `o4_default_fn`) will be executed and the resulting value repeated as necessary. +pub fn clamped_zip_2x5( + r0: R0, + r1: R1, + o0: O0, + o0_default_fn: D0, + o1: O1, + o1_default_fn: D1, + o2: O2, + o2_default_fn: D2, + o3: O3, + o3_default_fn: D3, + o4: O4, + o4_default_fn: D4, +) -> ClampedZip2x5< + R0::IntoIter, + R1::IntoIter, + O0::IntoIter, + O1::IntoIter, + O2::IntoIter, + O3::IntoIter, + O4::IntoIter, + D0, + D1, + D2, + D3, + D4, +> +where + R0: IntoIterator, + R1: IntoIterator, + O0: IntoIterator, + O0::Item: Clone, + O1: IntoIterator, + O1::Item: Clone, + O2: IntoIterator, + O2::Item: Clone, + O3: IntoIterator, + O3::Item: Clone, + O4: IntoIterator, + O4::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, +{ + ClampedZip2x5 { + r0: r0.into_iter(), + r1: r1.into_iter(), + o0: o0.into_iter(), + o1: o1.into_iter(), + o2: o2.into_iter(), + o3: o3.into_iter(), + o4: o4.into_iter(), + o0_default_fn, + o1_default_fn, + o2_default_fn, + o3_default_fn, + o4_default_fn, + o0_latest_value: None, + o1_latest_value: None, + o2_latest_value: None, + o3_latest_value: None, + o4_latest_value: None, + } +} + +/// Implements a clamped zip iterator combinator with 2 required iterators and 2 optional +/// iterators. +/// +/// See [`clamped_zip_2x5`] for more information. +pub struct ClampedZip2x5 +where + R0: Iterator, + R1: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + O4: Iterator, + O4::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, +{ + r0: R0, + r1: R1, + o0: O0, + o1: O1, + o2: O2, + o3: O3, + o4: O4, + o0_default_fn: D0, + o1_default_fn: D1, + o2_default_fn: D2, + o3_default_fn: D3, + o4_default_fn: D4, + + o0_latest_value: Option, + o1_latest_value: Option, + o2_latest_value: Option, + o3_latest_value: Option, + o4_latest_value: Option, +} + +impl Iterator + for ClampedZip2x5 +where + R0: Iterator, + R1: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + O4: Iterator, + O4::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, +{ + type Item = ( + R0::Item, + R1::Item, + O0::Item, + O1::Item, + O2::Item, + O3::Item, + O4::Item, + ); + + #[inline] + fn next(&mut self) -> Option { + let r0_next = self.r0.next()?; + let r1_next = self.r1.next()?; + let o0_next = self.o0.next().or(self.o0_latest_value.take()); + let o1_next = self.o1.next().or(self.o1_latest_value.take()); + let o2_next = self.o2.next().or(self.o2_latest_value.take()); + let o3_next = self.o3.next().or(self.o3_latest_value.take()); + let o4_next = self.o4.next().or(self.o4_latest_value.take()); + + self.o0_latest_value = o0_next.clone(); + self.o1_latest_value = o1_next.clone(); + self.o2_latest_value = o2_next.clone(); + self.o3_latest_value = o3_next.clone(); + self.o4_latest_value = o4_next.clone(); + + Some(( + r0_next, + r1_next, + o0_next.unwrap_or_else(|| (self.o0_default_fn)()), + o1_next.unwrap_or_else(|| (self.o1_default_fn)()), + o2_next.unwrap_or_else(|| (self.o2_default_fn)()), + o3_next.unwrap_or_else(|| (self.o3_default_fn)()), + o4_next.unwrap_or_else(|| (self.o4_default_fn)()), + )) + } +} + +/// Returns a new [`ClampedZip2x6`] iterator. +/// +/// The number of elements in a clamped zip iterator corresponds to the number of elements in the +/// shortest of its required iterators (`r0`, `r1`). +/// +/// Optional iterators (`o0`, `o1`, `o2`, `o3`, `o4`, `o5`) will repeat their latest values if they happen to be too short +/// to be zipped with the shortest of the required iterators. +/// +/// If an optional iterator is not only too short but actually empty, its associated default function +/// (`o0_default_fn`, `o1_default_fn`, `o2_default_fn`, `o3_default_fn`, `o4_default_fn`, `o5_default_fn`) will be executed and the resulting value repeated as necessary. +pub fn clamped_zip_2x6( + r0: R0, + r1: R1, + o0: O0, + o0_default_fn: D0, + o1: O1, + o1_default_fn: D1, + o2: O2, + o2_default_fn: D2, + o3: O3, + o3_default_fn: D3, + o4: O4, + o4_default_fn: D4, + o5: O5, + o5_default_fn: D5, +) -> ClampedZip2x6< + R0::IntoIter, + R1::IntoIter, + O0::IntoIter, + O1::IntoIter, + O2::IntoIter, + O3::IntoIter, + O4::IntoIter, + O5::IntoIter, + D0, + D1, + D2, + D3, + D4, + D5, +> +where + R0: IntoIterator, + R1: IntoIterator, + O0: IntoIterator, + O0::Item: Clone, + O1: IntoIterator, + O1::Item: Clone, + O2: IntoIterator, + O2::Item: Clone, + O3: IntoIterator, + O3::Item: Clone, + O4: IntoIterator, + O4::Item: Clone, + O5: IntoIterator, + O5::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, +{ + ClampedZip2x6 { + r0: r0.into_iter(), + r1: r1.into_iter(), + o0: o0.into_iter(), + o1: o1.into_iter(), + o2: o2.into_iter(), + o3: o3.into_iter(), + o4: o4.into_iter(), + o5: o5.into_iter(), + o0_default_fn, + o1_default_fn, + o2_default_fn, + o3_default_fn, + o4_default_fn, + o5_default_fn, + o0_latest_value: None, + o1_latest_value: None, + o2_latest_value: None, + o3_latest_value: None, + o4_latest_value: None, + o5_latest_value: None, + } +} + +/// Implements a clamped zip iterator combinator with 2 required iterators and 2 optional +/// iterators. +/// +/// See [`clamped_zip_2x6`] for more information. +pub struct ClampedZip2x6 +where + R0: Iterator, + R1: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + O4: Iterator, + O4::Item: Clone, + O5: Iterator, + O5::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, +{ + r0: R0, + r1: R1, + o0: O0, + o1: O1, + o2: O2, + o3: O3, + o4: O4, + o5: O5, + o0_default_fn: D0, + o1_default_fn: D1, + o2_default_fn: D2, + o3_default_fn: D3, + o4_default_fn: D4, + o5_default_fn: D5, + + o0_latest_value: Option, + o1_latest_value: Option, + o2_latest_value: Option, + o3_latest_value: Option, + o4_latest_value: Option, + o5_latest_value: Option, +} + +impl Iterator + for ClampedZip2x6 +where + R0: Iterator, + R1: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + O4: Iterator, + O4::Item: Clone, + O5: Iterator, + O5::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, +{ + type Item = ( + R0::Item, + R1::Item, + O0::Item, + O1::Item, + O2::Item, + O3::Item, + O4::Item, + O5::Item, + ); + + #[inline] + fn next(&mut self) -> Option { + let r0_next = self.r0.next()?; + let r1_next = self.r1.next()?; + let o0_next = self.o0.next().or(self.o0_latest_value.take()); + let o1_next = self.o1.next().or(self.o1_latest_value.take()); + let o2_next = self.o2.next().or(self.o2_latest_value.take()); + let o3_next = self.o3.next().or(self.o3_latest_value.take()); + let o4_next = self.o4.next().or(self.o4_latest_value.take()); + let o5_next = self.o5.next().or(self.o5_latest_value.take()); + + self.o0_latest_value = o0_next.clone(); + self.o1_latest_value = o1_next.clone(); + self.o2_latest_value = o2_next.clone(); + self.o3_latest_value = o3_next.clone(); + self.o4_latest_value = o4_next.clone(); + self.o5_latest_value = o5_next.clone(); + + Some(( + r0_next, + r1_next, + o0_next.unwrap_or_else(|| (self.o0_default_fn)()), + o1_next.unwrap_or_else(|| (self.o1_default_fn)()), + o2_next.unwrap_or_else(|| (self.o2_default_fn)()), + o3_next.unwrap_or_else(|| (self.o3_default_fn)()), + o4_next.unwrap_or_else(|| (self.o4_default_fn)()), + o5_next.unwrap_or_else(|| (self.o5_default_fn)()), + )) + } +} + +/// Returns a new [`ClampedZip2x7`] iterator. +/// +/// The number of elements in a clamped zip iterator corresponds to the number of elements in the +/// shortest of its required iterators (`r0`, `r1`). +/// +/// Optional iterators (`o0`, `o1`, `o2`, `o3`, `o4`, `o5`, `o6`) will repeat their latest values if they happen to be too short +/// to be zipped with the shortest of the required iterators. +/// +/// If an optional iterator is not only too short but actually empty, its associated default function +/// (`o0_default_fn`, `o1_default_fn`, `o2_default_fn`, `o3_default_fn`, `o4_default_fn`, `o5_default_fn`, `o6_default_fn`) will be executed and the resulting value repeated as necessary. +pub fn clamped_zip_2x7( + r0: R0, + r1: R1, + o0: O0, + o0_default_fn: D0, + o1: O1, + o1_default_fn: D1, + o2: O2, + o2_default_fn: D2, + o3: O3, + o3_default_fn: D3, + o4: O4, + o4_default_fn: D4, + o5: O5, + o5_default_fn: D5, + o6: O6, + o6_default_fn: D6, +) -> ClampedZip2x7< + R0::IntoIter, + R1::IntoIter, + O0::IntoIter, + O1::IntoIter, + O2::IntoIter, + O3::IntoIter, + O4::IntoIter, + O5::IntoIter, + O6::IntoIter, + D0, + D1, + D2, + D3, + D4, + D5, + D6, +> +where + R0: IntoIterator, + R1: IntoIterator, + O0: IntoIterator, + O0::Item: Clone, + O1: IntoIterator, + O1::Item: Clone, + O2: IntoIterator, + O2::Item: Clone, + O3: IntoIterator, + O3::Item: Clone, + O4: IntoIterator, + O4::Item: Clone, + O5: IntoIterator, + O5::Item: Clone, + O6: IntoIterator, + O6::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, + D6: Fn() -> O6::Item, +{ + ClampedZip2x7 { + r0: r0.into_iter(), + r1: r1.into_iter(), + o0: o0.into_iter(), + o1: o1.into_iter(), + o2: o2.into_iter(), + o3: o3.into_iter(), + o4: o4.into_iter(), + o5: o5.into_iter(), + o6: o6.into_iter(), + o0_default_fn, + o1_default_fn, + o2_default_fn, + o3_default_fn, + o4_default_fn, + o5_default_fn, + o6_default_fn, + o0_latest_value: None, + o1_latest_value: None, + o2_latest_value: None, + o3_latest_value: None, + o4_latest_value: None, + o5_latest_value: None, + o6_latest_value: None, + } +} + +/// Implements a clamped zip iterator combinator with 2 required iterators and 2 optional +/// iterators. +/// +/// See [`clamped_zip_2x7`] for more information. +pub struct ClampedZip2x7 +where + R0: Iterator, + R1: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + O4: Iterator, + O4::Item: Clone, + O5: Iterator, + O5::Item: Clone, + O6: Iterator, + O6::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, + D6: Fn() -> O6::Item, +{ + r0: R0, + r1: R1, + o0: O0, + o1: O1, + o2: O2, + o3: O3, + o4: O4, + o5: O5, + o6: O6, + o0_default_fn: D0, + o1_default_fn: D1, + o2_default_fn: D2, + o3_default_fn: D3, + o4_default_fn: D4, + o5_default_fn: D5, + o6_default_fn: D6, + + o0_latest_value: Option, + o1_latest_value: Option, + o2_latest_value: Option, + o3_latest_value: Option, + o4_latest_value: Option, + o5_latest_value: Option, + o6_latest_value: Option, +} + +impl Iterator + for ClampedZip2x7 +where + R0: Iterator, + R1: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + O4: Iterator, + O4::Item: Clone, + O5: Iterator, + O5::Item: Clone, + O6: Iterator, + O6::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, + D6: Fn() -> O6::Item, +{ + type Item = ( + R0::Item, + R1::Item, + O0::Item, + O1::Item, + O2::Item, + O3::Item, + O4::Item, + O5::Item, + O6::Item, + ); + + #[inline] + fn next(&mut self) -> Option { + let r0_next = self.r0.next()?; + let r1_next = self.r1.next()?; + let o0_next = self.o0.next().or(self.o0_latest_value.take()); + let o1_next = self.o1.next().or(self.o1_latest_value.take()); + let o2_next = self.o2.next().or(self.o2_latest_value.take()); + let o3_next = self.o3.next().or(self.o3_latest_value.take()); + let o4_next = self.o4.next().or(self.o4_latest_value.take()); + let o5_next = self.o5.next().or(self.o5_latest_value.take()); + let o6_next = self.o6.next().or(self.o6_latest_value.take()); + + self.o0_latest_value = o0_next.clone(); + self.o1_latest_value = o1_next.clone(); + self.o2_latest_value = o2_next.clone(); + self.o3_latest_value = o3_next.clone(); + self.o4_latest_value = o4_next.clone(); + self.o5_latest_value = o5_next.clone(); + self.o6_latest_value = o6_next.clone(); + + Some(( + r0_next, + r1_next, + o0_next.unwrap_or_else(|| (self.o0_default_fn)()), + o1_next.unwrap_or_else(|| (self.o1_default_fn)()), + o2_next.unwrap_or_else(|| (self.o2_default_fn)()), + o3_next.unwrap_or_else(|| (self.o3_default_fn)()), + o4_next.unwrap_or_else(|| (self.o4_default_fn)()), + o5_next.unwrap_or_else(|| (self.o5_default_fn)()), + o6_next.unwrap_or_else(|| (self.o6_default_fn)()), + )) + } +} + +/// Returns a new [`ClampedZip2x8`] iterator. +/// +/// The number of elements in a clamped zip iterator corresponds to the number of elements in the +/// shortest of its required iterators (`r0`, `r1`). +/// +/// Optional iterators (`o0`, `o1`, `o2`, `o3`, `o4`, `o5`, `o6`, `o7`) will repeat their latest values if they happen to be too short +/// to be zipped with the shortest of the required iterators. +/// +/// If an optional iterator is not only too short but actually empty, its associated default function +/// (`o0_default_fn`, `o1_default_fn`, `o2_default_fn`, `o3_default_fn`, `o4_default_fn`, `o5_default_fn`, `o6_default_fn`, `o7_default_fn`) will be executed and the resulting value repeated as necessary. +pub fn clamped_zip_2x8( + r0: R0, + r1: R1, + o0: O0, + o0_default_fn: D0, + o1: O1, + o1_default_fn: D1, + o2: O2, + o2_default_fn: D2, + o3: O3, + o3_default_fn: D3, + o4: O4, + o4_default_fn: D4, + o5: O5, + o5_default_fn: D5, + o6: O6, + o6_default_fn: D6, + o7: O7, + o7_default_fn: D7, +) -> ClampedZip2x8< + R0::IntoIter, + R1::IntoIter, + O0::IntoIter, + O1::IntoIter, + O2::IntoIter, + O3::IntoIter, + O4::IntoIter, + O5::IntoIter, + O6::IntoIter, + O7::IntoIter, + D0, + D1, + D2, + D3, + D4, + D5, + D6, + D7, +> +where + R0: IntoIterator, + R1: IntoIterator, + O0: IntoIterator, + O0::Item: Clone, + O1: IntoIterator, + O1::Item: Clone, + O2: IntoIterator, + O2::Item: Clone, + O3: IntoIterator, + O3::Item: Clone, + O4: IntoIterator, + O4::Item: Clone, + O5: IntoIterator, + O5::Item: Clone, + O6: IntoIterator, + O6::Item: Clone, + O7: IntoIterator, + O7::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, + D6: Fn() -> O6::Item, + D7: Fn() -> O7::Item, +{ + ClampedZip2x8 { + r0: r0.into_iter(), + r1: r1.into_iter(), + o0: o0.into_iter(), + o1: o1.into_iter(), + o2: o2.into_iter(), + o3: o3.into_iter(), + o4: o4.into_iter(), + o5: o5.into_iter(), + o6: o6.into_iter(), + o7: o7.into_iter(), + o0_default_fn, + o1_default_fn, + o2_default_fn, + o3_default_fn, + o4_default_fn, + o5_default_fn, + o6_default_fn, + o7_default_fn, + o0_latest_value: None, + o1_latest_value: None, + o2_latest_value: None, + o3_latest_value: None, + o4_latest_value: None, + o5_latest_value: None, + o6_latest_value: None, + o7_latest_value: None, + } +} + +/// Implements a clamped zip iterator combinator with 2 required iterators and 2 optional +/// iterators. +/// +/// See [`clamped_zip_2x8`] for more information. +pub struct ClampedZip2x8 +where + R0: Iterator, + R1: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + O4: Iterator, + O4::Item: Clone, + O5: Iterator, + O5::Item: Clone, + O6: Iterator, + O6::Item: Clone, + O7: Iterator, + O7::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, + D6: Fn() -> O6::Item, + D7: Fn() -> O7::Item, +{ + r0: R0, + r1: R1, + o0: O0, + o1: O1, + o2: O2, + o3: O3, + o4: O4, + o5: O5, + o6: O6, + o7: O7, + o0_default_fn: D0, + o1_default_fn: D1, + o2_default_fn: D2, + o3_default_fn: D3, + o4_default_fn: D4, + o5_default_fn: D5, + o6_default_fn: D6, + o7_default_fn: D7, + + o0_latest_value: Option, + o1_latest_value: Option, + o2_latest_value: Option, + o3_latest_value: Option, + o4_latest_value: Option, + o5_latest_value: Option, + o6_latest_value: Option, + o7_latest_value: Option, +} + +impl Iterator + for ClampedZip2x8 +where + R0: Iterator, + R1: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + O4: Iterator, + O4::Item: Clone, + O5: Iterator, + O5::Item: Clone, + O6: Iterator, + O6::Item: Clone, + O7: Iterator, + O7::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, + D6: Fn() -> O6::Item, + D7: Fn() -> O7::Item, +{ + type Item = ( + R0::Item, + R1::Item, + O0::Item, + O1::Item, + O2::Item, + O3::Item, + O4::Item, + O5::Item, + O6::Item, + O7::Item, + ); + + #[inline] + fn next(&mut self) -> Option { + let r0_next = self.r0.next()?; + let r1_next = self.r1.next()?; + let o0_next = self.o0.next().or(self.o0_latest_value.take()); + let o1_next = self.o1.next().or(self.o1_latest_value.take()); + let o2_next = self.o2.next().or(self.o2_latest_value.take()); + let o3_next = self.o3.next().or(self.o3_latest_value.take()); + let o4_next = self.o4.next().or(self.o4_latest_value.take()); + let o5_next = self.o5.next().or(self.o5_latest_value.take()); + let o6_next = self.o6.next().or(self.o6_latest_value.take()); + let o7_next = self.o7.next().or(self.o7_latest_value.take()); + + self.o0_latest_value = o0_next.clone(); + self.o1_latest_value = o1_next.clone(); + self.o2_latest_value = o2_next.clone(); + self.o3_latest_value = o3_next.clone(); + self.o4_latest_value = o4_next.clone(); + self.o5_latest_value = o5_next.clone(); + self.o6_latest_value = o6_next.clone(); + self.o7_latest_value = o7_next.clone(); + + Some(( + r0_next, + r1_next, + o0_next.unwrap_or_else(|| (self.o0_default_fn)()), + o1_next.unwrap_or_else(|| (self.o1_default_fn)()), + o2_next.unwrap_or_else(|| (self.o2_default_fn)()), + o3_next.unwrap_or_else(|| (self.o3_default_fn)()), + o4_next.unwrap_or_else(|| (self.o4_default_fn)()), + o5_next.unwrap_or_else(|| (self.o5_default_fn)()), + o6_next.unwrap_or_else(|| (self.o6_default_fn)()), + o7_next.unwrap_or_else(|| (self.o7_default_fn)()), + )) + } +} + +/// Returns a new [`ClampedZip2x9`] iterator. +/// +/// The number of elements in a clamped zip iterator corresponds to the number of elements in the +/// shortest of its required iterators (`r0`, `r1`). +/// +/// Optional iterators (`o0`, `o1`, `o2`, `o3`, `o4`, `o5`, `o6`, `o7`, `o8`) will repeat their latest values if they happen to be too short +/// to be zipped with the shortest of the required iterators. +/// +/// If an optional iterator is not only too short but actually empty, its associated default function +/// (`o0_default_fn`, `o1_default_fn`, `o2_default_fn`, `o3_default_fn`, `o4_default_fn`, `o5_default_fn`, `o6_default_fn`, `o7_default_fn`, `o8_default_fn`) will be executed and the resulting value repeated as necessary. +pub fn clamped_zip_2x9< + R0, + R1, + O0, + O1, + O2, + O3, + O4, + O5, + O6, + O7, + O8, + D0, + D1, + D2, + D3, + D4, + D5, + D6, + D7, + D8, +>( + r0: R0, + r1: R1, + o0: O0, + o0_default_fn: D0, + o1: O1, + o1_default_fn: D1, + o2: O2, + o2_default_fn: D2, + o3: O3, + o3_default_fn: D3, + o4: O4, + o4_default_fn: D4, + o5: O5, + o5_default_fn: D5, + o6: O6, + o6_default_fn: D6, + o7: O7, + o7_default_fn: D7, + o8: O8, + o8_default_fn: D8, +) -> ClampedZip2x9< + R0::IntoIter, + R1::IntoIter, + O0::IntoIter, + O1::IntoIter, + O2::IntoIter, + O3::IntoIter, + O4::IntoIter, + O5::IntoIter, + O6::IntoIter, + O7::IntoIter, + O8::IntoIter, + D0, + D1, + D2, + D3, + D4, + D5, + D6, + D7, + D8, +> +where + R0: IntoIterator, + R1: IntoIterator, + O0: IntoIterator, + O0::Item: Clone, + O1: IntoIterator, + O1::Item: Clone, + O2: IntoIterator, + O2::Item: Clone, + O3: IntoIterator, + O3::Item: Clone, + O4: IntoIterator, + O4::Item: Clone, + O5: IntoIterator, + O5::Item: Clone, + O6: IntoIterator, + O6::Item: Clone, + O7: IntoIterator, + O7::Item: Clone, + O8: IntoIterator, + O8::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, + D6: Fn() -> O6::Item, + D7: Fn() -> O7::Item, + D8: Fn() -> O8::Item, +{ + ClampedZip2x9 { + r0: r0.into_iter(), + r1: r1.into_iter(), + o0: o0.into_iter(), + o1: o1.into_iter(), + o2: o2.into_iter(), + o3: o3.into_iter(), + o4: o4.into_iter(), + o5: o5.into_iter(), + o6: o6.into_iter(), + o7: o7.into_iter(), + o8: o8.into_iter(), + o0_default_fn, + o1_default_fn, + o2_default_fn, + o3_default_fn, + o4_default_fn, + o5_default_fn, + o6_default_fn, + o7_default_fn, + o8_default_fn, + o0_latest_value: None, + o1_latest_value: None, + o2_latest_value: None, + o3_latest_value: None, + o4_latest_value: None, + o5_latest_value: None, + o6_latest_value: None, + o7_latest_value: None, + o8_latest_value: None, + } +} + +/// Implements a clamped zip iterator combinator with 2 required iterators and 2 optional +/// iterators. +/// +/// See [`clamped_zip_2x9`] for more information. +pub struct ClampedZip2x9< + R0, + R1, + O0, + O1, + O2, + O3, + O4, + O5, + O6, + O7, + O8, + D0, + D1, + D2, + D3, + D4, + D5, + D6, + D7, + D8, +> where + R0: Iterator, + R1: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + O4: Iterator, + O4::Item: Clone, + O5: Iterator, + O5::Item: Clone, + O6: Iterator, + O6::Item: Clone, + O7: Iterator, + O7::Item: Clone, + O8: Iterator, + O8::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, + D6: Fn() -> O6::Item, + D7: Fn() -> O7::Item, + D8: Fn() -> O8::Item, +{ + r0: R0, + r1: R1, + o0: O0, + o1: O1, + o2: O2, + o3: O3, + o4: O4, + o5: O5, + o6: O6, + o7: O7, + o8: O8, + o0_default_fn: D0, + o1_default_fn: D1, + o2_default_fn: D2, + o3_default_fn: D3, + o4_default_fn: D4, + o5_default_fn: D5, + o6_default_fn: D6, + o7_default_fn: D7, + o8_default_fn: D8, + + o0_latest_value: Option, + o1_latest_value: Option, + o2_latest_value: Option, + o3_latest_value: Option, + o4_latest_value: Option, + o5_latest_value: Option, + o6_latest_value: Option, + o7_latest_value: Option, + o8_latest_value: Option, +} + +impl Iterator + for ClampedZip2x9< + R0, + R1, + O0, + O1, + O2, + O3, + O4, + O5, + O6, + O7, + O8, + D0, + D1, + D2, + D3, + D4, + D5, + D6, + D7, + D8, + > +where + R0: Iterator, + R1: Iterator, + O0: Iterator, + O0::Item: Clone, + O1: Iterator, + O1::Item: Clone, + O2: Iterator, + O2::Item: Clone, + O3: Iterator, + O3::Item: Clone, + O4: Iterator, + O4::Item: Clone, + O5: Iterator, + O5::Item: Clone, + O6: Iterator, + O6::Item: Clone, + O7: Iterator, + O7::Item: Clone, + O8: Iterator, + O8::Item: Clone, + D0: Fn() -> O0::Item, + D1: Fn() -> O1::Item, + D2: Fn() -> O2::Item, + D3: Fn() -> O3::Item, + D4: Fn() -> O4::Item, + D5: Fn() -> O5::Item, + D6: Fn() -> O6::Item, + D7: Fn() -> O7::Item, + D8: Fn() -> O8::Item, +{ + type Item = ( + R0::Item, + R1::Item, + O0::Item, + O1::Item, + O2::Item, + O3::Item, + O4::Item, + O5::Item, + O6::Item, + O7::Item, + O8::Item, + ); + + #[inline] + fn next(&mut self) -> Option { + let r0_next = self.r0.next()?; + let r1_next = self.r1.next()?; + let o0_next = self.o0.next().or(self.o0_latest_value.take()); + let o1_next = self.o1.next().or(self.o1_latest_value.take()); + let o2_next = self.o2.next().or(self.o2_latest_value.take()); + let o3_next = self.o3.next().or(self.o3_latest_value.take()); + let o4_next = self.o4.next().or(self.o4_latest_value.take()); + let o5_next = self.o5.next().or(self.o5_latest_value.take()); + let o6_next = self.o6.next().or(self.o6_latest_value.take()); + let o7_next = self.o7.next().or(self.o7_latest_value.take()); + let o8_next = self.o8.next().or(self.o8_latest_value.take()); + + self.o0_latest_value = o0_next.clone(); + self.o1_latest_value = o1_next.clone(); + self.o2_latest_value = o2_next.clone(); + self.o3_latest_value = o3_next.clone(); + self.o4_latest_value = o4_next.clone(); + self.o5_latest_value = o5_next.clone(); + self.o6_latest_value = o6_next.clone(); + self.o7_latest_value = o7_next.clone(); + self.o8_latest_value = o8_next.clone(); + + Some(( + r0_next, + r1_next, + o0_next.unwrap_or_else(|| (self.o0_default_fn)()), + o1_next.unwrap_or_else(|| (self.o1_default_fn)()), + o2_next.unwrap_or_else(|| (self.o2_default_fn)()), + o3_next.unwrap_or_else(|| (self.o3_default_fn)()), + o4_next.unwrap_or_else(|| (self.o4_default_fn)()), + o5_next.unwrap_or_else(|| (self.o5_default_fn)()), + o6_next.unwrap_or_else(|| (self.o6_default_fn)()), + o7_next.unwrap_or_else(|| (self.o7_default_fn)()), + o8_next.unwrap_or_else(|| (self.o8_default_fn)()), + )) + } +} diff --git a/crates/re_query2/src/clamped_zip/mod.rs b/crates/re_query2/src/clamped_zip/mod.rs new file mode 100644 index 000000000000..65bd61b05021 --- /dev/null +++ b/crates/re_query2/src/clamped_zip/mod.rs @@ -0,0 +1,64 @@ +mod generated; +pub use self::generated::*; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn r0_is_empty_o0_is_empty() { + let r0 = std::iter::empty::(); + let o0 = (0..).map(|n| n.to_string()); + + let expected: Vec<(u32, String)> = vec![]; + let got = clamped_zip_1x1(r0, o0, String::new).collect::>(); + + similar_asserts::assert_eq!(expected, got); + } + + #[test] + fn r0_and_o0_are_matched() { + let r0 = 0..20u32; + let o0 = (0..20).map(|n| n.to_string()); + + let expected: Vec<(u32, String)> = (0..20u32).map(|n| (n, n.to_string())).collect(); + let got = clamped_zip_1x1(r0, o0, String::new).collect::>(); + + similar_asserts::assert_eq!(expected, got); + } + + #[test] + fn r0_is_shorter() { + let r0 = 0..10u32; + let o0 = (0..20).map(|n| n.to_string()); + + let expected: Vec<(u32, String)> = (0..10u32).map(|n| (n, n.to_string())).collect(); + let got = clamped_zip_1x1(r0, o0, String::new).collect::>(); + + similar_asserts::assert_eq!(expected, got); + } + + #[test] + fn r0_is_longer() { + let r0 = 0..30u32; + let o0 = (0..20).map(|n| n.to_string()); + + let expected: Vec<(u32, String)> = (0..30u32) + .map(|n| (n, u32::min(n, 19).to_string())) + .collect(); + let got = clamped_zip_1x1(r0, o0, String::new).collect::>(); + + similar_asserts::assert_eq!(expected, got); + } + + #[test] + fn r0_is_longer_and_o0_is_empty() { + let r0 = 0..10u32; + let o0 = std::iter::empty(); + + let expected: Vec<(u32, String)> = (0..10u32).map(|n| (n, "hey".to_owned())).collect(); + let got = clamped_zip_1x1(r0, o0, || "hey".to_owned()).collect::>(); + + similar_asserts::assert_eq!(expected, got); + } +} diff --git a/crates/re_query2/src/lib.rs b/crates/re_query2/src/lib.rs new file mode 100644 index 000000000000..33f05e522514 --- /dev/null +++ b/crates/re_query2/src/lib.rs @@ -0,0 +1,58 @@ +//! Provide query-centric access to the [`re_data_store`]. + +mod clamped_zip; +mod visible_history; + +pub use self::clamped_zip::*; +pub use self::visible_history::{ExtraQueryHistory, VisibleHistory, VisibleHistoryBoundary}; + +// --- + +#[derive(Debug, Clone, Copy)] +pub struct ComponentNotFoundError(pub re_types_core::ComponentName); + +impl std::fmt::Display for ComponentNotFoundError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!("Could not find component: {}", self.0)) + } +} + +impl std::error::Error for ComponentNotFoundError {} + +#[derive(thiserror::Error, Debug)] +pub enum QueryError { + #[error("Tried to access a column that doesn't exist")] + BadAccess, + + #[error("Could not find primary component: {0}")] + PrimaryNotFound(re_types_core::ComponentName), + + #[error(transparent)] + ComponentNotFound(#[from] ComponentNotFoundError), + + #[error("Tried to access component of type '{actual:?}' using component '{requested:?}'")] + TypeMismatch { + actual: re_types_core::ComponentName, + requested: re_types_core::ComponentName, + }, + + #[error("Error with one or more the underlying data cells: {0}")] + DataCell(#[from] re_log_types::DataCellError), + + #[error("Error deserializing: {0}")] + DeserializationError(#[from] re_types_core::DeserializationError), + + #[error("Error serializing: {0}")] + SerializationError(#[from] re_types_core::SerializationError), + + #[error("Error converting arrow data: {0}")] + ArrowError(#[from] arrow2::error::Error), + + #[error("Not implemented")] + NotImplemented, + + #[error(transparent)] + Other(#[from] anyhow::Error), +} + +pub type Result = std::result::Result; diff --git a/crates/re_query2/src/visible_history.rs b/crates/re_query2/src/visible_history.rs new file mode 100644 index 000000000000..f11b29f96baa --- /dev/null +++ b/crates/re_query2/src/visible_history.rs @@ -0,0 +1,126 @@ +use re_data_store::{TimeInt, TimeRange}; + +// --- + +/// One of the boundaries of the visible history. +/// +/// For [`VisibleHistoryBoundary::RelativeToTimeCursor`] and [`VisibleHistoryBoundary::Absolute`], +/// the value are either nanos or frames, depending on the type of timeline. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub enum VisibleHistoryBoundary { + /// Boundary is a value relative to the time cursor + RelativeToTimeCursor(i64), + + /// Boundary is an absolute value + Absolute(i64), + + /// The boundary extends to infinity. + Infinite, +} + +impl VisibleHistoryBoundary { + /// Value when the boundary is set to the current time cursor. + pub const AT_CURSOR: Self = Self::RelativeToTimeCursor(0); +} + +impl Default for VisibleHistoryBoundary { + fn default() -> Self { + Self::AT_CURSOR + } +} + +/// Visible history bounds. +#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct VisibleHistory { + /// Low time boundary. + pub from: VisibleHistoryBoundary, + + /// High time boundary. + pub to: VisibleHistoryBoundary, +} + +impl VisibleHistory { + /// Value with the visible history feature is disabled. + pub const OFF: Self = Self { + from: VisibleHistoryBoundary::AT_CURSOR, + to: VisibleHistoryBoundary::AT_CURSOR, + }; + + pub const ALL: Self = Self { + from: VisibleHistoryBoundary::Infinite, + to: VisibleHistoryBoundary::Infinite, + }; + + /// Returns the start boundary of the time range given an input cursor position. + /// + /// This is not guaranteed to be lesser than or equal to [`Self::to`]. + /// Do not use this to build a [`TimeRange`], use [`Self::time_range`]. + #[doc(hidden)] + pub fn range_start_from_cursor(&self, cursor: TimeInt) -> TimeInt { + match self.from { + VisibleHistoryBoundary::Absolute(value) => TimeInt::new_temporal(value), + VisibleHistoryBoundary::RelativeToTimeCursor(value) => { + cursor + TimeInt::new_temporal(value) + } + VisibleHistoryBoundary::Infinite => TimeInt::MIN, + } + } + + /// Returns the end boundary of the time range given an input cursor position. + /// + /// This is not guaranteed to be greater than [`Self::from`]. + /// Do not use this to build a [`TimeRange`], use [`Self::time_range`]. + #[doc(hidden)] + pub fn range_end_from_cursor(&self, cursor: TimeInt) -> TimeInt { + match self.to { + VisibleHistoryBoundary::Absolute(value) => TimeInt::new_temporal(value), + VisibleHistoryBoundary::RelativeToTimeCursor(value) => { + cursor + TimeInt::new_temporal(value) + } + VisibleHistoryBoundary::Infinite => TimeInt::MAX, + } + } + + /// Returns a _sanitized_ [`TimeRange`], i.e. guaranteed to be monotonically increasing. + pub fn time_range(&self, cursor: TimeInt) -> TimeRange { + let mut from = self.range_start_from_cursor(cursor); + let mut to = self.range_end_from_cursor(cursor); + + // TODO(#4993): visible time range UI can yield inverted ranges + if from > to { + std::mem::swap(&mut from, &mut to); + } + + TimeRange::new(from, to) + } +} + +/// When showing an entity in the history view, add this much history to it. +#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[cfg_attr(feature = "serde", serde(default))] +pub struct ExtraQueryHistory { + /// Is the feature enabled? + pub enabled: bool, + + /// Visible history settings for time timelines + pub nanos: VisibleHistory, + + /// Visible history settings for frame timelines + pub sequences: VisibleHistory, +} + +impl ExtraQueryHistory { + /// Multiply/and these together. + pub fn with_child(&self, child: &Self) -> Self { + if child.enabled { + *child + } else if self.enabled { + *self + } else { + Self::default() + } + } +} diff --git a/scripts/lint.py b/scripts/lint.py index 377be1982f17..b4a83b447535 100755 --- a/scripts/lint.py +++ b/scripts/lint.py @@ -900,6 +900,9 @@ def lint_file(filepath: str, args: Any) -> int: def lint_crate_docs(should_ignore: Callable[[Any], bool]) -> int: """Make sure ARCHITECTURE.md talks about every single crate we have.""" + # These crates will replace existing ones and won't ever be published as-is. + tmp_crates = ["re_query2", "re_query_cache2"] + crates_dir = Path("crates") architecture_md_file = Path("ARCHITECTURE.md") @@ -920,7 +923,7 @@ def lint_crate_docs(should_ignore: Callable[[Any], bool]) -> int: if crate_name in listed_crates: del listed_crates[crate_name] - if should_ignore(crate): + if should_ignore(crate) or crate.name in tmp_crates: continue if not re.search(r"\b" + crate_name + r"\b", architecture_md):