Compare commits

...

4 Commits

Author SHA1 Message Date
John Nunley 7b7c472203
feat: Add generic collection methods (#9) 2022-12-31 19:04:52 -08:00
Taiki Endo 23e9387721 Enable dependabot update for Rust 2022-12-28 12:37:09 +09:00
Taiki Endo ef8e467463 Clean up CI config 2022-12-28 12:37:09 +09:00
Taiki Endo 675298d76f Remove msrv field from .clippy.toml
Since Rust 1.64, Clippy respects `rust-version` field in Cargo.toml.
rust-lang/rust@b776fb8
2022-12-28 12:37:09 +09:00
4 changed files with 88 additions and 14 deletions

View File

@ -1 +0,0 @@
msrv = "1.35"

9
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,9 @@
version: 2
updates:
- package-ecosystem: cargo
directory: /
schedule:
interval: weekly
commit-message:
prefix: ''
labels: []

View File

@ -6,11 +6,20 @@ on:
branches:
- master
schedule:
- cron: '0 2 * * *'
- cron: '0 2 * * 0'
env:
RUSTFLAGS: -D warnings
CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
RUSTFLAGS: -D warnings
RUSTDOCFLAGS: -D warnings
RUSTUP_MAX_RETRIES: 10
defaults:
run:
shell: bash
jobs:
test:
@ -35,7 +44,7 @@ jobs:
strategy:
matrix:
# When updating this, the reminder to update the minimum supported
# Rust version in Cargo.toml and .clippy.toml.
# Rust version in Cargo.toml.
rust: ['1.35']
steps:
- uses: actions/checkout@v3
@ -74,6 +83,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/audit-check@v1
# https://github.com/rustsec/audit-check/issues/2
- uses: rustsec/audit-check@master
with:
token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -59,6 +59,7 @@
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
use std::fmt;
use std::iter::{self, FromIterator};
use std::mem;
use std::panic;
use std::process;
@ -153,26 +154,55 @@ impl<'a, T> Parallel<'a, T> {
/// let res = Parallel::new()
/// .each(1..=3, |i| 10 * i)
/// .add(|| 100)
/// .run();
/// .collect::<Vec<_>>();
///
/// assert_eq!(res, [10, 20, 30, 100]);
/// ```
pub fn run(mut self) -> Vec<T>
pub fn collect<C>(mut self) -> C
where
T: Send + 'a,
C: FromIterator<T> + Extend<T>,
{
// Get the last closure.
let f = match self.closures.pop() {
None => return Vec::new(),
None => return iter::empty().collect(),
Some(f) => f,
};
// Spawn threads, run the last closure on the current thread.
let (mut results, r) = self.finish(f);
results.push(r);
let (mut results, r) = self.finish_in::<_, _, C>(f);
results.extend(Some(r));
results
}
/// Runs each closure on a separate thread and collects their results.
///
/// Results are collected in the order in which closures were added. One of the closures always
/// runs on the main thread because there is no point in spawning an extra thread for it.
///
/// If a closure panics, panicking will resume in the main thread after all threads are joined.
///
/// # Examples
///
/// ```
/// use easy_parallel::Parallel;
/// use std::thread;
/// use std::time::Duration;
///
/// let res = Parallel::new()
/// .each(1..=3, |i| 10 * i)
/// .add(|| 100)
/// .run();
///
/// assert_eq!(res, [10, 20, 30, 100]);
/// ```
pub fn run(self) -> Vec<T>
where
T: Send + 'a,
{
self.collect()
}
/// Finishes with a closure to run on the main thread, starts threads, and collects results.
///
/// Results are collected in the order in which closures were added.
@ -196,6 +226,35 @@ impl<'a, T> Parallel<'a, T> {
where
F: FnOnce() -> R,
T: Send + 'a,
{
self.finish_in::<_, _, Vec<T>>(f)
}
/// Finishes with a closure to run on the main thread, starts threads, and collects results into an
/// arbitrary container.
///
/// Results are collected in the order in which closures were added.
///
/// If a closure panics, panicking will resume in the main thread after all threads are joined.
///
/// # Examples
///
/// ```
/// use easy_parallel::Parallel;
/// use std::thread;
/// use std::time::Duration;
///
/// let (res, ()) = Parallel::new()
/// .each(1..=3, |i| 10 * i)
/// .finish_in::<_, _, Vec<i32>>(|| println!("Waiting for results"));
///
/// assert_eq!(res, [10, 20, 30]);
/// ```
pub fn finish_in<F, R, C>(self, f: F) -> (C, R)
where
F: FnOnce() -> R,
T: Send + 'a,
C: FromIterator<T>,
{
// Set up a guard that aborts on panic.
let guard = NoPanic;
@ -242,10 +301,7 @@ impl<'a, T> Parallel<'a, T> {
}
// Collect the results from threads.
let mut results = Vec::new();
for receiver in receivers {
results.push(receiver.recv().unwrap());
}
let results = receivers.into_iter().map(|r| r.recv().unwrap()).collect();
// If the main closure panicked, resume its panic.
match res {