# HG changeset patch # User Tuomo Valkonen # Date 1776919319 18000 # Node ID 1f301affeae303baa66c845705432863143b21e5 # Parent 3697375f4ee9845964c16297d5963ac1f9904b3d Fix internal links in documentation diff -r 3697375f4ee9 -r 1f301affeae3 Cargo.lock --- a/Cargo.lock Thu Mar 19 18:21:40 2026 -0500 +++ b/Cargo.lock Wed Apr 22 23:41:59 2026 -0500 @@ -4,7 +4,7 @@ [[package]] name = "alg_tools" -version = "0.4.0-dev" +version = "0.4.1-dev" dependencies = [ "anyhow", "colored", diff -r 3697375f4ee9 -r 1f301affeae3 Cargo.toml --- a/Cargo.toml Thu Mar 19 18:21:40 2026 -0500 +++ b/Cargo.toml Wed Apr 22 23:41:59 2026 -0500 @@ -1,6 +1,6 @@ [package] name = "alg_tools" -version = "0.4.0-dev" +version = "0.4.1-dev" edition = "2021" rust-version = "1.85" authors = ["Tuomo Valkonen "] diff -r 3697375f4ee9 -r 1f301affeae3 src/bisection_tree.rs --- a/src/bisection_tree.rs Thu Mar 19 18:21:40 2026 -0500 +++ b/src/bisection_tree.rs Wed Apr 22 23:41:59 2026 -0500 @@ -14,8 +14,10 @@ value of the sum, each $f_k$ also needs to implement [`Mapping`][crate::mapping::Mapping]. Moreover, the sum needs to be represented by a [`SupportGenerator`] that associates to a low-storage-requirement identifier (typically `usize`) an object of the type that represents -$f_k$. [`BTFN`]s support basic vector space operations, and [minimisation][BTFN::minimise] and -[maximisation][BTFN::maximise] via a [branch-and-bound strategy][BTSearch::search_and_refine]. +$f_k$. [`BTFN`]s support basic vector space operations, and +[minimisation][crate::bounds::MinMaxMapping::minimise] and +[maximisation][crate::bounds::MinMaxMapping::maximise] +via a [branch-and-bound strategy][BTSearch::search_and_refine]. The nodes of a bisection tree also store aggregate information about the objects stored in the tree via an [`Aggregator`]. This way, rough upper and lower [bound][Bounds] estimates on @@ -42,10 +44,12 @@ a [`SupportGenerator`]. They can be summed and multipliced by a schalar using standard arithmetic operations. The types of the objects in two summed `BTFN`s do not need to be the same. To find an approximate minimum of a `BTFN` using a branch-and-bound strategy, -use [`BTFN::minimise`]. [`Bounded::bounds`] provides a shortcut to [`GlobalAnalysis`] with the +use [`crate::bounds::MinMaxMapping::minimise`]. +[`crate::bounds::Bounded::bounds`] provides a shortcut to [`GlobalAnalysis`] with the [`Bounds`] aggregator. If the rough bounds so obtained do not indicate that the `BTFN` is in some given bounds, instead of doing a full minimisation and maximisation for higher quality bounds, -it is more efficient to use [`BTFN::has_upper_bound`] and [`BTFN::has_lower_bound`]. +it is more efficient to use [`crate::bounds::MinMaxMapping::has_upper_bound`] and +[`crate::bounds::MinMaxMapping::has_lower_bound`]. */ mod supportid; diff -r 3697375f4ee9 -r 1f301affeae3 src/bisection_tree/btfn.rs --- a/src/bisection_tree/btfn.rs Thu Mar 19 18:21:40 2026 -0500 +++ b/src/bisection_tree/btfn.rs Wed Apr 22 23:41:59 2026 -0500 @@ -162,7 +162,7 @@ /// Change the [bisection tree][BTImpl] of the [`BTFN`] to a different one. /// /// This can be used to convert a [`PreBTFN`] to a full [`BTFN`], or the change - /// the aggreagator; see also [`self.convert_aggregator`]. + /// the aggreagator; see also [`Self::convert_aggregator`]. pub fn instantiate>( self, domain: Cube, diff -r 3697375f4ee9 -r 1f301affeae3 src/bounds.rs --- a/src/bounds.rs Thu Mar 19 18:21:40 2026 -0500 +++ b/src/bounds.rs Wed Apr 22 23:41:59 2026 -0500 @@ -9,12 +9,12 @@ /// Trait for globally analysing a property `A` of a [`Mapping`]. /// -/// Typically `A` is an [`Aggregator`][super::aggregator::Aggregator] such as -/// [`Bounds`][super::aggregator::Bounds]. +/// Typically `A` is an [`Aggregator`][super::bisection_tree::Aggregator] +/// such as [`Bounds`]. pub trait GlobalAnalysis { /// Perform global analysis of the property `A` of `Self`. /// - /// As an example, in the case of `A` being [`Bounds`][super::aggregator::Bounds], + /// As an example, in the case of `A` being [`Bounds`], /// this function will return global upper and lower bounds for the mapping /// represented by `self`. fn global_analysis(&self) -> A; @@ -28,15 +28,14 @@ // } // } -/// Trait for locally analysing a property `A` of a [`Mapping`] (implementing [`Support`]) +/// Trait for locally analysing a property `A` of a [`Mapping`] (implementing [`super::bisection_tree::Support`]) /// within a [`Cube`]. /// -/// Typically `A` is an [`Aggregator`][super::aggregator::Aggregator] such as -/// [`Bounds`][super::aggregator::Bounds]. +/// Typically `A` is an [`Aggregator`][super::bisection_tree::Aggregator] such as [`Bounds`]. pub trait LocalAnalysis: GlobalAnalysis { /// Perform local analysis of the property `A` of `Self`. /// - /// As an example, in the case of `A` being [`Bounds`][super::aggregator::Bounds], + /// As an example, in the case of `A` being [`Bounds`], /// this function will return upper and lower bounds within `cube` for the mapping /// represented by `self`. fn local_analysis(&self, cube: &Cube) -> A; diff -r 3697375f4ee9 -r 1f301affeae3 src/euclidean.rs --- a/src/euclidean.rs Thu Mar 19 18:21:40 2026 -0500 +++ b/src/euclidean.rs Wed Apr 22 23:41:59 2026 -0500 @@ -20,7 +20,7 @@ pub trait Euclidean: VectorSpace + Reflexive { - /// Principal form of the space; always equal to [`Space::Principal`] and + /// Principal form of the space; always equal to [`crate::linops::Space::Principal`] and /// [`VectorSpace::PrincipalV`], but with more traits guaranteed. type PrincipalE: ClosedEuclidean; diff -r 3697375f4ee9 -r 1f301affeae3 src/iterate.rs --- a/src/iterate.rs Thu Mar 19 18:21:40 2026 -0500 +++ b/src/iterate.rs Wed Apr 22 23:41:59 2026 -0500 @@ -56,40 +56,54 @@ ``` */ -use colored::{Colorize, ColoredString}; +use crate::logger::*; +use crate::types::*; +use colored::{ColoredString, Colorize}; use core::fmt::Debug; -use serde::{Serialize, Deserialize}; use cpu_time::ProcessTime; +use serde::{Deserialize, Serialize}; +use std::cell::RefCell; +use std::error::Error; use std::marker::PhantomData; +use std::rc::Rc; use std::time::Duration; -use std::error::Error; -use std::cell::RefCell; -use std::rc::Rc; -use crate::types::*; -use crate::logger::*; /// Create the displayed presentation for log items. -pub trait LogRepr : Debug { - fn logrepr(&self) -> ColoredString { format!("« {self:?} »").as_str().into() } +pub trait LogRepr: Debug { + fn logrepr(&self) -> ColoredString { + format!("« {self:?} »").as_str().into() + } } impl LogRepr for str { - fn logrepr(&self) -> ColoredString { self.into() } + fn logrepr(&self) -> ColoredString { + self.into() + } } impl LogRepr for String { - fn logrepr(&self) -> ColoredString { self.as_str().into() } + fn logrepr(&self) -> ColoredString { + self.as_str().into() + } } -impl LogRepr for T where T : Num { - fn logrepr(&self) -> ColoredString { format!("J={self}").as_str().into() } +impl LogRepr for T +where + T: Num, +{ + fn logrepr(&self) -> ColoredString { + format!("J={self}").as_str().into() + } } -impl LogRepr for Option where V : LogRepr { +impl LogRepr for Option +where + V: LogRepr, +{ fn logrepr(&self) -> ColoredString { match self { - None => { "===missing value===".red() } - Some(v) => { v.logrepr() } + None => "===missing value===".red(), + Some(v) => v.logrepr(), } } } @@ -97,29 +111,33 @@ /// Helper struct for returning results annotated with an additional string to /// [`if_verbose`][AlgIteratorState::if_verbose]. The [`LogRepr`] implementation will /// display that string when so decided by the specific [`AlgIterator`] in use. -#[derive(Debug,Clone)] +#[derive(Debug, Clone)] pub struct Annotated(pub F, pub String); -impl LogRepr for Annotated where V : LogRepr { +impl LogRepr for Annotated +where + V: LogRepr, +{ fn logrepr(&self) -> ColoredString { - format!("{}\t| {}", self.0.logrepr(), self.1).as_str().into() + format!("{}\t| {}", self.0.logrepr(), self.1) + .as_str() + .into() } } - /// Basic log item. #[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)] pub struct LogItem { - pub iter : usize, + pub iter: usize, // This causes [`csv`] to crash. //#[serde(flatten)] - pub data : V + pub data: V, } impl LogItem { /// Creates a new log item - fn new(iter : usize, data : V) -> Self { - LogItem{ iter, data } + fn new(iter: usize, data: V) -> Self { + LogItem { iter, data } } } @@ -127,7 +145,7 @@ /// /// This is the parameter obtained by the closure passed to [`AlgIterator::iterate`] or /// [`AlgIteratorFactory::iterate`]. -pub trait AlgIteratorState : Sized { +pub trait AlgIteratorState: Sized { /// Call `call_objective` if this is a verbose iteration. /// /// Verbosity depends on the [`AlgIterator`] that produced this state. @@ -135,7 +153,7 @@ /// The closure `calc_objective` should return an arbitrary value of type `V`, to be inserted /// into the log, or whatever is deemed by the [`AlgIterator`]. For usage instructions see the /// [module documentation][self]. - fn if_verbose(self, calc_objective : impl FnOnce() -> V) -> Step; + fn if_verbose(self, calc_objective: impl FnOnce() -> V) -> Step; /// Returns the current iteration count. fn iteration(&self) -> usize; @@ -146,7 +164,7 @@ /// Result of a step of an [`AlgIterator`] #[derive(Debug, Serialize)] -pub enum Step { +pub enum Step { /// Iteration should be terminated Terminated, /// Iteration should be terminated due to failure @@ -157,19 +175,19 @@ Result(V, S), } -impl Step { +impl Step { /// Maps the value contained within the `Step`, if any, by the closure `f`. - pub fn map(self, mut f : impl FnMut(V) -> U) -> Step { + pub fn map(self, mut f: impl FnMut(V) -> U) -> Step { match self { - Step::Result(v, s) => Step::Result(f(v), s), + Step::Result(v, s) => Step::Result(f(v), s), Step::Failure(e) => Step::Failure(e), - Step::Quiet => Step::Quiet, + Step::Quiet => Step::Quiet, Step::Terminated => Step::Terminated, } } } -impl Default for Step { +impl Default for Step { fn default() -> Self { Step::Quiet } @@ -179,29 +197,34 @@ /// /// Typically not accessed directly, but transparently produced by an [`AlgIteratorFactory`]. /// Every [`AlgIteratorFactory`] has to implement a corresponding `AlgIterator`. -pub trait AlgIterator : Sized { +pub trait AlgIterator: Sized { /// The state type - type State : AlgIteratorState; + type State: AlgIteratorState; /// The output type for [`Self::poststep`] and [`Self::step`]. type Output; /// The input type for [`Self::poststep`]. type Input; /// Advance the iterator, performing `step_fn` with the state - fn step(&mut self, step_fn : &mut F) -> Step - where F : FnMut(Self::State) -> Step, - E : Error { - self.prestep().map_or(Step::Terminated, - |state| self.poststep(step_fn(state))) + fn step(&mut self, step_fn: &mut F) -> Step + where + F: FnMut(Self::State) -> Step, + E: Error, + { + self.prestep() + .map_or(Step::Terminated, |state| self.poststep(step_fn(state))) } /// Initial stage of advancing the iterator, before the actual step fn prestep(&mut self) -> Option; /// Handle step result - fn poststep(&mut self, result : Step) - -> Step - where E : Error; + fn poststep( + &mut self, + result: Step, + ) -> Step + where + E: Error; /// Return current iteration count. fn iteration(&self) -> usize { @@ -213,16 +236,18 @@ /// Iterate the `AlgIterator` until termination, erforming `step_fn` on each step. /// - /// Returns either `()` or an error if the step closure terminated in [`Step::Failure´]. + /// Returns either `()` or an error if the step closure terminated in [`Step::Failure`]. #[inline] - fn iterate(&mut self, mut step_fn : F) -> Result<(), E> - where F : FnMut(Self::State) -> Step, - E : Error { + fn iterate(&mut self, mut step_fn: F) -> Result<(), E> + where + F: FnMut(Self::State) -> Step, + E: Error, + { loop { match self.step(&mut step_fn) { Step::Terminated => return Ok(()), Step::Failure(e) => return Err(e), - _ => {}, + _ => {} } } } @@ -231,12 +256,12 @@ /// A factory for producing an [`AlgIterator`]. /// /// For usage instructions see the [module documentation][self]. -pub trait AlgIteratorFactory : Sized { - type Iter : AlgIterator; +pub trait AlgIteratorFactory: Sized { + type Iter: AlgIterator; /// The state type of the corresponding [`AlgIterator`]. /// A reference to this is passed to the closures passed to methods such as [`Self::iterate`]. - type State : AlgIteratorState; + type State: AlgIteratorState; /// The output type of the corresponding [`AlgIterator`]. /// This is the output of the closures passed to methods such as [`Self::iterate`] after /// mappings performed by each [`AlgIterator`] implementation. @@ -254,9 +279,11 @@ /// /// This method is equivalent to [`Self::prepare`] followed by [`AlgIterator::iterate`]. #[inline] - fn iterate_fallible(self, step : F) -> Result<(), E> - where F : FnMut(Self::State) -> Step, - E : Error { + fn iterate_fallible(self, step: F) -> Result<(), E> + where + F: FnMut(Self::State) -> Step, + E: Error, + { self.prepare().iterate(step) } @@ -271,8 +298,10 @@ /// This method is equivalent to [`Self::prepare`] followed by [`AlgIterator::iterate`] /// with the error type `E=`[`std::convert::Infallible`]. #[inline] - fn iterate(self, step : F) - where F : FnMut(Self::State) -> Step { + fn iterate(self, step: F) + where + F: FnMut(Self::State) -> Step, + { self.iterate_fallible(step).unwrap_or_default() } @@ -288,13 +317,16 @@ /// /// For usage instructions see the [module documentation][self]. #[inline] - fn iterate_data_fallible(self, mut datasource : I, mut step : F) - -> Result<(), E> - where F : FnMut(Self::State, D) -> Step, - I : Iterator, - E : Error { + fn iterate_data_fallible(self, mut datasource: I, mut step: F) -> Result<(), E> + where + F: FnMut(Self::State, D) -> Step, + I: Iterator, + E: Error, + { self.prepare().iterate(move |state| { - datasource.next().map_or(Step::Terminated, |d| step(state, d)) + datasource + .next() + .map_or(Step::Terminated, |d| step(state, d)) }) } @@ -309,10 +341,13 @@ /// /// For usage instructions see the [module documentation][self]. #[inline] - fn iterate_data(self, datasource : I, step : F) - where F : FnMut(Self::State, D) -> Step, - I : Iterator { - self.iterate_data_fallible(datasource, step).unwrap_or_default() + fn iterate_data(self, datasource: I, step: F) + where + F: FnMut(Self::State, D) -> Step, + I: Iterator, + { + self.iterate_data_fallible(datasource, step) + .unwrap_or_default() } // fn make_iterate<'own>(self) @@ -345,79 +380,87 @@ /// }) /// }) /// ``` - fn into_log<'log>(self, logger : &'log mut Logger) - -> LoggingIteratorFactory<'log, Self::Output, Self> - where Self : Sized { - LoggingIteratorFactory { - base_options : self, - logger, - } + fn into_log<'log>( + self, + logger: &'log mut Logger, + ) -> LoggingIteratorFactory<'log, Self::Output, Self> + where + Self: Sized, + { + LoggingIteratorFactory { base_options: self, logger } } /// Map the output of the iterator produced by the factory. /// /// Returns a new factory. - fn mapped(self, map : G) - -> MappingIteratorFactory - where Self : Sized, - G : Fn(usize, Self::Output) -> U { - MappingIteratorFactory { - base_options : self, - map - } + fn mapped(self, map: G) -> MappingIteratorFactory + where + Self: Sized, + G: Fn(usize, Self::Output) -> U, + { + MappingIteratorFactory { base_options: self, map } } /// Adds iteration number to the output. /// /// Returns a new factory. /// Typically followed by [`Self::into_log`]. - fn with_iteration_number(self) - -> MappingIteratorFactory LogItem, Self> - where Self : Sized { + fn with_iteration_number( + self, + ) -> MappingIteratorFactory LogItem, Self> + where + Self: Sized, + { self.mapped(LogItem::new) } /// Add timing to the iterator produced by the factory. fn timed(self) -> TimingIteratorFactory - where Self : Sized { + where + Self: Sized, + { TimingIteratorFactory(self) } /// Add value stopping threshold to the iterator produce by the factory - fn stop_target(self, target : Self::Output) -> ValueIteratorFactory - where Self : Sized, - Self::Output : Num { - ValueIteratorFactory { base_options : self, target : target } + fn stop_target(self, target: Self::Output) -> ValueIteratorFactory + where + Self: Sized, + Self::Output: Num, + { + ValueIteratorFactory { base_options: self, target: target } } /// Add stall stopping to the iterator produce by the factory - fn stop_stall(self, stall : Self::Output) -> StallIteratorFactory - where Self : Sized, - Self::Output : Num { - StallIteratorFactory { base_options : self, stall : stall } + fn stop_stall(self, stall: Self::Output) -> StallIteratorFactory + where + Self: Sized, + Self::Output: Num, + { + StallIteratorFactory { base_options: self, stall: stall } } /// Is the iterator quiet, i.e., on-verbose? - fn is_quiet(&self) -> bool { false } + fn is_quiet(&self) -> bool { + false + } /// Returns an an [`std::iter::Iterator`] that can be used in a `for`-loop. fn iter(self) -> AlgIteratorIterator { - AlgIteratorIterator { - algi : Rc::new(RefCell::new(self.prepare())), - } + AlgIteratorIterator { algi: Rc::new(RefCell::new(self.prepare())) } } /// Returns an an [`std::iter::Iterator`] that can be used in a `for`-loop, /// also inputting an initial iteration status calculated by `f` if needed. - fn iter_init(self, f : impl FnOnce() -> ::Input) - -> AlgIteratorIterator { + fn iter_init( + self, + f: impl FnOnce() -> ::Input, + ) -> AlgIteratorIterator { let mut i = self.prepare(); let st = i.state(); - let step : Step<::Input, Self::State> = st.if_verbose(f); + let step: Step<::Input, Self::State> = st.if_verbose(f); i.poststep(step); - AlgIteratorIterator { - algi : Rc::new(RefCell::new(i)), - } + AlgIteratorIterator { algi: Rc::new(RefCell::new(i)) } } } @@ -431,12 +474,12 @@ #[derive(Clone, Copy, Debug, Serialize, Deserialize, Eq, PartialEq)] pub struct AlgIteratorOptions { /// Maximum number of iterations - pub max_iter : usize, + pub max_iter: usize, /// Number of iterations between verbose iterations that display state. - pub verbose_iter : Verbose, + pub verbose_iter: Verbose, /// Whether verbose iterations are displayed, or just passed onwards to a containing /// `AlgIterator`. - pub quiet : bool, + pub quiet: bool, } #[derive(Clone, Copy, Debug, Serialize, Deserialize, Eq, PartialEq)] @@ -444,7 +487,7 @@ /// Be verbose every $n$ iterations. Every(usize), /// Be verbose every $n$ iterations and initial $m$ iterations. - EveryAndInitial{ every : usize, initial : usize }, + EveryAndInitial { every: usize, initial: usize }, /// Be verbose if iteration number $n$ divides by $b^{\text{floor}(\log_b(n))}$, where /// $b$ is indicated logarithmic base. So, with $b=10$, /// * every iteration for first 10 iterations, @@ -455,24 +498,22 @@ /// is the given `cap`. For example, with `base=10` and `cap=2`, the first ten iterations /// will be output, then every tenth iteration, and after 100 iterations, every 100th iteration, /// without further logarithmic progression. - LogarithmicCap{ base : usize, cap : u32 }, + LogarithmicCap { base: usize, cap: u32 }, } impl Verbose { /// Indicates whether given iteration number is verbose - pub fn is_verbose(&self, iter : usize) -> bool { + pub fn is_verbose(&self, iter: usize) -> bool { match self { - &Verbose::Every(every) => { - every != 0 && iter % every == 0 - }, - &Verbose::EveryAndInitial{ every, initial } => { + &Verbose::Every(every) => every != 0 && iter % every == 0, + &Verbose::EveryAndInitial { every, initial } => { iter <= initial || (every != 0 && iter % every == 0) - }, + } &Verbose::Logarithmic(base) => { let every = base.pow((iter as float).log(base as float).floor() as u32); iter % every == 0 } - &Verbose::LogarithmicCap{base, cap} => { + &Verbose::LogarithmicCap { base, cap } => { let every = base.pow(((iter as float).log(base as float).floor() as u32).min(cap)); iter % every == 0 } @@ -482,41 +523,41 @@ impl Default for AlgIteratorOptions { fn default() -> AlgIteratorOptions { - AlgIteratorOptions{ - max_iter : 1000, - verbose_iter : Verbose::EveryAndInitial { every : 100, initial : 10 }, - quiet : false + AlgIteratorOptions { + max_iter: 1000, + verbose_iter: Verbose::EveryAndInitial { every: 100, initial: 10 }, + quiet: false, } } } /// State of a `BasicAlgIterator` -#[derive(Clone,Copy,Debug,Serialize,Eq,PartialEq)] +#[derive(Clone, Copy, Debug, Serialize, Eq, PartialEq)] pub struct BasicState { /// Current iteration - iter : usize, + iter: usize, /// Whether the iteration is verbose, i.e., results should be displayed. /// Requires `calc` to be `true`. - verbose : bool, + verbose: bool, /// Whether results should be calculated. - calc : bool, + calc: bool, /// Indicates whether the iteration is quiet - quiet : bool, + quiet: bool, } /// [`AlgIteratorFactory`] for [`BasicAlgIterator`] -#[derive(Clone,Debug)] +#[derive(Clone, Debug)] pub struct BasicAlgIteratorFactory { - options : AlgIteratorOptions, - _phantoms : PhantomData, + options: AlgIteratorOptions, + _phantoms: PhantomData, } /// The simplest [`AlgIterator`], created by [`BasicAlgIteratorFactory`] -#[derive(Clone,Debug)] +#[derive(Clone, Debug)] pub struct BasicAlgIterator { - options : AlgIteratorOptions, - iter : usize, - _phantoms : PhantomData, + options: AlgIteratorOptions, + iter: usize, + _phantoms: PhantomData, } impl AlgIteratorOptions { @@ -524,25 +565,20 @@ /// however, due to type inference issues, it may become convenient to instantiate /// it to a specific return type for the inner step function. This method does that. pub fn instantiate(&self) -> BasicAlgIteratorFactory { - BasicAlgIteratorFactory { - options : self.clone(), - _phantoms : PhantomData - } + BasicAlgIteratorFactory { options: self.clone(), _phantoms: PhantomData } } } impl AlgIteratorFactory for AlgIteratorOptions -where V : LogRepr { +where + V: LogRepr, +{ type State = BasicState; type Iter = BasicAlgIterator; type Output = V; fn prepare(self) -> Self::Iter { - BasicAlgIterator{ - options : self, - iter : 0, - _phantoms : PhantomData, - } + BasicAlgIterator { options: self, iter: 0, _phantoms: PhantomData } } #[inline] @@ -552,17 +588,15 @@ } impl AlgIteratorFactory for BasicAlgIteratorFactory -where V : LogRepr { +where + V: LogRepr, +{ type State = BasicState; type Iter = BasicAlgIterator; type Output = V; fn prepare(self) -> Self::Iter { - BasicAlgIterator { - options : self.options, - iter : 0, - _phantoms : PhantomData - } + BasicAlgIterator { options: self.options, iter: 0, _phantoms: PhantomData } } #[inline] @@ -572,7 +606,9 @@ } impl AlgIterator for BasicAlgIterator -where V : LogRepr { +where + V: LogRepr, +{ type State = BasicState; type Output = V; type Input = V; @@ -587,14 +623,17 @@ } } - fn poststep(&mut self, res : Step) -> Step { + fn poststep(&mut self, res: Step) -> Step { if let Step::Result(ref val, ref state) = res { if state.verbose && !self.options.quiet { - println!("{}{}/{} {}{}", "".dimmed(), - state.iter, - self.options.max_iter, - val.logrepr(), - "".clear()); + println!( + "{}{}/{} {}{}", + "".dimmed(), + state.iter, + self.options.max_iter, + val.logrepr(), + "".clear() + ); } } res @@ -609,18 +648,13 @@ fn state(&self) -> BasicState { let iter = self.iter; let verbose = self.options.verbose_iter.is_verbose(iter); - BasicState { - iter : iter, - verbose : verbose, - calc : verbose, - quiet : self.options.quiet - } + BasicState { iter: iter, verbose: verbose, calc: verbose, quiet: self.options.quiet } } } impl AlgIteratorState for BasicState { #[inline] - fn if_verbose(self, calc_objective : impl FnOnce() -> V) -> Step { + fn if_verbose(self, calc_objective: impl FnOnce() -> V) -> Step { if self.calc { Step::Result(calc_objective(), self) } else { @@ -647,34 +681,35 @@ /// /// We define stall as $(v_{k+n}-v_k)/v_k ≤ θ$, where $n$ the distance between /// [`Step::Result`] iterations, and $θ$ is the provided `stall` parameter. -#[derive(Clone,Copy,Debug,Serialize,Eq,PartialEq)] -pub struct StallIteratorFactory { +#[derive(Clone, Copy, Debug, Serialize, Eq, PartialEq)] +pub struct StallIteratorFactory { /// An [`AlgIteratorFactory`] on which to build on - pub base_options : BaseFactory, + pub base_options: BaseFactory, /// Stalling threshold $θ$. - pub stall : U, + pub stall: U, } /// Iterator produced by [`StallIteratorFactory`]. -pub struct StallIterator { - base_iterator : BaseIterator, - stall : U, - previous_value : Option, +pub struct StallIterator { + base_iterator: BaseIterator, + stall: U, + previous_value: Option, } -impl AlgIteratorFactory -for StallIteratorFactory -where BaseFactory : AlgIteratorFactory, - U : SignedNum + PartialOrd { +impl AlgIteratorFactory for StallIteratorFactory +where + BaseFactory: AlgIteratorFactory, + U: SignedNum + PartialOrd, +{ type Iter = StallIterator; type State = BaseFactory::State; type Output = BaseFactory::Output; fn prepare(self) -> Self::Iter { StallIterator { - base_iterator : self.base_options.prepare(), - stall : self.stall, - previous_value : None, + base_iterator: self.base_options.prepare(), + stall: self.stall, + previous_value: None, } } @@ -683,10 +718,11 @@ } } -impl AlgIterator -for StallIterator -where BaseIterator : AlgIterator, - U : SignedNum + PartialOrd { +impl AlgIterator for StallIterator +where + BaseIterator: AlgIterator, + U: SignedNum + PartialOrd, +{ type State = BaseIterator::State; type Output = U; type Input = BaseIterator::Input; @@ -697,8 +733,10 @@ } #[inline] - fn poststep(&mut self, res : Step) -> Step - where E : Error { + fn poststep(&mut self, res: Step) -> Step + where + E: Error, + { match self.base_iterator.poststep(res) { Step::Result(nv, state) => { let previous_v = self.previous_value; @@ -707,7 +745,7 @@ Some(pv) if (nv - pv).abs() <= self.stall * pv.abs() => Step::Terminated, _ => Step::Result(nv, state), } - }, + } val => val, } } @@ -725,33 +763,31 @@ /// An [`AlgIteratorFactory`] for an [`AlgIterator`] that detect whether step function /// return value is less than `target`, and terminates if it is. -#[derive(Clone,Copy,Debug,Serialize,Eq,PartialEq)] -pub struct ValueIteratorFactory { +#[derive(Clone, Copy, Debug, Serialize, Eq, PartialEq)] +pub struct ValueIteratorFactory { /// An [`AlgIteratorFactory`] on which to build on - pub base_options : BaseFactory, + pub base_options: BaseFactory, /// Target value - pub target : U, + pub target: U, } /// Iterator produced by [`ValueIteratorFactory`]. -pub struct ValueIterator { - base_iterator : BaseIterator, - target : U, +pub struct ValueIterator { + base_iterator: BaseIterator, + target: U, } -impl AlgIteratorFactory -for ValueIteratorFactory -where BaseFactory : AlgIteratorFactory, - U : SignedNum + PartialOrd { +impl AlgIteratorFactory for ValueIteratorFactory +where + BaseFactory: AlgIteratorFactory, + U: SignedNum + PartialOrd, +{ type Iter = ValueIterator; type State = BaseFactory::State; type Output = BaseFactory::Output; fn prepare(self) -> Self::Iter { - ValueIterator { - base_iterator : self.base_options.prepare(), - target : self.target - } + ValueIterator { base_iterator: self.base_options.prepare(), target: self.target } } fn is_quiet(&self) -> bool { @@ -759,10 +795,11 @@ } } -impl AlgIterator -for ValueIterator -where BaseIterator : AlgIterator, - U : SignedNum + PartialOrd { +impl AlgIterator for ValueIterator +where + BaseIterator: AlgIterator, + U: SignedNum + PartialOrd, +{ type State = BaseIterator::State; type Output = U; type Input = BaseIterator::Input; @@ -773,15 +810,18 @@ } #[inline] - fn poststep(&mut self, res : Step) -> Step where E : Error{ + fn poststep(&mut self, res: Step) -> Step + where + E: Error, + { match self.base_iterator.poststep(res) { Step::Result(v, state) => { - if v <= self.target { + if v <= self.target { Step::Terminated - } else { + } else { Step::Result(v, state) - } - }, + } + } val => val, } } @@ -808,31 +848,29 @@ #[derive(Debug)] pub struct LoggingIteratorFactory<'log, U, BaseFactory> { /// Base [`AlgIteratorFactory`] on which to build - base_options : BaseFactory, + base_options: BaseFactory, /// The `Logger` to use. - logger : &'log mut Logger, + logger: &'log mut Logger, } /// Iterator produced by `LoggingIteratorFactory`. pub struct LoggingIterator<'log, U, BaseIterator> { - base_iterator : BaseIterator, - logger : &'log mut Logger, + base_iterator: BaseIterator, + logger: &'log mut Logger, } - impl<'log, V, BaseFactory> AlgIteratorFactory -for LoggingIteratorFactory<'log, BaseFactory::Output, BaseFactory> -where BaseFactory : AlgIteratorFactory, - BaseFactory::Output : 'log { + for LoggingIteratorFactory<'log, BaseFactory::Output, BaseFactory> +where + BaseFactory: AlgIteratorFactory, + BaseFactory::Output: 'log, +{ type State = BaseFactory::State; type Iter = LoggingIterator<'log, BaseFactory::Output, BaseFactory::Iter>; type Output = (); fn prepare(self) -> Self::Iter { - LoggingIterator { - base_iterator : self.base_options.prepare(), - logger : self.logger, - } + LoggingIterator { base_iterator: self.base_options.prepare(), logger: self.logger } } #[inline] @@ -841,10 +879,11 @@ } } -impl<'log, BaseIterator> AlgIterator -for LoggingIterator<'log, BaseIterator::Output, BaseIterator> -where BaseIterator : AlgIterator, - BaseIterator::Output : 'log { +impl<'log, BaseIterator> AlgIterator for LoggingIterator<'log, BaseIterator::Output, BaseIterator> +where + BaseIterator: AlgIterator, + BaseIterator::Output: 'log, +{ type State = BaseIterator::State; type Output = (); type Input = BaseIterator::Input; @@ -855,12 +894,15 @@ } #[inline] - fn poststep(&mut self, res : Step) -> Step<(), Self::State, E> where E : Error { + fn poststep(&mut self, res: Step) -> Step<(), Self::State, E> + where + E: Error, + { match self.base_iterator.poststep(res) { Step::Result(v, _) => { self.logger.log(v); Step::Quiet - }, + } Step::Quiet => Step::Quiet, Step::Terminated => Step::Terminated, Step::Failure(e) => Step::Failure(e), @@ -884,32 +926,29 @@ #[derive(Debug)] pub struct MappingIteratorFactory { /// Base [`AlgIteratorFactory`] on which to build - base_options : BaseFactory, + base_options: BaseFactory, /// A closure `G : Fn(usize, BaseFactory::Output) -> U` that gets the current iteration /// and the output of the base factory as input, and produces a new output. - map : G, + map: G, } /// [`AlgIterator`] produced by [`MappingIteratorFactory`]. pub struct MappingIterator { - base_iterator : BaseIterator, - map : G, + base_iterator: BaseIterator, + map: G, } - -impl AlgIteratorFactory -for MappingIteratorFactory -where BaseFactory : AlgIteratorFactory, - G : Fn(usize, BaseFactory::Output) -> U { +impl AlgIteratorFactory for MappingIteratorFactory +where + BaseFactory: AlgIteratorFactory, + G: Fn(usize, BaseFactory::Output) -> U, +{ type State = BaseFactory::State; type Iter = MappingIterator; type Output = U; fn prepare(self) -> Self::Iter { - MappingIterator { - base_iterator : self.base_options.prepare(), - map : self.map - } + MappingIterator { base_iterator: self.base_options.prepare(), map: self.map } } #[inline] @@ -918,10 +957,11 @@ } } -impl AlgIterator -for MappingIterator -where BaseIterator : AlgIterator, - G : Fn(usize, BaseIterator::Output) -> U { +impl AlgIterator for MappingIterator +where + BaseIterator: AlgIterator, + G: Fn(usize, BaseIterator::Output) -> U, +{ type State = BaseIterator::State; type Output = U; type Input = BaseIterator::Input; @@ -932,7 +972,13 @@ } #[inline] - fn poststep(&mut self, res : Step) -> Step where E : Error { + fn poststep( + &mut self, + res: Step, + ) -> Step + where + E: Error, + { match self.base_iterator.poststep(res) { Step::Result(v, state) => Step::Result((self.map)(self.iteration(), v), state), Step::Quiet => Step::Quiet, @@ -963,41 +1009,47 @@ /// Iterator produced by [`TimingIteratorFactory`] #[derive(Debug)] pub struct TimingIterator { - base_iterator : BaseIterator, - start_time : ProcessTime, + base_iterator: BaseIterator, + start_time: ProcessTime, } /// Data `U` with production time attached #[derive(Copy, Clone, Debug, Serialize)] pub struct Timed { /// CPU time taken - pub cpu_time : Duration, + pub cpu_time: Duration, /// Iteration number - pub iter : usize, + pub iter: usize, /// User data //#[serde(flatten)] - pub data : U + pub data: U, } -impl LogRepr for Timed where T : LogRepr { +impl LogRepr for Timed +where + T: LogRepr, +{ fn logrepr(&self) -> ColoredString { - format!("[{:.3}s] {}", self.cpu_time.as_secs_f64(), self.data.logrepr()).as_str().into() + format!( + "[{:.3}s] {}", + self.cpu_time.as_secs_f64(), + self.data.logrepr() + ) + .as_str() + .into() } } - -impl AlgIteratorFactory -for TimingIteratorFactory -where BaseFactory : AlgIteratorFactory { +impl AlgIteratorFactory for TimingIteratorFactory +where + BaseFactory: AlgIteratorFactory, +{ type State = BaseFactory::State; type Iter = TimingIterator; type Output = Timed; fn prepare(self) -> Self::Iter { - TimingIterator { - base_iterator : self.0.prepare(), - start_time : ProcessTime::now() - } + TimingIterator { base_iterator: self.0.prepare(), start_time: ProcessTime::now() } } #[inline] @@ -1006,9 +1058,10 @@ } } -impl AlgIterator -for TimingIterator -where BaseIterator : AlgIterator { +impl AlgIterator for TimingIterator +where + BaseIterator: AlgIterator, +{ type State = BaseIterator::State; type Output = Timed; type Input = BaseIterator::Input; @@ -1019,15 +1072,18 @@ } #[inline] - fn poststep(&mut self, res : Step) -> Step where E : Error { + fn poststep( + &mut self, + res: Step, + ) -> Step + where + E: Error, + { match self.base_iterator.poststep(res) { - Step::Result(data, state) => { - Step::Result(Timed{ - cpu_time : self.start_time.elapsed(), - iter : self.iteration(), - data - }, state) - }, + Step::Result(data, state) => Step::Result( + Timed { cpu_time: self.start_time.elapsed(), iter: self.iteration(), data }, + state, + ), Step::Quiet => Step::Quiet, Step::Terminated => Step::Terminated, Step::Failure(e) => Step::Failure(e), @@ -1049,35 +1105,34 @@ // New for-loop interface // -pub struct AlgIteratorIterator { - algi : Rc>, +pub struct AlgIteratorIterator { + algi: Rc>, } -pub struct AlgIteratorIteration { - state : I::State, - algi : Rc>, +pub struct AlgIteratorIteration { + state: I::State, + algi: Rc>, } -impl std::iter::Iterator for AlgIteratorIterator { +impl std::iter::Iterator for AlgIteratorIterator { type Item = AlgIteratorIteration; fn next(&mut self) -> Option { let algi = self.algi.clone(); - RefCell::borrow_mut(&self.algi).prestep().map(|state| AlgIteratorIteration { - state, - algi, - }) + RefCell::borrow_mut(&self.algi) + .prestep() + .map(|state| AlgIteratorIteration { state, algi }) } } /// Types of errors that may occur -#[derive(Debug,PartialEq,Eq)] +#[derive(Debug, PartialEq, Eq)] pub enum IterationError { /// [`AlgIteratorIteration::if_verbose_check`] is not called in iteration order. - ReportingOrderingError + ReportingOrderingError, } -impl AlgIteratorIteration { +impl AlgIteratorIteration { /// Call `call_objective` if this is a verbose iteration. /// /// Verbosity depends on the [`AlgIterator`] that produced this state. @@ -1089,22 +1144,24 @@ /// This function may panic if result reporting is not ordered correctly (an unlikely mistake /// if using this facility correctly). For a version that propagates errors, see /// [`Self::if_verbose_check`]. - pub fn if_verbose(self, calc_objective : impl FnOnce() -> I::Input) { + pub fn if_verbose(self, calc_objective: impl FnOnce() -> I::Input) { self.if_verbose_check(calc_objective).unwrap() } /// Version of [`Self::if_verbose`] that propagates errors instead of panicking. - pub fn if_verbose_check(self, calc_objective : impl FnOnce() -> I::Input) - -> Result<(), IterationError> { + pub fn if_verbose_check( + self, + calc_objective: impl FnOnce() -> I::Input, + ) -> Result<(), IterationError> { let mut algi = match RefCell::try_borrow_mut(&self.algi) { Err(_) => return Err(IterationError::ReportingOrderingError), - Ok(algi) => algi + Ok(algi) => algi, }; if self.state.iteration() != algi.iteration() { Err(IterationError::ReportingOrderingError) } else { - let res : Step - = self.state.if_verbose(calc_objective); + let res: Step = + self.state.if_verbose(calc_objective); algi.poststep(res); Ok(()) } @@ -1131,10 +1188,10 @@ use crate::logger::Logger; #[test] fn iteration() { - let options = AlgIteratorOptions{ - max_iter : 10, - verbose_iter : Verbose::Every(3), - .. Default::default() + let options = AlgIteratorOptions { + max_iter: 10, + verbose_iter: Verbose::Every(3), + ..Default::default() }; { @@ -1149,31 +1206,35 @@ { let mut start = 1 as int; let mut log = Logger::new(); - let factory = options.instantiate() - .with_iteration_number() - .into_log(&mut log); + let factory = options + .instantiate() + .with_iteration_number() + .into_log(&mut log); factory.iterate(|state| { start = start * 2; state.if_verbose(|| start) }); assert_eq!(start, (2 as int).pow(10)); - assert_eq!(log.data() - .iter() - .map(|LogItem{ data : v, iter : _ }| v.clone()) - .collect::>(), - (1..10).map(|i| (2 as int).pow(i)) - .skip(2) - .step_by(3) - .collect::>()) + assert_eq!( + log.data() + .iter() + .map(|LogItem { data: v, iter: _ }| v.clone()) + .collect::>(), + (1..10) + .map(|i| (2 as int).pow(i)) + .skip(2) + .step_by(3) + .collect::>() + ) } } #[test] fn iteration_for_loop() { - let options = AlgIteratorOptions{ - max_iter : 10, - verbose_iter : Verbose::Every(3), - .. Default::default() + let options = AlgIteratorOptions { + max_iter: 10, + verbose_iter: Verbose::Every(3), + ..Default::default() }; { @@ -1188,23 +1249,26 @@ { let mut start = 1 as int; let mut log = Logger::new(); - let factory = options.instantiate() - .with_iteration_number() - .into_log(&mut log); + let factory = options + .instantiate() + .with_iteration_number() + .into_log(&mut log); for state in factory.iter() { start = start * 2; state.if_verbose(|| start) } assert_eq!(start, (2 as int).pow(10)); - assert_eq!(log.data() - .iter() - .map(|LogItem{ data : v, iter : _ }| v.clone()) - .collect::>(), - (1..10).map(|i| (2 as int).pow(i)) - .skip(2) - .step_by(3) - .collect::>()) + assert_eq!( + log.data() + .iter() + .map(|LogItem { data: v, iter: _ }| v.clone()) + .collect::>(), + (1..10) + .map(|i| (2 as int).pow(i)) + .skip(2) + .step_by(3) + .collect::>() + ) } } - } diff -r 3697375f4ee9 -r 1f301affeae3 src/linops.rs --- a/src/linops.rs Thu Mar 19 18:21:40 2026 -0500 +++ b/src/linops.rs Wed Apr 22 23:41:59 2026 -0500 @@ -1059,7 +1059,7 @@ /// The simplest linear mapping, scaling by a scalar. /// -/// TODO: redefined/replace [`Weighted`] by composition with [`Scaled`]. +/// TODO: redefined/replace `Weighted` by composition with [`Scaled`]. pub struct Scaled(pub F); impl Mapping for Scaled diff -r 3697375f4ee9 -r 1f301affeae3 src/parallelism.rs --- a/src/parallelism.rs Thu Mar 19 18:21:40 2026 -0500 +++ b/src/parallelism.rs Wed Apr 22 23:41:59 2026 -0500 @@ -7,24 +7,24 @@ For actually spawning scoped tasks in a thread pool, it currently uses [`rayon`]. */ -use std::sync::Once; +pub use rayon::{Scope, ThreadPool, ThreadPoolBuilder}; use std::num::NonZeroUsize; -use std::thread::available_parallelism; -pub use rayon::{Scope, ThreadPoolBuilder, ThreadPool}; use std::sync::atomic::{ AtomicUsize, - Ordering::{Release, Relaxed}, + Ordering::{Relaxed, Release}, }; +use std::sync::Once; +use std::thread::available_parallelism; #[cfg(feature = "use_custom_thread_pool")] type Pool = ThreadPool; #[cfg(not(feature = "use_custom_thread_pool"))] type Pool = GlobalPool; -const ONE : NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(1) }; -static mut TASK_OVERBUDGETING : AtomicUsize = AtomicUsize::new(1); -static mut N_THREADS : NonZeroUsize = ONE; -static mut POOL : Option = None; +const ONE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(1) }; +static mut TASK_OVERBUDGETING: AtomicUsize = AtomicUsize::new(1); +static mut N_THREADS: NonZeroUsize = ONE; +static mut POOL: Option = None; static INIT: Once = Once::new(); #[cfg(not(feature = "use_custom_thread_pool"))] @@ -38,7 +38,8 @@ pub fn scope<'scope, OP, R>(&self, op: OP) -> R where OP: FnOnce(&rayon::Scope<'scope>) -> R + Send, - R: Send { + R: Send, + { rayon::scope(op) } } @@ -51,17 +52,22 @@ /// /// This routine can only be called once. /// It also calls [`set_task_overbudgeting`] with $m = (n + 1) / 2$. -pub fn set_num_threads(n : NonZeroUsize) { +pub fn set_num_threads(n: NonZeroUsize) { INIT.call_once(|| unsafe { N_THREADS = n; let n = n.get(); set_task_overbudgeting((n + 1) / 2); POOL = if n > 1 { - #[cfg(feature = "use_custom_thread_pool")] { + #[cfg(feature = "use_custom_thread_pool")] + { Some(ThreadPoolBuilder::new().num_threads(n).build().unwrap()) } - #[cfg(not(feature = "use_custom_thread_pool"))] { - ThreadPoolBuilder::new().num_threads(n).build_global().unwrap(); + #[cfg(not(feature = "use_custom_thread_pool"))] + { + ThreadPoolBuilder::new() + .num_threads(n) + .build_global() + .unwrap(); Some(GlobalPool) } } else { @@ -74,20 +80,21 @@ /// /// The initial value is 1. Calling [`set_num_threads`] sets this to $m = (n + 1) / 2$, where /// $n$ is the number of threads. -pub fn set_task_overbudgeting(m : usize) { +pub fn set_task_overbudgeting(m: usize) { #[allow(static_mut_refs)] - unsafe { TASK_OVERBUDGETING.store(m, Relaxed) } + unsafe { + TASK_OVERBUDGETING.store(m, Relaxed) + } } /// Set the number of threads to the minimum of `n` and [`available_parallelism`]. /// /// This routine can only be called once. -pub fn set_max_threads(n : NonZeroUsize) { +pub fn set_max_threads(n: NonZeroUsize) { let available = available_parallelism().unwrap_or(ONE); set_num_threads(available.min(n)); } - /// Get the number of threads pub fn num_threads() -> NonZeroUsize { unsafe { N_THREADS } @@ -99,7 +106,9 @@ /// The pool has [`num_threads`]` - 1` threads. pub fn thread_pool() -> Option<&'static Pool> { #[allow(static_mut_refs)] - unsafe { POOL.as_ref() } + unsafe { + POOL.as_ref() + } } /// Get the number of thread pool workers. @@ -119,25 +128,25 @@ /// Initial multi-threaded state MultiThreadedInitial { /// Thread budget counter - budget : AtomicUsize, + budget: AtomicUsize, /// Thread pool - pool : &'scheduler Pool, + pool: &'scheduler Pool, }, /// Nested multi-threaded state MultiThreadedZoom { /// Thread budget reference - budget : &'scope AtomicUsize, - scope : &'scheduler Scope<'scope>, - } + budget: &'scope AtomicUsize, + scope: &'scheduler Scope<'scope>, + }, } /// Task execution scope for [`TaskBudget`]. pub enum TaskBudgetScope<'scope, 'scheduler> { SingleThreaded, MultiThreaded { - budget : &'scope AtomicUsize, - scope : &'scheduler Scope<'scope>, - } + budget: &'scope AtomicUsize, + scope: &'scheduler Scope<'scope>, + }, } impl<'scope, 'b> TaskBudget<'scope, 'b> { @@ -146,7 +155,7 @@ /// The number of tasks [executed][TaskBudgetScope::execute] in [scopes][TaskBudget::zoom] /// created through the budget is limited to [`num_threads()`]` + overbudget`. If `overbudget` /// is `None`, the [global setting][set_task_overbudgeting] is used.§ - pub fn init(overbudget : Option) -> Self { + pub fn init(overbudget: Option) -> Self { let n = num_threads().get(); #[allow(static_mut_refs)] let m = overbudget.unwrap_or_else(|| unsafe { TASK_OVERBUDGETING.load(Relaxed) }); @@ -161,14 +170,18 @@ } /// Initialise single-threaded thread budgeting. - pub fn none() -> Self { Self::SingleThreaded } + pub fn none() -> Self { + Self::SingleThreaded + } } impl<'scope, 'scheduler> TaskBudget<'scope, 'scheduler> { /// Create a sub-scope for launching tasks - pub fn zoom<'smaller, F, R : Send>(&self, scheduler : F) -> R - where 'scope : 'smaller, - F : for<'a> FnOnce(TaskBudgetScope<'smaller, 'a>) -> R + Send + 'smaller { + pub fn zoom<'smaller, F, R: Send>(&self, scheduler: F) -> R + where + 'scope: 'smaller, + F: for<'a> FnOnce(TaskBudgetScope<'smaller, 'a>) -> R + Send + 'smaller, + { match self { &Self::SingleThreaded => scheduler(TaskBudgetScope::SingleThreaded), &Self::MultiThreadedInitial { ref budget, pool } => { @@ -191,15 +204,16 @@ impl<'scope, 'scheduler> TaskBudgetScope<'scope, 'scheduler> { /// Queue a task or execute it in this thread if the thread budget is exhausted. - pub fn execute(&self, job : F) - where F : for<'b> FnOnce(TaskBudget<'scope, 'b>) + Send + 'scope { + pub fn execute(&self, job: F) + where + F: for<'b> FnOnce(TaskBudget<'scope, 'b>) + Send + 'scope, + { match self { Self::SingleThreaded => job(TaskBudget::SingleThreaded), Self::MultiThreaded { scope, budget } => { - let spawn = budget.fetch_update(Release, - Relaxed, - |n| (n > 1).then_some(n - 1)) - .is_ok(); + let spawn = budget + .fetch_update(Release, Relaxed, |n| (n > 1).then_some(n - 1)) + .is_ok(); if spawn { scope.spawn(|scope| { let task_budget = TaskBudget::MultiThreadedZoom { scope, budget }; @@ -216,8 +230,10 @@ /// Runs `scheduler` with a [`TaskBudget`]. /// -/// This corresponds to calling `scheduler` with [`TaskBudget::init(None)`]. -pub fn with_task_budget<'scope, F, R>(scheduler : F) -> R -where F : for<'b> FnOnce(TaskBudget<'scope, 'b>) -> R + 'scope { +/// This corresponds to calling `scheduler` with [`TaskBudget::init`]`(None)`. +pub fn with_task_budget<'scope, F, R>(scheduler: F) -> R +where + F: for<'b> FnOnce(TaskBudget<'scope, 'b>) -> R + 'scope, +{ scheduler(TaskBudget::init(None)) }