diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index b6a32d5b6421..0d509f55ce2e 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1083,9 +1083,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[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/src/tools/rust-analyzer/crates/stdx/Cargo.toml b/src/tools/rust-analyzer/crates/stdx/Cargo.toml index 76033308fe58..7bda106764b9 100644 --- a/src/tools/rust-analyzer/crates/stdx/Cargo.toml +++ b/src/tools/rust-analyzer/crates/stdx/Cargo.toml @@ -13,7 +13,7 @@ rust-version.workspace = true [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/src/tools/rust-analyzer/crates/stdx/src/anymap.rs b/src/tools/rust-analyzer/crates/stdx/src/anymap.rs index 0c39419133f1..f55698ecb051 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/anymap.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/anymap.rs @@ -1,4 +1,5 @@ //! This file is a port of only the necessary features from version 1.0.0-beta.2 for use within rust-analyzer. +//! //! Copyright © 2014–2022 Chris Morgan. //! 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 @@ pub struct TypeIdHasher { 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 @@ use ::std::collections::hash_map; /// 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 = hash_map::HashMap, BuildHasherDefault>; /// A collection containing zero or one values for any given type and allowing convenient, @@ -73,19 +74,20 @@ pub type RawMap = hash_map::HashMap, BuildHasherDefault[Map]<dyn [core::any::Any]>, +/// - `[Map]`, /// also spelled [`AnyMap`] for convenience. -/// - [Map]<dyn [core::any::Any] + Send> -/// - [Map]<dyn [core::any::Any] + Send + Sync> +/// - `[Map]` +/// - `[Map]` /// /// ## Example /// -/// (Here using the [`AnyMap`] convenience alias; the first line could use -/// [anymap::Map][Map]::<[core::any::Any]>::new() 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 @@ pub struct Map { raw: RawMap, } -/// The most common type of `Map`: just using `Any`; [Map]<dyn [Any]>. +/// The most common type of `Map`: just using `Any`; `[Map]`. /// /// Why is this a separate type alias rather than a default value for `Map`? -/// `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; impl Default for Map { @@ -113,6 +115,7 @@ impl Map { /// Returns a reference to the value stored in the collection for the type `T`, /// if it exists. #[inline] + #[must_use] pub fn get>(&self) -> Option<&T> { self.raw.get(&TypeId::of::()).map(|any| unsafe { any.downcast_ref_unchecked::() }) } @@ -132,30 +135,30 @@ impl Map { } /// 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>, +pub struct OccupiedEntry<'map, A: ?Sized + Downcast, V: 'map> { + inner: hash_map::OccupiedEntry<'map, TypeId, Box>, type_: PhantomData, } /// 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>, +pub struct VacantEntry<'map, A: ?Sized + Downcast, V: 'map> { + inner: hash_map::VacantEntry<'map, TypeId, Box>, type_: PhantomData, } /// 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> Entry<'a, A, V> { +impl<'map, A: ?Sized + Downcast, V: IntoBox> 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 V>(self, default: F) -> &'a mut V { + pub fn or_insert_with 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> Entry<'a, A, V> { } } -impl<'a, A: ?Sized + Downcast, V: IntoBox> OccupiedEntry<'a, A, V> { - /// Converts the OccupiedEntry into a mutable reference to the value in the entry +impl<'map, A: ?Sized + Downcast, V: IntoBox> 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> VacantEntry<'a, A, V> { - /// Sets the value of the entry with the VacantEntry's key, +impl<'map, A: ?Sized + Downcast, V: IntoBox> 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 @@ mod tests { #[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::()); verify_hashing_with(TypeId::of::<()>()); verify_hashing_with(TypeId::of::()); @@ -220,34 +223,34 @@ mod tests { /// 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::() 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::() 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::() 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(&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(&mut self) -> &mut T; } @@ -267,12 +270,12 @@ macro_rules! implement { #[inline] unsafe fn downcast_ref_unchecked(&self) -> &T { - unsafe { &*(self as *const Self as *const T) } + unsafe { &*std::ptr::from_ref::(self).cast::() } } #[inline] unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { - unsafe { &mut *(self as *mut Self as *mut T) } + unsafe { &mut *std::ptr::from_mut::(self).cast::() } } } diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs index 982be40dd425..9a292eacd7f7 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/lib.rs @@ -17,7 +17,7 @@ pub mod thread; 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 @@ pub fn hash_once(thing: impl std::hash::Has } #[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 @@ where } // Taken from rustc. +#[must_use] pub fn to_camel_case(ident: &str) -> String { ident .trim_matches('_') @@ -156,7 +157,7 @@ pub fn to_camel_case(ident: &str) -> String { camel_cased_component }) - .fold((String::new(), None), |(acc, prev): (_, Option), next| { + .fold((String::new(), None), |(mut acc, prev): (_, Option), 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 @@ pub fn to_camel_case(ident: &str) -> String { 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 @@ pub fn replace(buf: &mut String, from: char, to: &str) { *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 ops::DerefMut for JodChild { 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 @@ impl JodChild { 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::(self) } + unsafe { std::mem::transmute::(self) } } } diff --git a/src/tools/rust-analyzer/crates/stdx/src/non_empty_vec.rs b/src/tools/rust-analyzer/crates/stdx/src/non_empty_vec.rs index 342194c7838c..faa322d9e746 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/non_empty_vec.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/non_empty_vec.rs @@ -8,8 +8,8 @@ pub struct NonEmptyVec { impl NonEmptyVec { #[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 @@ impl NonEmptyVec { #[inline] pub fn push(&mut self, value: T) { - self.rest.push(value) + self.rest.push(value); } #[inline] diff --git a/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs b/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs index a35d50b78dfb..b220451c45a0 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs @@ -16,7 +16,7 @@ impl Drop for PanicContext { } 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/src/tools/rust-analyzer/crates/stdx/src/process.rs b/src/tools/rust-analyzer/crates/stdx/src/process.rs index 3b3955c72ca4..2efeed45e44e 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/process.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/process.rs @@ -54,6 +54,9 @@ pub fn streaming_output( 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/src/tools/rust-analyzer/crates/stdx/src/rand.rs b/src/tools/rust-analyzer/crates/stdx/src/rand.rs index 115a073dab33..e028990900af 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/rand.rs +++ b/src/tools/rust-analyzer/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(slice: &mut [T], mut rand_index: impl FnMut(usize) -> usize) { let mut remaining = slice.len() - 1; diff --git a/src/tools/rust-analyzer/crates/stdx/src/thread.rs b/src/tools/rust-analyzer/crates/stdx/src/thread.rs index e577eb431371..6c742fecf1b6 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/thread.rs +++ b/src/tools/rust-analyzer/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 @@ mod pool; pub use intent::ThreadIntent; pub use pool::Pool; +/// # Panics +/// +/// Panics if failed to spawn the thread. pub fn spawn(intent: ThreadIntent, f: F) -> JoinHandle 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 @@ pub struct Builder { } 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(self, f: F) -> std::io::Result> 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 @@ pub struct JoinHandle { } impl JoinHandle { + /// # 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 @@ impl Drop for JoinHandle { } } +#[expect(clippy::min_ident_chars, reason = "trait impl")] impl fmt::Debug for JoinHandle { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("JoinHandle { .. }") diff --git a/src/tools/rust-analyzer/crates/stdx/src/thread/intent.rs b/src/tools/rust-analyzer/crates/stdx/src/thread/intent.rs index 7b65db30cc5b..1203bfc38541 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/thread/intent.rs +++ b/src/tools/rust-analyzer/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 @@ use imp::QoSClass; 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 @@ mod imp { /// /// * **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 @@ mod imp { /// 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 @@ mod imp { /// 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 @@ mod imp { /// * 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 @@ mod imp { } _ => { - // `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 @@ mod imp { }; 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/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs b/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs index 0efff381c680..074cd747dacc 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs @@ -38,7 +38,11 @@ struct Job { } 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 @@ impl Pool { } 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 @@ impl Pool { 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(&self, intent: ThreadIntent, f: F) where F: FnOnce() + Send + UnwindSafe + 'static, @@ -84,14 +91,20 @@ impl Pool { 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 + } }