Skip to main content

rust-modern-apis

Reference for stable Rust APIs added in versions 1.89 through 1.99 (August 2025 - October 2026). Use whenever writing, reviewing, or refactoring Rust code when MSRV allows, to replace patterns that were verbose before newer APIs existed.

Source facts

Repository
bug-ops/claude-plugins
Last source activity
October 8, 2026 at 16:31
Detected SKILL.md language
English
Stars
12
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
17 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
rust-modern-apis
description
Reference for stable Rust APIs added in versions 1.89 through 1.99 (August 2025 - October 2026). Use whenever writing, reviewing, or refactoring Rust code when MSRV allows, to replace patterns that were verbose before newer APIs existed.
when_to_use
Modernizing Rust code, upgrading MSRV, "the latest Rust features", "can this be simpler in modern Rust?", or seeing manual UTF-8 truncation, path extension manipulation, advisory file locking via external crates, ignored `retain` removal results, `try_into().unwrap()` for fixed arrays, `compare_exchange` loops for atomic update, `cfg_if` crate usage, matching `0`/`1` to `bool`, `assert!(matches!(...))` in tests, hand-rolled bit-manipulation idioms, chained `strip_prefix`/`strip_suffix`, `.map(f).unwrap_or_default()`, the `itoa` crate, manual UTF-16LE/BE decoding, the `filetime` crate, `from_utf8_lossy(&v).into_owned()`, or `Box::into_raw` + `NonNull::new_unchecked` pairs.
# Modern Rust APIs (1.89 – 1.99) This skill is a lookup table for stable Rust APIs added after 1.88. Use it when writing or reviewing Rust code — replace older verbose patterns with newer concise ones where the project's MSRV allows. ## How to use this skill 1. **Check the project's MSRV first.** Look at `Cargo.toml` for `rust-version = "X.Y"`. Only suggest APIs available at or below the MSRV. If MSRV is lower than an API's version, either skip the suggestion or note that "raising MSRV to X.Y unlocks this." 2. **Scan the code for trigger patterns** (see section below). Each trigger maps to a newer API. When you see one, suggest the replacement with a brief before/after. 3. **For detailed API info**, read the matching reference file in `references/`. Files are organized by domain, not by version. 4. **Don't over-apply.** Some patterns are fine as-is. Only suggest a change when the new API is clearly better (shorter, safer, or fixes a subtle bug). ## Trigger patterns — fastest lookup Scan for these code shapes first. Each points to a concrete API that replaces it. | Code pattern spotted | Modern replacement | Version | Details | |----------------------|-------------------|---------|---------| | `Duration::from_secs(60 * N)` or ad-hoc minute math | `Duration::from_mins(N)` | 1.91 | [time.md](references/time.md) | | `Duration::from_secs(60 * 60 * N)` | `Duration::from_hours(N)` | 1.91 | [time.md](references/time.md) | | `path.with_extension("X.tmp")` (trying to ADD suffix) | `path.with_added_extension("tmp")` | 1.91 | [paths.md](references/paths.md) | | Manual `file_stem` + `format!` to compose meta paths | `path.with_added_extension(...)` | 1.91 | [paths.md](references/paths.md) | | `file_stem()` returning wrong thing for `.tar.gz` | `Path::file_prefix()` | 1.91 | [paths.md](references/paths.md) | | `path.to_string_lossy() == "literal"` | `path == Path::new("literal")` or `path == "literal"` | 1.91 | [paths.md](references/paths.md) | | `Ipv4Addr::new(a, b, c, d)` from `[u8; 4]` | `Ipv4Addr::from_octets(bytes)` | 1.91 | [net.md](references/net.md) | | `Ipv6Addr::new(a, b, c, d, e, f, g, h)` from segments | `Ipv6Addr::from_segments(segs)` | 1.91 | [net.md](references/net.md) | | Manual `is_char_boundary` loop for UTF-8 truncation | `str::floor_char_boundary(n)` / `ceil_char_boundary(n)` | 1.91 | [strings.md](references/strings.md) | | `checked_add(x).unwrap()` where overflow = bug | `strict_add(x)` | 1.91 | [arithmetic.md](references/arithmetic.md) | | `iter.into_iter().chain(other)` as free pattern | `std::iter::chain(iter, other)` | 1.91 | [iterators.md](references/iterators.md) | | `[val; N]` requiring `Copy` for non-Copy types | `core::array::repeat(val)` | 1.91 | [iterators.md](references/iterators.md) | | `retain` where you need to see/count removed items | `extract_if(..)` (Vec since 1.87, BTree since 1.91) | 1.87+ | [collections.md](references/collections.md) | | `fs2::FileExt::try_lock_exclusive` or custom lock | `File::try_lock()` / `File::lock()` | 1.89 | [io-files.md](references/io-files.md) | | External `pid-lock`/`fd-lock` crate | Built-in `File::lock` | 1.89 | [io-files.md](references/io-files.md) | | `Result<Result<T, E>, E>` manual flatten | `Result::flatten()` | 1.89 | [results.md](references/results.md) | | `slice.try_into::<[T; N]>().unwrap()` | `slice.as_array::<N>()` / `as_mut_array::<N>()` | 1.93 | [slices.md](references/slices.md) | | `slice.windows(N)` with const N giving `&[T]` | `slice.array_windows::<N>()` giving `&[T; N]` | 1.94 | [slices.md](references/slices.md) | | `write_copy_of_slice` / `write_clone_of_slice` on `MaybeUninit` | Stabilized `<[MaybeUninit<T>]>::write_copy_of_slice` | 1.93 | [maybe-uninit.md](references/maybe-uninit.md) | | One-off `impl Display` for temporary formatter | `std::fmt::from_fn(|f| ...)` | 1.93 | [formatting.md](references/formatting.md) | | `pop()` then `if !cond { push_back }` | `pop_front_if(cond)` / `pop_back_if(cond)` | 1.93 (VecDeque), 1.86 (Vec) | [collections.md](references/collections.md) | | Checking `LazyLock` was initialized without blocking | `LazyLock::get()` / `LazyCell::get()` | 1.94 | [sync.md](references/sync.md) | | Mutating `LazyLock` after init with `&mut` access | `LazyLock::force_mut()` / `get_mut()` | 1.94 | [sync.md](references/sync.md) | | `peekable.peek().filter(...).map(...)` with consume | `peekable.next_if_map(|v| ...)` | 1.94 | [iterators.md](references/iterators.md) | | `duration.as_nanos() > u64::MAX` concerns | `Duration::from_nanos_u128(n)` | 1.93 | [time.md](references/time.md) | | Magic number `4` for UTF-8 byte length | `char::MAX_LEN_UTF8` | 1.93 | [strings.md](references/strings.md) | | Magic number `2` for UTF-16 unit length | `char::MAX_LEN_UTF16` | 1.93 | [strings.md](references/strings.md) | | `BTreeMap`/`BTreeSet` full scan to evict | `BTreeMap::extract_if(..)` / `BTreeSet::extract_if(..)` | 1.91 | [collections.md](references/collections.md) | | `Default` not implemented for `Pin<Box<T>>` etc | Now works for `Pin<Box<T>>`, `Pin<Rc<T>>`, `Pin<Arc<T>>` | 1.91 | [sync.md](references/sync.md) | | Unsafe `Box::new(MaybeUninit::zeroed().assume_init())` | `Box::new_zeroed()` (unsafe-free alternative) | 1.92 | [maybe-uninit.md](references/maybe-uninit.md) | | `compare_exchange_weak` loop for atomic CAS-update pattern | `AtomicPtr/Bool/Isize/Usize::update()` / `try_update()` | 1.95 | [sync.md](references/sync.md) | | Matching integer `0`/`1` to produce `bool`, or `n != 0` for strict-validation | `bool::try_from(n)` (returns `Err` for any value ≠ 0/1) | 1.95 | [arithmetic.md](references/arithmetic.md) | | `cfg_if::cfg_if! { ... }` from external crate | `core::cfg_select! { ... }` (std macro) | 1.95 | [changelog.md](references/changelog.md) | | Manual `#[cold]` helper + `core::hint::unreachable_unchecked` to mark cold branches | `core::hint::cold_path()` | 1.95 | [changelog.md](references/changelog.md) | | `match` arm with `if let Some(x) = expr.foo() && cond(x)` simulated via nested matches | `match { Pattern if let Some(x) = ... => ... }` (`if let` guards) | 1.95 | [changelog.md](references/changelog.md) | | `unsafe { &*ptr }` to dereference a pointer known non-null | `unsafe { ptr.as_ref_unchecked() }` (and `as_mut_unchecked`) | 1.95 | [changelog.md](references/changelog.md) | | `assert!(matches!(x, Pat))` in tests, or `match x { Pat => {} _ => panic!() }` test scaffolding | `assert_matches!(x, Pat)` (prints the value's `Debug` on failure) | 1.96 | [assertions.md](references/assertions.md) | | `LazyLock::new(\|\| value)` / `LazyCell::new(\|\| value)` where `value` is already computed | `LazyLock::from(value)` / `LazyCell::from(value)` | 1.96 | [sync.md](references/sync.md) | | `std::ops::Range` field blocking `#[derive(Copy)]` on a struct | `core::range::Range` (is `Copy`; `IntoIterator` not `Iterator`) | 1.96 | [iterators.md](references/iterators.md) | | `1 << (Self::BITS - 1 - x.leading_zeros())` to isolate the highest set bit | `x.isolate_highest_one()` | 1.97 | [arithmetic.md](references/arithmetic.md) | | `x & x.wrapping_neg()` to isolate the lowest set bit | `x.isolate_lowest_one()` | 1.97 | [arithmetic.md](references/arithmetic.md) | | `Self::BITS - x.leading_zeros()` for value bit width | `x.bit_width()` | 1.97 | [arithmetic.md](references/arithmetic.md) | | Manual math for the index of the highest/lowest set bit | `x.highest_one()` / `x.lowest_one()` | 1.97 | [arithmetic.md](references/arithmetic.md) | | `s.strip_prefix(p).and_then(\|s\| s.strip_suffix(q))` chain | `s.strip_circumfix(p, q)` (also on slices) | 1.98 | [strings.md](references/strings.md) | | `haystack.find(part)` to recover the index of a `split()` result | `str::substr_range` / `slice::subslice_range` (pointer-derived, no search) | 1.98 | [strings.md](references/strings.md) | | `chunks_exact(2).map(u16::from_le_bytes)` + `String::from_utf16` | `String::from_utf16le` / `from_utf16be` (+ `_lossy`) | 1.98 | [strings.md](references/strings.md) | | `itoa` crate, or `n.to_string()` just to get digits into a buffer | `n.format_into(&mut NumBuffer::new())` | 1.98 | [formatting.md](references/formatting.md) | | `.map(f).unwrap_or_default()` on `Option`/`Result` | `.map_or_default(f)` | 1.98 | [results.md](references/results.md) | | `if cond { Ok(()) } else { Err(e) }` or `cond.then_some(()).ok_or(e)` | `cond.ok_or(e)` / `cond.ok_or_else(f)` | 1.98 | [results.md](references/results.md) | | `unsafe` transmute between `&mut u32` and `&AtomicU32` | `Atomic*::from_mut` / `from_mut_slice` / `get_mut_slice` | 1.98 | [sync.md](references/sync.md) |
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub