upstream stdx changes
diff --git a/Cargo.lock b/Cargo.lock
index b6a32d5..0d509f5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1083,9 +1083,9 @@
[[package]]
name = "jod-thread"
-version = "0.1.2"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b23360e99b8717f20aaa4598f5a6541efbe30630039fbc7706cf954a87947ae"
+checksum = "a037eddb7d28de1d0fc42411f501b53b75838d313908078d6698d064f3029b24"
[[package]]
name = "kqueue"
diff --git a/crates/stdx/Cargo.toml b/crates/stdx/Cargo.toml
index 7603330..7bda106 100644
--- a/crates/stdx/Cargo.toml
+++ b/crates/stdx/Cargo.toml
@@ -13,7 +13,7 @@
[dependencies]
backtrace = { version = "0.3.74", optional = true }
-jod-thread = "0.1.2"
+jod-thread = "1.0.0"
crossbeam-channel.workspace = true
itertools.workspace = true
tracing.workspace = true
diff --git a/crates/stdx/src/anymap.rs b/crates/stdx/src/anymap.rs
index 0c39419..f55698e 100644
--- a/crates/stdx/src/anymap.rs
+++ b/crates/stdx/src/anymap.rs
@@ -1,4 +1,5 @@
//! This file is a port of only the necessary features from <https://github.com/chris-morgan/anymap> version 1.0.0-beta.2 for use within rust-analyzer.
+//!
//! Copyright © 2014–2022 Chris Morgan.
//! COPYING: <https://github.com/chris-morgan/anymap/blob/master/COPYING>
//! Note that the license is changed from Blue Oak Model 1.0.0 or MIT or Apache-2.0 to MIT OR Apache-2.0
@@ -20,14 +21,14 @@
use core::hash::Hasher;
-/// A hasher designed to eke a little more speed out, given `TypeId`’s known characteristics.
+/// A hasher designed to eke a little more speed out, given `TypeId`'s known characteristics.
///
-/// Specifically, this is a no-op hasher that expects to be fed a u64’s worth of
+/// Specifically, this is a no-op hasher that expects to be fed a u64's worth of
/// randomly-distributed bits. It works well for `TypeId` (eliminating start-up time, so that my
-/// get_missing benchmark is ~30ns rather than ~900ns, and being a good deal faster after that, so
-/// that my insert_and_get_on_260_types benchmark is ~12μs instead of ~21.5μs), but will
+/// `get_missing` benchmark is ~30ns rather than ~900ns, and being a good deal faster after that, so
+/// that my `insert_and_get_on_260_types` benchmark is ~12μs instead of ~21.5μs), but will
/// panic in debug mode and always emit zeros in release mode for any other sorts of inputs, so
-/// yeah, don’t use it! 😀
+/// yeah, don't use it! 😀
#[derive(Default)]
pub struct TypeIdHasher {
value: u64,
@@ -36,9 +37,9 @@
impl Hasher for TypeIdHasher {
#[inline]
fn write(&mut self, bytes: &[u8]) {
- // This expects to receive exactly one 64-bit value, and there’s no realistic chance of
- // that changing, but I don’t want to depend on something that isn’t expressly part of the
- // contract for safety. But I’m OK with release builds putting everything in one bucket
+ // This expects to receive exactly one 64-bit value, and there's no realistic chance of
+ // that changing, but I don't want to depend on something that isn't expressly part of the
+ // contract for safety. But I'm OK with release builds putting everything in one bucket
// if it *did* change (and debug builds panicking).
debug_assert_eq!(bytes.len(), 8);
let _ = bytes.try_into().map(|array| self.value = u64::from_ne_bytes(array));
@@ -59,7 +60,7 @@
/// Raw access to the underlying `HashMap`.
///
/// This alias is provided for convenience because of the ugly third generic parameter.
-#[allow(clippy::disallowed_types)] // Uses a custom hasher
+#[expect(clippy::disallowed_types, reason = "Uses a custom hasher")]
pub type RawMap<A> = hash_map::HashMap<TypeId, Box<A>, BuildHasherDefault<TypeIdHasher>>;
/// A collection containing zero or one values for any given type and allowing convenient,
@@ -73,19 +74,20 @@
///
/// Cumulatively, there are thus six forms of map:
///
-/// - <code>[Map]<dyn [core::any::Any]></code>,
+/// - `[Map]<dyn [core::any::Any]>`,
/// also spelled [`AnyMap`] for convenience.
-/// - <code>[Map]<dyn [core::any::Any] + Send></code>
-/// - <code>[Map]<dyn [core::any::Any] + Send + Sync></code>
+/// - `[Map]<dyn [core::any::Any] + Send>`
+/// - `[Map]<dyn [core::any::Any] + Send + Sync>`
///
/// ## Example
///
-/// (Here using the [`AnyMap`] convenience alias; the first line could use
-/// <code>[anymap::Map][Map]::<[core::any::Any]>::new()</code> instead if desired.)
+/// (Here, the [`AnyMap`] convenience alias is used;
+/// the first line could use `[anymap::Map][Map]::<[core::any::Any]>::new()`
+/// instead if desired.)
///
/// ```
/// # use stdx::anymap;
-#[doc = "let mut data = anymap::AnyMap::new();"]
+/// let mut data = anymap::AnyMap::new();
/// assert_eq!(data.get(), None::<&i32>);
/// ```
///
@@ -95,11 +97,11 @@
raw: RawMap<A>,
}
-/// The most common type of `Map`: just using `Any`; <code>[Map]<dyn [Any]></code>.
+/// The most common type of `Map`: just using `Any`; `[Map]<dyn [Any]>`.
///
/// Why is this a separate type alias rather than a default value for `Map<A>`?
-/// `Map::new()` doesn’t seem to be happy to infer that it should go with the default
-/// value. It’s a bit sad, really. Ah well, I guess this approach will do.
+/// `Map::new()` doesn't seem to be happy to infer that it should go with the default
+/// value. It's a bit sad, really. Ah well, I guess this approach will do.
pub type AnyMap = Map<dyn Any>;
impl<A: ?Sized + Downcast> Default for Map<A> {
@@ -113,6 +115,7 @@
/// Returns a reference to the value stored in the collection for the type `T`,
/// if it exists.
#[inline]
+ #[must_use]
pub fn get<T: IntoBox<A>>(&self) -> Option<&T> {
self.raw.get(&TypeId::of::<T>()).map(|any| unsafe { any.downcast_ref_unchecked::<T>() })
}
@@ -132,30 +135,30 @@
}
/// A view into a single occupied location in an `Map`.
-pub struct OccupiedEntry<'a, A: ?Sized + Downcast, V: 'a> {
- inner: hash_map::OccupiedEntry<'a, TypeId, Box<A>>,
+pub struct OccupiedEntry<'map, A: ?Sized + Downcast, V: 'map> {
+ inner: hash_map::OccupiedEntry<'map, TypeId, Box<A>>,
type_: PhantomData<V>,
}
/// A view into a single empty location in an `Map`.
-pub struct VacantEntry<'a, A: ?Sized + Downcast, V: 'a> {
- inner: hash_map::VacantEntry<'a, TypeId, Box<A>>,
+pub struct VacantEntry<'map, A: ?Sized + Downcast, V: 'map> {
+ inner: hash_map::VacantEntry<'map, TypeId, Box<A>>,
type_: PhantomData<V>,
}
/// A view into a single location in an `Map`, which may be vacant or occupied.
-pub enum Entry<'a, A: ?Sized + Downcast, V> {
+pub enum Entry<'map, A: ?Sized + Downcast, V> {
/// An occupied Entry
- Occupied(OccupiedEntry<'a, A, V>),
+ Occupied(OccupiedEntry<'map, A, V>),
/// A vacant Entry
- Vacant(VacantEntry<'a, A, V>),
+ Vacant(VacantEntry<'map, A, V>),
}
-impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> Entry<'a, A, V> {
+impl<'map, A: ?Sized + Downcast, V: IntoBox<A>> Entry<'map, A, V> {
/// Ensures a value is in the entry by inserting the result of the default function if
/// empty, and returns a mutable reference to the value in the entry.
#[inline]
- pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
+ pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'map mut V {
match self {
Entry::Occupied(inner) => inner.into_mut(),
Entry::Vacant(inner) => inner.insert(default()),
@@ -163,20 +166,21 @@
}
}
-impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> OccupiedEntry<'a, A, V> {
- /// Converts the OccupiedEntry into a mutable reference to the value in the entry
+impl<'map, A: ?Sized + Downcast, V: IntoBox<A>> OccupiedEntry<'map, A, V> {
+ /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry
/// with a lifetime bound to the collection itself
#[inline]
- pub fn into_mut(self) -> &'a mut V {
+ #[must_use]
+ pub fn into_mut(self) -> &'map mut V {
unsafe { self.inner.into_mut().downcast_mut_unchecked() }
}
}
-impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> VacantEntry<'a, A, V> {
- /// Sets the value of the entry with the VacantEntry's key,
+impl<'map, A: ?Sized + Downcast, V: IntoBox<A>> VacantEntry<'map, A, V> {
+ /// Sets the value of the entry with the `VacantEntry`'s key,
/// and returns a mutable reference to it
#[inline]
- pub fn insert(self, value: V) -> &'a mut V {
+ pub fn insert(self, value: V) -> &'map mut V {
unsafe { self.inner.insert(value.into_box()).downcast_mut_unchecked() }
}
}
@@ -201,14 +205,13 @@
#[test]
fn type_id_hasher() {
use core::any::TypeId;
- use core::hash::Hash;
+ use core::hash::Hash as _;
fn verify_hashing_with(type_id: TypeId) {
let mut hasher = TypeIdHasher::default();
type_id.hash(&mut hasher);
- // SAFETY: u64 is valid for all bit patterns.
- let _ = hasher.finish();
+ _ = hasher.finish();
}
- // Pick a variety of types, just to demonstrate it’s all sane. Normal, zero-sized, unsized, &c.
+ // Pick a variety of types, just to demonstrate it's all sane. Normal, zero-sized, unsized, &c.
verify_hashing_with(TypeId::of::<usize>());
verify_hashing_with(TypeId::of::<()>());
verify_hashing_with(TypeId::of::<str>());
@@ -220,34 +223,34 @@
/// Methods for downcasting from an `Any`-like trait object.
///
/// This should only be implemented on trait objects for subtraits of `Any`, though you can
-/// implement it for other types and it’ll work fine, so long as your implementation is correct.
+/// implement it for other types and it'll work fine, so long as your implementation is correct.
pub trait Downcast {
/// Gets the `TypeId` of `self`.
fn type_id(&self) -> TypeId;
// Note the bound through these downcast methods is 'static, rather than the inexpressible
// concept of Self-but-as-a-trait (where Self is `dyn Trait`). This is sufficient, exceeding
- // TypeId’s requirements. Sure, you *can* do CloneAny.downcast_unchecked::<NotClone>() and the
- // type system won’t protect you, but that doesn’t introduce any unsafety: the method is
+ // TypeId's requirements. Sure, you *can* do CloneAny.downcast_unchecked::<NotClone>() and the
+ // type system won't protect you, but that doesn't introduce any unsafety: the method is
// already unsafe because you can specify the wrong type, and if this were exposing safe
// downcasting, CloneAny.downcast::<NotClone>() would just return an error, which is just as
// correct.
//
- // Now in theory we could also add T: ?Sized, but that doesn’t play nicely with the common
- // implementation, so I’m doing without it.
+ // Now in theory we could also add T: ?Sized, but that doesn't play nicely with the common
+ // implementation, so I'm doing without it.
/// Downcast from `&Any` to `&T`, without checking the type matches.
///
/// # Safety
///
- /// The caller must ensure that `T` matches the trait object, on pain of *undefined behaviour*.
+ /// The caller must ensure that `T` matches the trait object, on pain of *undefined behavior*.
unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T;
/// Downcast from `&mut Any` to `&mut T`, without checking the type matches.
///
/// # Safety
///
- /// The caller must ensure that `T` matches the trait object, on pain of *undefined behaviour*.
+ /// The caller must ensure that `T` matches the trait object, on pain of *undefined behavior*.
unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T;
}
@@ -267,12 +270,12 @@
#[inline]
unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
- unsafe { &*(self as *const Self as *const T) }
+ unsafe { &*std::ptr::from_ref::<Self>(self).cast::<T>() }
}
#[inline]
unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
- unsafe { &mut *(self as *mut Self as *mut T) }
+ unsafe { &mut *std::ptr::from_mut::<Self>(self).cast::<T>() }
}
}
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs
index 982be40..9a292ea 100644
--- a/crates/stdx/src/lib.rs
+++ b/crates/stdx/src/lib.rs
@@ -17,7 +17,7 @@
pub use itertools;
#[inline(always)]
-pub fn is_ci() -> bool {
+pub const fn is_ci() -> bool {
option_env!("CI").is_some()
}
@@ -26,14 +26,14 @@
}
#[must_use]
-#[allow(clippy::print_stderr)]
+#[expect(clippy::print_stderr, reason = "only visible to developers")]
pub fn timeit(label: &'static str) -> impl Drop {
let start = Instant::now();
- defer(move || eprintln!("{}: {:.2?}", label, start.elapsed()))
+ defer(move || eprintln!("{}: {:.2}", label, start.elapsed().as_nanos()))
}
/// Prints backtrace to stderr, useful for debugging.
-#[allow(clippy::print_stderr)]
+#[expect(clippy::print_stderr, reason = "only visible to developers")]
pub fn print_backtrace() {
#[cfg(feature = "backtrace")]
eprintln!("{:?}", backtrace::Backtrace::new());
@@ -126,6 +126,7 @@
}
// Taken from rustc.
+#[must_use]
pub fn to_camel_case(ident: &str) -> String {
ident
.trim_matches('_')
@@ -156,7 +157,7 @@
camel_cased_component
})
- .fold((String::new(), None), |(acc, prev): (_, Option<String>), next| {
+ .fold((String::new(), None), |(mut acc, prev): (_, Option<String>), next| {
// separate two components with an underscore if their boundary cannot
// be distinguished using an uppercase/lowercase case distinction
let join = prev
@@ -166,16 +167,20 @@
Some(!char_has_case(l) && !char_has_case(f))
})
.unwrap_or(false);
- (acc + if join { "_" } else { "" } + &next, Some(next))
+ acc.push_str(if join { "_" } else { "" });
+ acc.push_str(&next);
+ (acc, Some(next))
})
.0
}
// Taken from rustc.
-pub fn char_has_case(c: char) -> bool {
+#[must_use]
+pub const fn char_has_case(c: char) -> bool {
c.is_lowercase() || c.is_uppercase()
}
+#[must_use]
pub fn is_upper_snake_case(s: &str) -> bool {
s.chars().all(|c| c.is_uppercase() || c == '_' || c.is_numeric())
}
@@ -188,6 +193,7 @@
*buf = buf.replace(from, to);
}
+#[must_use]
pub fn trim_indent(mut text: &str) -> String {
if text.starts_with('\n') {
text = &text[1..];
@@ -249,8 +255,8 @@
impl Drop for JodChild {
fn drop(&mut self) {
- let _ = self.0.kill();
- let _ = self.0.wait();
+ _ = self.0.kill();
+ _ = self.0.wait();
}
}
@@ -259,12 +265,11 @@
command.spawn().map(Self)
}
+ #[must_use]
+ #[cfg(not(target_arch = "wasm32"))]
pub fn into_inner(self) -> std::process::Child {
- if cfg!(target_arch = "wasm32") {
- panic!("no processes on wasm");
- }
// SAFETY: repr transparent, except on WASM
- unsafe { std::mem::transmute::<JodChild, std::process::Child>(self) }
+ unsafe { std::mem::transmute::<Self, std::process::Child>(self) }
}
}
diff --git a/crates/stdx/src/non_empty_vec.rs b/crates/stdx/src/non_empty_vec.rs
index 342194c..faa322d 100644
--- a/crates/stdx/src/non_empty_vec.rs
+++ b/crates/stdx/src/non_empty_vec.rs
@@ -8,8 +8,8 @@
impl<T> NonEmptyVec<T> {
#[inline]
- pub fn new(first: T) -> Self {
- NonEmptyVec { first, rest: Vec::new() }
+ pub const fn new(first: T) -> Self {
+ Self { first, rest: Vec::new() }
}
#[inline]
@@ -24,7 +24,7 @@
#[inline]
pub fn push(&mut self, value: T) {
- self.rest.push(value)
+ self.rest.push(value);
}
#[inline]
diff --git a/crates/stdx/src/panic_context.rs b/crates/stdx/src/panic_context.rs
index a35d50b..b220451 100644
--- a/crates/stdx/src/panic_context.rs
+++ b/crates/stdx/src/panic_context.rs
@@ -16,7 +16,7 @@
}
pub fn enter(frame: String) -> PanicContext {
- #[allow(clippy::print_stderr)]
+ #[expect(clippy::print_stderr, reason = "already panicking anyway")]
fn set_hook() {
let default_hook = panic::take_hook();
panic::set_hook(Box::new(move |panic_info| {
diff --git a/crates/stdx/src/process.rs b/crates/stdx/src/process.rs
index 3b3955c..2efeed4 100644
--- a/crates/stdx/src/process.rs
+++ b/crates/stdx/src/process.rs
@@ -54,6 +54,9 @@
Ok((stdout, stderr))
}
+/// # Panics
+///
+/// Panics if `cmd` is not configured to have `stdout` and `stderr` as `piped`.
pub fn spawn_with_streaming_output(
mut cmd: Command,
on_stdout_line: &mut dyn FnMut(&str),
diff --git a/crates/stdx/src/rand.rs b/crates/stdx/src/rand.rs
index 115a073..e028990 100644
--- a/crates/stdx/src/rand.rs
+++ b/crates/stdx/src/rand.rs
@@ -1,8 +1,7 @@
-//! We don't use `rand`, as that's too many things for us.
+//! We don't use `rand` because that is too many things for us.
//!
-//! We currently use oorandom instead, but it's missing these two utilities.
-//! Perhaps we should switch to `fastrand`, or our own small PRNG, it's not like
-//! we need anything more complicated than xor-shift.
+//! `oorandom` is used instead, but it's missing these two utilities.
+//! Switching to `fastrand` or our own small PRNG may be good because only xor-shift is needed.
pub fn shuffle<T>(slice: &mut [T], mut rand_index: impl FnMut(usize) -> usize) {
let mut remaining = slice.len() - 1;
diff --git a/crates/stdx/src/thread.rs b/crates/stdx/src/thread.rs
index e577eb4..6c742fe 100644
--- a/crates/stdx/src/thread.rs
+++ b/crates/stdx/src/thread.rs
@@ -1,12 +1,12 @@
//! A utility module for working with threads that automatically joins threads upon drop
-//! and abstracts over operating system quality of service (QoS) APIs
+//! and abstracts over operating system quality of service (`QoS`) APIs
//! through the concept of a “thread intent”.
//!
//! The intent of a thread is frozen at thread creation time,
//! i.e. there is no API to change the intent of a thread once it has been spawned.
//!
//! As a system, rust-analyzer should have the property that
-//! old manual scheduling APIs are replaced entirely by QoS.
+//! old manual scheduling APIs are replaced entirely by `QoS`.
//! To maintain this invariant, we panic when it is clear that
//! old scheduling APIs have been used.
//!
@@ -23,10 +23,12 @@
pub use intent::ThreadIntent;
pub use pool::Pool;
+/// # Panics
+///
+/// Panics if failed to spawn the thread.
pub fn spawn<F, T>(intent: ThreadIntent, f: F) -> JoinHandle<T>
where
- F: FnOnce() -> T,
- F: Send + 'static,
+ F: (FnOnce() -> T) + Send + 'static,
T: Send + 'static,
{
Builder::new(intent).spawn(f).expect("failed to spawn thread")
@@ -39,26 +41,29 @@
}
impl Builder {
- pub fn new(intent: ThreadIntent) -> Builder {
- Builder { intent, inner: jod_thread::Builder::new(), allow_leak: false }
+ #[must_use]
+ pub fn new(intent: ThreadIntent) -> Self {
+ Self { intent, inner: jod_thread::Builder::new(), allow_leak: false }
}
- pub fn name(self, name: String) -> Builder {
- Builder { inner: self.inner.name(name), ..self }
+ #[must_use]
+ pub fn name(self, name: String) -> Self {
+ Self { inner: self.inner.name(name), ..self }
}
- pub fn stack_size(self, size: usize) -> Builder {
- Builder { inner: self.inner.stack_size(size), ..self }
+ #[must_use]
+ pub fn stack_size(self, size: usize) -> Self {
+ Self { inner: self.inner.stack_size(size), ..self }
}
- pub fn allow_leak(self, b: bool) -> Builder {
- Builder { allow_leak: b, ..self }
+ #[must_use]
+ pub fn allow_leak(self, allow_leak: bool) -> Self {
+ Self { allow_leak, ..self }
}
pub fn spawn<F, T>(self, f: F) -> std::io::Result<JoinHandle<T>>
where
- F: FnOnce() -> T,
- F: Send + 'static,
+ F: (FnOnce() -> T) + Send + 'static,
T: Send + 'static,
{
let inner_handle = self.inner.spawn(move || {
@@ -78,6 +83,10 @@
}
impl<T> JoinHandle<T> {
+ /// # Panics
+ ///
+ /// Panics if there is no thread to join.
+ #[must_use]
pub fn join(mut self) -> T {
self.inner.take().unwrap().join()
}
@@ -95,6 +104,7 @@
}
}
+#[expect(clippy::min_ident_chars, reason = "trait impl")]
impl<T> fmt::Debug for JoinHandle<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad("JoinHandle { .. }")
diff --git a/crates/stdx/src/thread/intent.rs b/crates/stdx/src/thread/intent.rs
index 7b65db3..1203bfc 100644
--- a/crates/stdx/src/thread/intent.rs
+++ b/crates/stdx/src/thread/intent.rs
@@ -1,9 +1,9 @@
-//! An opaque façade around platform-specific QoS APIs.
+//! An opaque façade around platform-specific `QoS` APIs.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
// Please maintain order from least to most priority for the derived `Ord` impl.
pub enum ThreadIntent {
- /// Any thread which does work that isn’t in the critical path of the user typing
+ /// Any thread which does work that isn't in the critical path of the user typing
/// (e.g. processing Go To Definition).
Worker,
@@ -34,6 +34,7 @@
const IS_QOS_AVAILABLE: bool = imp::IS_QOS_AVAILABLE;
+#[expect(clippy::semicolon_if_nothing_returned, reason = "thin wrapper")]
fn set_current_thread_qos_class(class: QoSClass) {
imp::set_current_thread_qos_class(class)
}
@@ -63,7 +64,7 @@
///
/// * **You do not care about how long it takes for work to finish.**
/// * **You do not care about work being deferred temporarily.**
- /// (e.g. if the device’s battery is in a critical state)
+ /// (e.g. if the device's battery is in a critical state)
///
/// Examples:
///
@@ -84,7 +85,7 @@
/// All other work is prioritized over background tasks.
Background,
- /// TLDR: tasks that don’t block using your app
+ /// TLDR: tasks that don't block using your app
///
/// Contract:
///
@@ -110,7 +111,7 @@
/// for tasks using this class.
///
/// This QoS class provides a balance between
- /// performance, responsiveness and efficiency.
+ /// performance, responsiveness, and efficiency.
Utility,
/// TLDR: tasks that block using your app
@@ -126,10 +127,10 @@
/// * in a video editor:
/// opening a saved project
/// * in a browser:
- /// loading a list of the user’s bookmarks and top sites
+ /// loading a list of the user's bookmarks and top sites
/// when a new tab is created
/// * in a collaborative word processor:
- /// running a search on the document’s content
+ /// running a search on the document's content
///
/// Use this QoS class for tasks which were initiated by the user
/// and block the usage of your app while they are in progress.
@@ -208,7 +209,7 @@
}
_ => {
- // `pthread_set_qos_class_self_np`’s documentation
+ // `pthread_set_qos_class_self_np`'s documentation
// does not mention any other errors.
unreachable!("`pthread_set_qos_class_self_np` returned unexpected error {errno}")
}
@@ -223,7 +224,7 @@
};
if code != 0 {
- // `pthread_get_qos_class_np`’s documentation states that
+ // `pthread_get_qos_class_np`'s documentation states that
// an error value is placed into errno if the return code is not zero.
// However, it never states what errors are possible.
// Inspecting the source[0] shows that, as of this writing, it always returns zero.
diff --git a/crates/stdx/src/thread/pool.rs b/crates/stdx/src/thread/pool.rs
index 0efff38..074cd74 100644
--- a/crates/stdx/src/thread/pool.rs
+++ b/crates/stdx/src/thread/pool.rs
@@ -38,7 +38,11 @@
}
impl Pool {
- pub fn new(threads: usize) -> Pool {
+ /// # Panics
+ ///
+ /// Panics if job panics
+ #[must_use]
+ pub fn new(threads: usize) -> Self {
const STACK_SIZE: usize = 8 * 1024 * 1024;
const INITIAL_INTENT: ThreadIntent = ThreadIntent::Worker;
@@ -63,7 +67,7 @@
}
extant_tasks.fetch_add(1, Ordering::SeqCst);
// discard the panic, we should've logged the backtrace already
- _ = panic::catch_unwind(job.f);
+ drop(panic::catch_unwind(job.f));
extant_tasks.fetch_sub(1, Ordering::SeqCst);
}
}
@@ -73,9 +77,12 @@
handles.push(handle);
}
- Pool { _handles: handles.into_boxed_slice(), extant_tasks, job_sender }
+ Self { _handles: handles.into_boxed_slice(), extant_tasks, job_sender }
}
+ /// # Panics
+ ///
+ /// Panics if job panics
pub fn spawn<F>(&self, intent: ThreadIntent, f: F)
where
F: FnOnce() + Send + UnwindSafe + 'static,
@@ -84,14 +91,20 @@
if cfg!(debug_assertions) {
intent.assert_is_used_on_current_thread();
}
- f()
+ f();
});
let job = Job { requested_intent: intent, f };
self.job_sender.send(job).unwrap();
}
+ #[must_use]
pub fn len(&self) -> usize {
self.extant_tasks.load(Ordering::SeqCst)
}
+
+ #[must_use]
+ pub fn is_empty(&self) -> bool {
+ self.len() == 0
+ }
}