From 100dda63323d95289ba727e8dde34157e80db23a Mon Sep 17 00:00:00 2001 From: Techcable Date: Thu, 28 Aug 2025 14:09:42 -0700 Subject: [PATCH 01/13] Improve error messages for bad feature combos The crate cannot function without at least one of the 'nightly' or 'std' features. The 'unique-wrap-std' implicitly enables the 'std' feature, but raises an error if the 'nightly' feature is not explicitly be enabled. The 'nightly' requirement will be dropped if `#[feature(thread_id_value)]` is ever enabled. Before this change, encountering this issue would trigger a nice `compile_error!` with a descriptive error message, along with a bunch of other confusing looking errors. After this change, only the single `compile_error!` is displayed. This is implemented by adding stub implementations which call `unreachable!()` --- src/lib.rs | 6 ++---- src/locals.rs | 36 +++++++++++++++++++++++++++++++++++- src/unique.rs | 13 ++++++++++--- 3 files changed, 47 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 911f3e8..f45cdc3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,10 +50,7 @@ )] #[cfg(not(any(feature = "nightly", feature = "std")))] -compile_error!("Either the `nightly` or `std` feature must be enabled for this crate to work"); - -#[cfg(all(feature = "unique-wrap-std", not(feature = "nightly")))] -compile_error!("The `unique-wrap-std` feature currently requires the `nightly` feature to be enabled"); +compile_error!("The `threadid` crate requires at least one of the `nightly` or `std` features"); #[cfg(feature = "alloc")] extern crate alloc; @@ -73,6 +70,7 @@ pub use self::std::StdThreadId; #[macro_use] mod locals; #[cfg(feature = "std")] +#[cfg_attr(feature = "nightly-docs", doc(cfg(feature = "std")))] pub mod debug; #[cfg(feature = "std")] #[cfg_attr(feature = "nightly-docs", doc(cfg(feature = "std")))] diff --git a/src/locals.rs b/src/locals.rs index 978e77b..f6693ec 100644 --- a/src/locals.rs +++ b/src/locals.rs @@ -13,12 +13,15 @@ macro_rules! fast_thread_local { static $var: $tp = const { $init };)* } } else { - compile_error!("Either the `std` or `nightly` feature must be enabled"); + $( + static $var: $crate::locals::dummy::DummyLocalKey<$tp> = $crate::locals::dummy::DummyLocalKey::new($init); + )* } } }; } +/// Version of [`std::thread::LocalKey`] using the nightly `#[thread_local]` attribute. #[cfg(feature = "nightly")] #[cfg_attr(not(feature = "std"), allow(dead_code))] pub mod nightly { @@ -41,3 +44,34 @@ pub mod nightly { } type AccessError = core::convert::Infallible; } + +/// Dummy version of [`std::thread::LocalKey`] to avoid duplicate compilation errors. +#[cfg(not(any(feature = "nightly", feature = "std")))] +pub mod dummy { + use core::mem::ManuallyDrop; + + pub struct DummyLocalKey { + _value: ManuallyDrop, + } + // always Sync because we don't give any access + unsafe impl Sync for DummyLocalKey {} + impl DummyLocalKey { + pub const fn new(value: T) -> Self { + DummyLocalKey { + _value: ManuallyDrop::new(value), + } + } + #[inline] + pub fn with R, R>(&self, func: F) -> R { + let _ = func; + unimplemented!("thread local unsupported") + } + #[inline] + #[allow(clippy::unnecessary_wraps)] + pub fn try_with R, R>(&self, func: F) -> Result { + let _ = func; + Err("thread local unsupported") + } + } + type AccessError = &'static str; +} diff --git a/src/unique.rs b/src/unique.rs index 94155d9..65a3b76 100644 --- a/src/unique.rs +++ b/src/unique.rs @@ -43,8 +43,15 @@ impl UniqueThreadId { #[cfg_attr(feature = "nightly-docs", doc(cfg(feature = "unique-wrap-std")))] #[inline] pub fn from_std(id: impl Into) -> Self { - // SAFETY: Enabling the feature guarantees ids are equivalent - unsafe { Self::from_int(id.into().as_u64().get()) } + cfg_if::cfg_if! { + if #[cfg(feature="nightly")] { + // SAFETY: Enabling the feature guarantees ids are equivalent + unsafe { Self::from_int(id.into().as_u64().get()) } + } else { + let _ = id; + unreachable!("unique-wrap-std not possible without nightly features") + } + } } /// Convert a [`UniqueThreadId`] into an integer value. @@ -82,7 +89,7 @@ impl UniqueThreadId { if #[cfg(all(feature = "std", feature = "nightly"))] { UniqueThreadId(crate::StdThreadId::current().0.as_u64()) } else if #[cfg(feature = "unique-wrap-std")] { - compile_error!("requires nightly + std") + compile_error!("The `unique-wrap-std` feature requires the `nightly` feature to be enabled") } else { THREAD_ID.with(|cell| { match cell.get() { From b011e1bf8d65dd9dd0b255929b445a82f447944c Mon Sep 17 00:00:00 2001 From: Techcable Date: Thu, 28 Aug 2025 14:44:35 -0700 Subject: [PATCH 02/13] Enable all-features for docs.rs Includes the nightly-doc feature, which will show #[doc(cfg(...)] attributes. --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 58f13ff..39dee17 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,3 +64,6 @@ parking_lot = ["dep:parking_lot"] # By default, this is implicitly enabled on nightly + std, # this feature only makes the requirement explicit. unique-wrap-std = ["std"] + +[package.metadata.docs.rs] +all-features = true From 08ca7883c7eae0587aec631144908987ec59dae2 Mon Sep 17 00:00:00 2001 From: Techcable Date: Thu, 28 Aug 2025 14:24:49 -0700 Subject: [PATCH 03/13] Make basic test work without std feature --- tests/basic.rs | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/tests/basic.rs b/tests/basic.rs index 91bbfa6..cec5537 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -5,12 +5,16 @@ use std::collections::HashSet; use std::sync::{Barrier, Mutex}; use crossbeam_utils::thread; -use threadid::{IThreadId, LiveThreadId, StdThreadId, UniqueThreadId}; +use threadid::{IThreadId, UniqueThreadId}; +#[cfg(feature = "std")] +use threadid::{LiveThreadId, StdThreadId}; #[test] fn death_reuse() { let seen_unique_ids = Mutex::new(HashSet::::new()); + #[cfg(feature = "std")] let seen_std_ids = Mutex::new(HashSet::::new()); + #[cfg(feature = "std")] let seen_live_ids = Mutex::new(HashSet::::new()); fn add_new(lock: &Mutex>) { let id = threadid::current(); @@ -26,8 +30,11 @@ fn death_reuse() { } } add_new(&seen_unique_ids); - add_new(&seen_std_ids); - add_new(&seen_live_ids); + #[cfg(feature = "std")] + { + add_new(&seen_std_ids); + add_new(&seen_live_ids); + } { let start = Barrier::new(2); let end = Barrier::new(2); @@ -35,15 +42,21 @@ fn death_reuse() { let t1 = scope.spawn(|_scope| { start.wait(); add_new(&seen_unique_ids); - add_new(&seen_std_ids); - add_new(&seen_live_ids); + #[cfg(feature = "std")] + { + add_new(&seen_std_ids); + add_new(&seen_live_ids); + } end.wait(); }); let t2 = scope.spawn(|_scope| { start.wait(); add_new(&seen_unique_ids); - add_new(&seen_std_ids); - add_new(&seen_live_ids); + #[cfg(feature = "std")] + { + add_new(&seen_std_ids); + add_new(&seen_live_ids); + } end.wait(); }); t1.join().unwrap_or_else(|payload| propagate_panic(payload)); @@ -56,9 +69,12 @@ fn death_reuse() { scope .spawn(|_scope| { add_new(&seen_unique_ids); - add_new(&seen_std_ids); - let live_id: LiveThreadId = threadid::current(); - assert!(seen_live_ids.lock().unwrap().contains(&live_id)); + #[cfg(feature = "std")] + { + add_new(&seen_std_ids); + let live_id: LiveThreadId = threadid::current(); + assert!(seen_live_ids.lock().unwrap().contains(&live_id)); + } }) .join() .unwrap_or_else(|payload| propagate_panic(payload)); From 043d809871133283295e892ffb483173f966733a Mon Sep 17 00:00:00 2001 From: Techcable Date: Thu, 28 Aug 2025 14:25:23 -0700 Subject: [PATCH 04/13] Indicate thread_name example requires std --- Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 39dee17..7cb7b0b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,10 @@ bytemuck = { version = "1.23", optional = true, features = ["derive"] } # criterion = "0.7" crossbeam-utils = "0.8" +[[example]] +name = "thread_name" +required-features = ["std"] + [[bench]] name = "access" required-features = [] From 52c14c00d6eb27df120401857d7cc7a95013489f Mon Sep 17 00:00:00 2001 From: Techcable Date: Thu, 28 Aug 2025 14:27:34 -0700 Subject: [PATCH 05/13] Drop unused bytemuck/derive feature All trait implementations are currently manual. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7cb7b0b..eb5e4a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ nonmax = { version = "0.5", default-features = false } parking_lot = { version = "0.12", optional = true } serde = { version = "1", optional = true, features = ["derive"] } slog = { version = "2.6", optional = true, default-features = false } -bytemuck = { version = "1.23", optional = true, features = ["derive"] } +bytemuck = { version = "1.23", optional = true } [dev-dependencies] # criterion = "0.7" From 2ff9fe06c06b13d49b53d2383bf68149ca78081c Mon Sep 17 00:00:00 2001 From: Techcable Date: Thu, 28 Aug 2025 14:40:13 -0700 Subject: [PATCH 06/13] Eliminate use of serde_derive Not needed for something as simple as a newtype. --- Cargo.toml | 4 ++-- src/lib.rs | 3 ++- src/live.rs | 2 +- src/unique.rs | 2 +- src/utils.rs | 12 ++++++++++++ 5 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index eb5e4a7..f662cdc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ portable-atomic = { version = "1", features = ["require-cas"] } nonmax = { version = "0.5", default-features = false } # optional parking_lot = { version = "0.12", optional = true } -serde = { version = "1", optional = true, features = ["derive"] } +serde = { version = "1", optional = true } slog = { version = "2.6", optional = true, default-features = false } bytemuck = { version = "1.23", optional = true } @@ -46,7 +46,7 @@ alloc = [] nightly = ["parking_lot?/nightly"] # Enables serde serialization for most types # -# Deserialization can not be reasonbly implemented +# Deserialization can not be reasonably implemented serde = ["dep:serde", "nonmax/serde"] # Implements slog::Value for most types slog = ["dep:slog"] diff --git a/src/lib.rs b/src/lib.rs index f45cdc3..d725cc9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,6 +67,8 @@ pub use unique::UniqueThreadId; #[cfg_attr(feature = "nightly-docs", doc(cfg(feature = "std")))] pub use self::std::StdThreadId; +#[macro_use] +mod utils; #[macro_use] mod locals; #[cfg(feature = "std")] @@ -79,7 +81,6 @@ pub mod live; #[cfg_attr(feature = "nightly-docs", doc(cfg(feature = "std")))] pub mod std; pub mod unique; -mod utils; /// Defines methods common to all thread ids. /// diff --git a/src/live.rs b/src/live.rs index bc7eb30..45e46e9 100644 --- a/src/live.rs +++ b/src/live.rs @@ -24,7 +24,6 @@ use crate::utils::sync::{Mutex, MutexGuard}; /// It is guaranteed that `Option` has the same representation as `LiveThreadId`. /// Currently [`LiveThreadId::to_int`] can be zero, reducing wasted indexes. #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize))] #[must_use] #[repr(transparent)] pub struct LiveThreadId { @@ -112,6 +111,7 @@ impl LiveThreadId { self.index.get() } } +simple_serde_serialize!(LiveThreadId, |this| this.to_int()); #[cfg(feature = "bytemuck")] // SAFETY: We wrap a NonMax, which has the same niche as NonZero unsafe impl bytemuck::ZeroableInOption for LiveThreadId {} diff --git a/src/unique.rs b/src/unique.rs index 65a3b76..fd553c1 100644 --- a/src/unique.rs +++ b/src/unique.rs @@ -18,7 +18,6 @@ fast_thread_local! { /// While the current value is a [`core::num::NonZero`], /// this may change in the future if other niche types like `NonMax` become stabilized. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Serialize))] #[must_use] #[repr(transparent)] pub struct UniqueThreadId(NonZeroU64); @@ -105,6 +104,7 @@ impl UniqueThreadId { } } } +simple_serde_serialize!(UniqueThreadId, |this| this.to_int()); // SAFETY: Unique across all threads that have ever existed unsafe impl crate::IThreadId for UniqueThreadId { #[inline] diff --git a/src/utils.rs b/src/utils.rs index 4b9e3fa..77dd739 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -72,3 +72,15 @@ mod cell { // SAFETY: Fine to send because old thread loses access unsafe impl Send for OnceCell {} } +macro_rules! simple_serde_serialize { + ($target:ident, |$this:ident| $to_inner:expr) => { + #[cfg(feature = "serde")] + impl serde::Serialize for $target { + fn serialize(&self, serializer: S) -> Result { + let $this = self; + let value = $to_inner; + serde::Serialize::serialize(&value, serializer) + } + } + }; +} From 6c5fabfd129528e1cab247824d30cc8ddaccdeac Mon Sep 17 00:00:00 2001 From: Techcable Date: Thu, 28 Aug 2025 14:30:16 -0700 Subject: [PATCH 07/13] Annotate impls with #[doc(feature = "...")] where appropriate --- src/live.rs | 3 +++ src/std.rs | 1 + src/unique.rs | 2 ++ src/utils.rs | 1 + 4 files changed, 7 insertions(+) diff --git a/src/live.rs b/src/live.rs index 45e46e9..073623b 100644 --- a/src/live.rs +++ b/src/live.rs @@ -113,12 +113,15 @@ impl LiveThreadId { } simple_serde_serialize!(LiveThreadId, |this| this.to_int()); #[cfg(feature = "bytemuck")] +#[cfg_attr(feature = "nightly-docs", doc(cfg(feature = "bytemuck")))] // SAFETY: We wrap a NonMax, which has the same niche as NonZero unsafe impl bytemuck::ZeroableInOption for LiveThreadId {} #[cfg(feature = "bytemuck")] +#[cfg_attr(feature = "nightly-docs", doc(cfg(feature = "bytemuck")))] // SAFETY: A NonMax is equivalent to a NonZero unsafe impl bytemuck::NoUninit for LiveThreadId {} #[cfg(feature = "slog")] +#[cfg_attr(feature = "nightly-docs", doc(cfg(feature = "slog")))] impl slog::Value for LiveThreadId { fn serialize(&self, _record: &slog::Record, key: slog::Key, serializer: &mut dyn slog::Serializer) -> slog::Result { serializer.emit_arguments(key, &format_args!("{self:?}")) diff --git a/src/std.rs b/src/std.rs index f898a58..fd0726a 100644 --- a/src/std.rs +++ b/src/std.rs @@ -43,6 +43,7 @@ unsafe impl crate::IThreadId for StdThreadId { } } #[cfg(feature = "bytemuck")] +#[cfg_attr(feature = "nightly-docs", doc(cfg(feature = "bytemuck")))] // SAFETY: We are #[repr(transparent)] unsafe impl bytemuck::TransparentWrapper for StdThreadId {} // SAFETY: stdlib guarantees that threadid is unique diff --git a/src/unique.rs b/src/unique.rs index fd553c1..8b073ff 100644 --- a/src/unique.rs +++ b/src/unique.rs @@ -113,9 +113,11 @@ unsafe impl crate::IThreadId for UniqueThreadId { } } #[cfg(feature = "bytemuck")] +#[cfg_attr(feature = "nightly-docs", doc(cfg(feature = "bytemuck")))] // SAFETY: Wraps a NonZero unsafe impl bytemuck::ZeroableInOption for UniqueThreadId {} #[cfg(feature = "bytemuck")] +#[cfg_attr(feature = "nightly-docs", doc(cfg(feature = "bytemuck")))] // SAFETY: Wraps a NonZero unsafe impl bytemuck::NoUninit for UniqueThreadId {} impl From for u64 { diff --git a/src/utils.rs b/src/utils.rs index 77dd739..ef16383 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -75,6 +75,7 @@ mod cell { macro_rules! simple_serde_serialize { ($target:ident, |$this:ident| $to_inner:expr) => { #[cfg(feature = "serde")] + #[cfg_attr(feature = "nightly-docs", doc(cfg(feature = "serde")))] impl serde::Serialize for $target { fn serialize(&self, serializer: S) -> Result { let $this = self; From 12d97ba5814b6e8934c2ec3ddb42b3123fb2f380 Mon Sep 17 00:00:00 2001 From: Techcable Date: Fri, 29 Aug 2025 19:44:35 -0700 Subject: [PATCH 08/13] Re-add criterion as dev-dependency Benchmarks won't compile without it. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f662cdc..1b22942 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ slog = { version = "2.6", optional = true, default-features = false } bytemuck = { version = "1.23", optional = true } [dev-dependencies] -# criterion = "0.7" +criterion = "0.7" crossbeam-utils = "0.8" [[example]] From f268f05e24a6d78b06e6b8fbc5b9cf044f4d8fbd Mon Sep 17 00:00:00 2001 From: Techcable Date: Fri, 29 Aug 2025 19:50:09 -0700 Subject: [PATCH 09/13] bench: Suppress clippy::redundant_closure lint In this case it makes things clearer. --- benches/access.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/benches/access.rs b/benches/access.rs index 1d91f06..7a919a7 100644 --- a/benches/access.rs +++ b/benches/access.rs @@ -1,3 +1,5 @@ +#![allow(clippy::redundant_closure)] // slightly cleaner + use criterion::{Criterion, criterion_group, criterion_main}; use threadid::{LiveThreadId, StdThreadId, UniqueThreadId}; From 97f5de817b0a6748b3fa51d711a56b75eef55128 Mon Sep 17 00:00:00 2001 From: Techcable Date: Fri, 29 Aug 2025 20:01:49 -0700 Subject: [PATCH 10/13] Move benchmarks to a separate crate Avoids compiling criterion unless necessary, and avoids breaking the MSRV. --- Cargo.toml | 11 ++++------- benchmarks/Cargo.toml | 19 +++++++++++++++++++ benchmarks/README.md | 2 ++ {benches => benchmarks/benches}/access.rs | 0 4 files changed, 25 insertions(+), 7 deletions(-) create mode 100644 benchmarks/Cargo.toml create mode 100644 benchmarks/README.md rename {benches => benchmarks/benches}/access.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 1b22942..1292668 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,19 +23,12 @@ slog = { version = "2.6", optional = true, default-features = false } bytemuck = { version = "1.23", optional = true } [dev-dependencies] -criterion = "0.7" crossbeam-utils = "0.8" [[example]] name = "thread_name" required-features = ["std"] -[[bench]] -name = "access" -required-features = [] -harness = false -test = false - [features] default = ["std"] # Enables features which require the standard library @@ -71,3 +64,7 @@ unique-wrap-std = ["std"] [package.metadata.docs.rs] all-features = true + +[workspace] +members = [".", "benchmarks"] +resolver = "2" diff --git a/benchmarks/Cargo.toml b/benchmarks/Cargo.toml new file mode 100644 index 0000000..fd3b918 --- /dev/null +++ b/benchmarks/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "threadid-benchmarks" +description = "Benchmarks for the threadid crate" +version = "0.0.0" +license = "Apache-2.0 OR MIT" +repository = "https://github.com/Techcable/threadid.rs" +publish = false # internal use only +edition = "2021" + +[dev-dependencies] +threadid.path = ".." +criterion = "0.7" +crossbeam-utils = "0.8" + +[[bench]] +name = "access" +required-features = [] +harness = false +test = false diff --git a/benchmarks/README.md b/benchmarks/README.md new file mode 100644 index 0000000..dda445f --- /dev/null +++ b/benchmarks/README.md @@ -0,0 +1,2 @@ +# Benchmarks for thraedid.rs +Separate from the main crate to avoid compiling criterion and because the MSRV is different. diff --git a/benches/access.rs b/benchmarks/benches/access.rs similarity index 100% rename from benches/access.rs rename to benchmarks/benches/access.rs From cdba47366a92e45f006ffb02bade804ccad60258 Mon Sep 17 00:00:00 2001 From: Techcable Date: Fri, 29 Aug 2025 19:23:59 -0700 Subject: [PATCH 11/13] Setup Github Actions --- .github/workflows/rustfmt.yml | 24 +++++ .github/workflows/spellcheck.yml | 23 +++++ .github/workflows/test.yml | 171 +++++++++++++++++++++++++++++++ 3 files changed, 218 insertions(+) create mode 100644 .github/workflows/rustfmt.yml create mode 100644 .github/workflows/spellcheck.yml create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/rustfmt.yml b/.github/workflows/rustfmt.yml new file mode 100644 index 0000000..5491638 --- /dev/null +++ b/.github/workflows/rustfmt.yml @@ -0,0 +1,24 @@ +# The file is the workflow for rustfmt +# +# It runs `cargo fmt --check` +# +# It will fail if there are formatting problems. +on: [push, pull_request] +name: rustfmt + +env: + CARGO_TERM_COLOR: always + +jobs: + rustfmt: + # Only run on PRs if the source branch is on someone else's repo + if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt + - shell: bash + run: | + cargo fmt --all -- --check diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spellcheck.yml new file mode 100644 index 0000000..d76b0f6 --- /dev/null +++ b/.github/workflows/spellcheck.yml @@ -0,0 +1,23 @@ +# Checks spelling with typos +# This has very few false positives, only checking for known misspellings (similar to codespell). +# This action is based on https://github.com/crate-ci/typos/blob/master/docs/github-action.md +name: Check Spelling +on: [push, pull_request] + +env: + CLICOLOR: 1 + +permissions: + contents: read + +jobs: + typos: + # Only run on PRs if the source branch is on someone else's repo + if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }} + + name: Check spelling with typos + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - name: Run typos (pinned version) + uses: crate-ci/typos@v1.35.6 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..8f07632 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,171 @@ +# We use `actions-rs` for most of our actions +# +# This file is for the main tests. clippy & rustfmt are separate workflows +on: [push, pull_request] +name: Cargo Test + +env: + CARGO_TERM_COLOR: always + # has a history of occasional bugs (especially on old versions) + # + # the ci is free so we might as well use it ;) + CARGO_INCREMENTAL: 0 + + + +jobs: + test: + # Only run on PRs if the source branch is on someone else's repo + if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }} + + runs-on: ubuntu-latest + strategy: + fail-fast: false # Even if one job fails we still want to see the other ones + matrix: + rust: + # Minimum Supported Rust Version + # + # This is hardcoded and needs to be in sync with Cargo.toml and the README + # + # If one of the features does not support this MSRV, + # you need to remove this from the main list and manually add the desired + # feature/version combinations to 'include' + # This hack is not currently needed because serde-erased v0.3 supports our MSRV. + - 1.63 + + # Intermediate Releases (between MSRV and latest stable) + # Be careful not to add these needlessly; they hold up CI + + # The most recent version of stable rust (automatically updated) + - stable + - nightly + # NOTE: Features to test must be specified manually. They are applied to all versions separately. + features: + - "std" + - "std bytemuck slog serde" + include: + - rust: stable + features: "std parking_lot" + - rust: nightly + features: "nightly" # no features except nightly + - rust: nightly + features: "nightly alloc" # no features except nightly + alloc + - rust: nightly + features: "std nightly" + - rust: nightly + features: "std unique-wrap-std nightly" + - rust: nightly + features: "std nightly parking_lot" + - rust: nightly + features: "std nightly parking_lot bytemuck slog serde" + steps: + - uses: actions/checkout@v5 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} + - name: Cache Cargo Registry + id: cache-index + uses: actions/cache@v4 + with: + path: + # Before the sparse index, updating the registry took forever + ~/.cargo/registry/index/ + key: ${{ runner.os }}-cargo-${{ matrix.rust }} + restore-keys: | + ${{ runner.os }}-cargo- + continue-on-error: false + - name: Test + # NOTE: Running --all-targets does not include doc tests + # Does not compile benchmarks because they break on MSRV. Still checked by clippy + run: | + cargo test --all --verbose --no-default-features --features "${{ matrix.features }}" --exclude "benchmarks" + + clippy: + # Only run on PRs if the source branch is on someone else's repo + if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }} + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + rust: + # in hardcoded versions, warnings will fail the build + - 1.89 + # in auto-updated versions, warnings will not fail the build + - stable + - nightly + features: + # NOTE: Unfortunately, the benchmarks crate implicitly requires 'std' + - "std parking_lot bytemuck slog serde" + include: + - rust: nightly + features: "std slog bytemuck parking_lot serde nightly" + - rust: nightly + features: "std nightly unique-wrap-std" + + steps: + - uses: actions/checkout@v5 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} + components: clippy + - name: Clippy + run: | + cargo clippy --all --all-targets --verbose --no-default-features --features "${{ matrix.features }}" -- -D warnings + # When using hardcoded/pinned versions, warnings are forbidden. + # + # On automatically updated versions of rust (both stable & nightly) we allow clippy to fail. + # This is because automatic updates can introduce new lints or change existing lints. + continue-on-error: ${{ !contains(matrix.rust, '1.') }} + + docs: + # Only run on PRs if the source branch is on someone else's repo + if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }} + + runs-on: ubuntu-latest + env: + RUSTDOCFLAGS: "-D warnings" + strategy: + fail-fast: false + matrix: + rust: + - nightly + - stable + features: + - "std parking_lot bytemuck slog serde" + include: + - rust: nightly + features: "std parking_lot bytemuck slog serde nightly nightly-docs" + steps: + - uses: actions/checkout@v5 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} + - name: Docs + run: | + cargo doc --verbose --no-default-features --features "${{ matrix.features }}" + cargo-rdme: + # Only run on PRs if the source branch is on someone else's repo + if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }} + + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - uses: dtolnay/rust-toolchain@stable + with: + components: rust-src + # need to cache cargo-rdme to avoid redundant install + - name: Cache Binaries + id: cache-binaries + uses: actions/cache@v4 + with: + path: + ~/.cargo/bin/cargo-rdme + key: ${{ runner.os }}-binary-cargo-rdme + - name: Install cargo-rdme + run: | + cargo install cargo-rdme + - name: Run cargo-rdme + run: | + cargo install cargo-rdme + cargo rdme --check From f03a3201814118257d2dacfd810883bef45f54d3 Mon Sep 17 00:00:00 2001 From: Techcable Date: Fri, 29 Aug 2025 20:19:18 -0700 Subject: [PATCH 12/13] Bump version v0.1.0 First official release. --- Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1292668..98afe0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "threadid" description = "Fast and flexible thread identifiers" -version = "0.1.0-alpha.1" +version = "0.1.0" license = "Apache-2.0 OR MIT" repository = "https://github.com/Techcable/threadid.rs" edition = "2021" @@ -10,6 +10,8 @@ edition = "2021" # 1.61 - dep:foo and foo?/std syntax # 1.63 - const Mutex::new rust-version = "1.63" +categories = ["concurrency", "development-tools::debugging", "no-std", "no-std::no-alloc"] +keywords = ["threadid", "tid", "name"] [dependencies] cfg-if = "1" From 949ff7e79fa428d08819494594c746b6fa409c6e Mon Sep 17 00:00:00 2001 From: Techcable Date: Fri, 29 Aug 2025 20:22:35 -0700 Subject: [PATCH 13/13] ci: Don't rebuild cargo-rdme if present Avoids an error by cargo-install leading to failed builds --- .github/workflows/test.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8f07632..a84ef57 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -163,9 +163,12 @@ jobs: ~/.cargo/bin/cargo-rdme key: ${{ runner.os }}-binary-cargo-rdme - name: Install cargo-rdme + shell: bash + # NOTE: This doesn't worry about installing updates run: | - cargo install cargo-rdme + if not test -f "~/.cargo/bin/cargo-rdme"; then + cargo install cargo-rdme + fi - name: Run cargo-rdme run: | - cargo install cargo-rdme cargo rdme --check