diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index b737e9a..68eb318 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -6,14 +6,14 @@ }, "metadata": { "description": "Professional Rust development plugin: specialist agents with LSP integration, team orchestration, and peer-to-peer communication", - "version": "1.48.0" + "version": "1.49.0" }, "plugins": [ { "name": "rust-agents", "source": "./rust-code", - "description": "Rust development agents and skills for Claude Code: 15 specialist agents (architect, developer, testing, performance, security, reviewer, CI/CD, debugger, critic, SDD, live-tester, tech-writer, researcher, architecture and security analysts), team-develop and team-debug agent-team orchestration, a read-only continuous-improvement cycle that also runs headless, Rust 1.89-1.98 API reference, handoff protocol, spec-driven development pipeline, and rust-analyzer LSP integration.", - "version": "1.48.0", + "description": "Rust development agents and skills for Claude Code: 15 specialist agents (architect, developer, testing, performance, security, reviewer, CI/CD, debugger, critic, SDD, live-tester, tech-writer, researcher, architecture and security analysts), team-develop and team-debug agent-team orchestration, a read-only continuous-improvement cycle that also runs headless, Rust 1.89-1.99 API reference, handoff protocol, spec-driven development pipeline, and rust-analyzer LSP integration.", + "version": "1.49.0", "author": { "name": "Andrei G", "email": "andrei.g@my.com" @@ -56,7 +56,7 @@ "spec-driven-development", "modern-apis", "rust-1-89", - "rust-1-98" + "rust-1-99" ], "category": "development", "tags": [ diff --git a/README.md b/README.md index 71df452..ed9a680 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ This repository contains plugins that extend Claude Code's capabilities with spe ### Rust Agents Plugin (`rust-code`) -[![Version](https://img.shields.io/badge/version-1.48.0-blue)](./rust-code) +[![Version](https://img.shields.io/badge/version-1.49.0-blue)](./rust-code) [![License](https://img.shields.io/badge/license-MIT-green)](./rust-code/LICENSE) A comprehensive collection of specialized Rust development agents covering the entire Rust development lifecycle. @@ -38,7 +38,7 @@ A comprehensive collection of specialized Rust development agents covering the e - **sdd** — Spec-Driven Development workflow - **spec-from-stream** — Business requirements from stream-of-consciousness (BRD/SRS/NFR) - **fast-yaml** — YAML validation, formatting, and conversion - - **rust-modern-apis** — Lookup table for stable Rust APIs added in 1.89–1.98 + - **rust-modern-apis** — Lookup table for stable Rust APIs added in 1.89–1.99 - rust-analyzer LSP integration for real-time code intelligence - Proactive triggers for automatic agent selection - Rust Edition 2024 support diff --git a/rust-code/.claude-plugin/plugin.json b/rust-code/.claude-plugin/plugin.json index f060c8a..110f791 100644 --- a/rust-code/.claude-plugin/plugin.json +++ b/rust-code/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "rust-agents", - "version": "1.48.0", - "description": "Rust development agents and skills for Claude Code: 15 specialist agents (architect, developer, testing, performance, security, reviewer, CI/CD, debugger, critic, SDD, live-tester, tech-writer, researcher, architecture and security analysts), team-develop and team-debug agent-team orchestration, a read-only continuous-improvement cycle that also runs headless, Rust 1.89-1.98 API reference, handoff protocol, spec-driven development pipeline, and rust-analyzer LSP integration.", + "version": "1.49.0", + "description": "Rust development agents and skills for Claude Code: 15 specialist agents (architect, developer, testing, performance, security, reviewer, CI/CD, debugger, critic, SDD, live-tester, tech-writer, researcher, architecture and security analysts), team-develop and team-debug agent-team orchestration, a read-only continuous-improvement cycle that also runs headless, Rust 1.89-1.99 API reference, handoff protocol, spec-driven development pipeline, and rust-analyzer LSP integration.", "author": { "name": "Andrei G", "email": "andrei.g@my.com" @@ -44,6 +44,6 @@ "spec-driven-development", "modern-apis", "rust-1-89", - "rust-1-98" + "rust-1-99" ] } diff --git a/rust-code/CHANGELOG.md b/rust-code/CHANGELOG.md index dae02bc..17df40c 100644 --- a/rust-code/CHANGELOG.md +++ b/rust-code/CHANGELOG.md @@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.49.0] - 2026-10-01 + +### Added + +- `rust-modern-apis`: Rust 1.99 coverage — changelog section, trigger-table and MSRV-gate entries, and reference entries for `String::from_utf8_lossy_owned`/`into_utf8_lossy`, `fs::set_times`, `Box::into_non_null`, `Vec::into_parts`, `VecDeque::retain_back`, `IntoIterator for Box<[T; N]>`, raw-pointer layout queries, and 1.99 Cargo changes. (#12) + +### Changed + +- Skill coverage range extended to 1.89–1.99 across README badges, `rust-arch-analyst` startup protocol, plugin and marketplace manifests; version bumped to `1.49.0`. (#12) + ## [1.48.0] - 2026-09-29 ### Changed diff --git a/rust-code/README.md b/rust-code/README.md index d42b038..6e0096a 100644 --- a/rust-code/README.md +++ b/rust-code/README.md @@ -1,6 +1,6 @@ # Rust Agents Plugin -[![Version](https://img.shields.io/badge/version-1.48.0-blue)](https://github.com/bug-ops/claude-plugins) +[![Version](https://img.shields.io/badge/version-1.49.0-blue)](https://github.com/bug-ops/claude-plugins) [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE) [![Rust Edition](https://img.shields.io/badge/rust-Edition%202024-orange)](https://doc.rust-lang.org/edition-guide/rust-2024/) @@ -28,7 +28,7 @@ A comprehensive collection of specialized Rust development agents for Claude Cod - **sdd** — Full-cycle Spec-Driven Development: BRD/SRS/NFR → spec/plan/tasks - **spec-from-stream** — Business requirements from stream-of-consciousness input - **fast-yaml** — YAML validation, formatting, and conversion - - **rust-modern-apis** — Lookup table for stable Rust APIs added in 1.89–1.98; loaded explicitly at session startup by rust-developer and rust-code-reviewer + - **rust-modern-apis** — Lookup table for stable Rust APIs added in 1.89–1.99; loaded explicitly at session startup by rust-developer and rust-code-reviewer - **rust-analyzer LSP integration** for real-time code intelligence with Claude - **Proactive triggers** — agents are suggested automatically based on your task - **Rust Edition 2024** support with modern tooling @@ -554,7 +554,7 @@ YAML validation, formatting, linting, and JSON↔YAML conversion via the `fy` CL ### rust-modern-apis -Reference lookup table for stable Rust APIs added in versions 1.89–1.98 (August 2025 – August 2026). +Reference lookup table for stable Rust APIs added in versions 1.89–1.99 (August 2025 – October 2026). **Active by default in**: `rust-developer`, `rust-code-reviewer` diff --git a/rust-code/agents/15-rust-arch-analyst.md b/rust-code/agents/15-rust-arch-analyst.md index 19e5db9..0e8d370 100644 --- a/rust-code/agents/15-rust-arch-analyst.md +++ b/rust-code/agents/15-rust-arch-analyst.md @@ -17,7 +17,7 @@ You are not designing new architecture — you are auditing what exists. Every f # Startup Protocol (MANDATORY) -1. Call `Skill(skill: "rust-agents:rust-modern-apis")` to load awareness of stable Rust APIs added in 1.89–1.98. +1. Call `Skill(skill: "rust-agents:rust-modern-apis")` to load awareness of stable Rust APIs added in 1.89–1.99. 2. Call `Skill(skill: "rust-agents:rust-agent-handoff")` and follow the protocol (your suffix: `arch-analyst`). 3. Call `Skill(skill: "rust-agents:arch-inspect")` to load the audit checklist and follow it. diff --git a/rust-code/skills/rust-modern-apis/SKILL.md b/rust-code/skills/rust-modern-apis/SKILL.md index 44e4de2..dc3c33c 100644 --- a/rust-code/skills/rust-modern-apis/SKILL.md +++ b/rust-code/skills/rust-modern-apis/SKILL.md @@ -1,10 +1,10 @@ --- name: rust-modern-apis -description: Reference for stable Rust APIs added in versions 1.89 through 1.98 (August 2025 - August 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, or manual UTF-16LE/BE decoding. +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.98) +# 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. @@ -79,6 +79,13 @@ Scan for these code shapes first. Each points to a concrete API that replaces it | `pb.into_os_string().into_string().map_err(PathBuf::from)` | `pb.into_string()` | 1.98 | [paths.md](references/paths.md) | | Fast-math reassociation hacks (nightly `fadd_fast`, manual reordering) | `f32/f64::algebraic_add/sub/mul/div/rem` | 1.98 | [arithmetic.md](references/arithmetic.md) | | `u32::from_str_radix(s, 16)` then `NonZero::new(..).ok_or(..)` | `NonZero::from_str_radix(s, 16)` | 1.98 | [arithmetic.md](references/arithmetic.md) | +| `String::from_utf8_lossy(&vec).into_owned()` (always copies) | `String::from_utf8_lossy_owned(vec)` (reuses the buffer) | 1.99 | [strings.md](references/strings.md) | +| `from_utf8(v)` + separate lossy fallback re-reading the bytes | `String::from_utf8(v).unwrap_or_else(\|e\| e.into_utf8_lossy())` | 1.99 | [strings.md](references/strings.md) | +| `filetime` crate, or opening a `File` just to `set_times` | `std::fs::set_times(path, times)` / `set_times_nofollow` | 1.99 | [io-files.md](references/io-files.md) | +| `Box::into_raw(b)` + `NonNull::new_unchecked(p)` pair | `Box::into_non_null(b)` / `Box::from_non_null(p)` | 1.99 | [sync.md](references/sync.md) | +| `Vec::into_raw_parts` + `NonNull::new_unchecked` for FFI handles | `Vec::into_parts()` / `Vec::from_parts(..)` (NonNull-based) | 1.99 | [collections.md](references/collections.md) | +| `boxed_array.into_vec().into_iter()` or `.iter().cloned()` to consume `Box<[T; N]>` | `boxed_array.into_iter()` (`IntoIterator` for `Box<[T; N]>`) | 1.99 | [collections.md](references/collections.md) | +| Reverse `retain` loop with `swap_remove_back` / index math on `VecDeque` tail | `VecDeque::retain_back(\|x\| ..)` | 1.99 | [collections.md](references/collections.md) | ## Version → MSRV gate @@ -96,6 +103,7 @@ When suggesting an API, check MSRV first. Quick reference: - **MSRV 1.96+**: `assert_matches!` / `debug_assert_matches!`, `From` for `LazyCell` / `LazyLock` / `AssertUnwindSafe`, `core::range::Range`/`RangeFrom`/`RangeToInclusive` (+ matching `*Iter`), `NonZero` range iteration - **MSRV 1.97+**: integer bit-manipulation methods `isolate_highest_one`/`isolate_lowest_one`/`highest_one`/`lowest_one`/`bit_width` (all integer types + `NonZero` equivalents, all `const fn`), `char::is_control` const - **MSRV 1.98+**: `str::substr_range`/`slice::subslice_range`, `strip_circumfix` (str + slices), `String::from_utf16le`/`from_utf16be` (+ `_lossy`), integer `format_into` + `core::fmt::NumBuffer`, float `algebraic_*` ops (const), `NonZero::from_str_radix` (const), `Option/Result::map_or_default`, `bool::ok_or`/`ok_or_else`, atomic `from_mut`/`get_mut_slice`/`from_mut_slice`, `Box::as_ptr`/`as_mut_ptr`, `PathBuf::into_string`, `Path::is_empty` +- **MSRV 1.99+**: `String::from_utf8_lossy_owned`, `FromUtf8Error::into_utf8_lossy`, `fs::set_times`/`set_times_nofollow`, `Box::into_non_null`/`from_non_null`, `Vec::into_parts`/`from_parts`, `IntoIterator for Box<[T; N]>`, `VecDeque::retain_back`, `FusedIterator for StepBy`, `mem::size_of_val_raw`/`align_of_val_raw`, `Layout::for_value_raw`, `core::ffi::VaList` + C-variadic fn definitions Full changelog by version lives in [references/changelog.md](references/changelog.md) if you need to explain a release to the user or find something not in the trigger table. @@ -127,7 +135,7 @@ Don't produce walls of diffs for trivial cosmetic changes. Batch suggestions log Read these only when you need the details. Each file covers one domain across all versions: -- [references/changelog.md](references/changelog.md) — full release notes by version (1.89-1.98) — use when the user asks about a specific release +- [references/changelog.md](references/changelog.md) — full release notes by version (1.89-1.99) — use when the user asks about a specific release - [references/paths.md](references/paths.md) — `Path`/`PathBuf` API additions (1.91 mainly) - [references/strings.md](references/strings.md) — `str` and `char` additions - [references/time.md](references/time.md) — `Duration` additions diff --git a/rust-code/skills/rust-modern-apis/references/changelog.md b/rust-code/skills/rust-modern-apis/references/changelog.md index 2e96633..1020574 100644 --- a/rust-code/skills/rust-modern-apis/references/changelog.md +++ b/rust-code/skills/rust-modern-apis/references/changelog.md @@ -1,4 +1,4 @@ -# Rust release changelog (1.89 – 1.98) +# Rust release changelog (1.89 – 1.99) Consolidated changes relevant to application code. For the full release notes, see [doc.rust-lang.org/stable/releases.html](https://doc.rust-lang.org/stable/releases.html). @@ -654,6 +654,75 @@ New lints: `unnecessary_unwrap_unchecked` (complexity), `chunks_exact_to_as_chun --- +## Rust 1.99 (2026-10-01) + +Source: [releases.rs/docs/1.99.0/](https://releases.rs/docs/1.99.0/) and [blog.rust-lang.org/2026/10/01/Rust-1.99.0](https://blog.rust-lang.org/2026/10/01/Rust-1.99.0/). + +### Language + +- **C-variadic function definitions stabilized** for the `C` and `C-unwind` ABIs — Rust code can now *define* (not just call) `extern "C" fn f(x: i32, ...)` using `core::ffi::VaList`, with arguments constrained by the `VaArgSafe` trait. `#[unsafe(naked)]` is also allowed on C-variadic functions. +- Stabilized custom attributes on outlined modules: `#[my_macro] mod foo;` now works (macro expansion on module declarations). +- 128-bit integers can be passed in vector registers in x86 `asm!`. +- Trait methods now resolve on the adjusted never type; coercion from inference variables to trait objects improved. +- New allow-by-default `raw_borrows_via_references` lint; `unconditional_panic` extended to zero-sized `chunks`/`windows`; unused `#[path]` attributes on inline modules are now linted; POSIX symbols added to the runtime-symbol-definition lints (see 1.98). +- Documented guarantees: allocation growth behavior, and access to `UnsafeCell` contents without `get()`. + +### Stabilized APIs + +**Box / Vec raw-handle round-trips** (NonNull-based, complement the raw-pointer forms): +- `Box::into_non_null`, `Box::from_non_null` +- `Vec::into_parts` → `(NonNull, usize, usize)`, `Vec::from_parts` + +**Collections / iterators**: +- `impl IntoIterator for Box<[T; N]>` (and `&Box<[T; N]>`, `&mut Box<[T; N]>`) — iterate a boxed array by value +- `VecDeque::retain_back` — like `retain`, but walks from the back and stops at the first kept element +- `impl FusedIterator for StepBy` + +**Strings**: +- `String::from_utf8_lossy_owned(Vec) -> String` — lossy conversion that reuses the allocation when the input is valid UTF-8 +- `string::FromUtf8Error::into_utf8_lossy(self) -> String` — lossy recovery after a failed `String::from_utf8` + +**Filesystem**: +- `std::fs::set_times(path, FileTimes)`, `std::fs::set_times_nofollow` — set file timestamps by path, without opening a `File` (std replacement for the `filetime` crate) + +**Layout from raw pointers** (all `unsafe`): +- `core::mem::size_of_val_raw`, `core::mem::align_of_val_raw` +- `core::alloc::Layout::for_value_raw` + +**FFI**: +- `core::ffi::VaList` (see Language above) + +### Compiler + +- LLVM 23. +- Static position-independent executables enabled on GNU/musl targets. +- `riscv64-unknown-linux-musl` promoted to Tier 2 with host tools. +- Method suggestions prefer exact doc-alias matches over similarity matching. + +### Cargo + +- **New built-in `debug` profile** — currently an alias for `dev`, preparation for renaming the default profile. +- Edition 2024+ workspace members can override an inherited dependency's `default-features`. +- **Incremental compilation is disabled by default in CI environments** (detected via `CI` env var) — speeds up cold CI builds and shrinks caches; set `CARGO_INCREMENTAL=1` to restore. + +### Rustdoc + +- New `unused_footnote_definition` lint. +- Trait-impl filtering optimized — 20% average (up to 40%) faster doc builds. + +### Compatibility notes + +- **Legacy numeric modules fully deprecated** — `std::i32::MAX` etc. now warn everywhere; use the associated consts (`i32::MAX`). +- `no_mangle_generic_items` upgraded to a hard error. +- References to extern statics are no longer promoted. +- `#[repr(simd)]` on macro invocations no longer accepted on stable (accidental stabilization fixed). +- Anonymous lifetimes in associated consts now inferred as `'static`. +- `Pin::new_unchecked` safety docs tightened; `Box::leak` docs now recommend `Box::into_non_null` over leak-then-free round-trips. +- Doc-comment code-block attributes that don't apply now generate errors; `doc(cfg())` is ignored when filtering doctests. +- Macros expanding to semicolons now warn even when the macro comes from another crate. + +--- + ## How to use this changelog - **Looking up when an API stabilized**: skim the "Stabilized APIs" section under each version. diff --git a/rust-code/skills/rust-modern-apis/references/collections.md b/rust-code/skills/rust-modern-apis/references/collections.md index cd92f8b..b3e8fb7 100644 --- a/rust-code/skills/rust-modern-apis/references/collections.md +++ b/rust-code/skills/rust-modern-apis/references/collections.md @@ -106,6 +106,54 @@ let v = unsafe { Vec::from_raw_parts(ptr, len, cap) }; Only useful if you're building FFI layers or similar low-level code. For `unsafe_code = "deny"` projects, skip. +## `VecDeque::retain_back` — 1.99 + +**`retain` that walks from the back and stops at the first element it keeps.** + +```rust +// Before — reverse scan with index math to drop a "dirty tail" +while deque.back().is_some_and(|x| is_stale(x)) { + deque.pop_back(); +} + +// After (1.99+) — predicate form, symmetric with retain +deque.retain_back(|x| !is_stale(x)); +``` + +Unlike `retain`, it short-circuits: once an element is kept, everything in front of it stays untouched — O(tail) instead of O(n). The right tool for queues where staleness is monotonic from the back (newest entries invalidated on rollback, trailing placeholder frames). If stale items can be interleaved with live ones, you still want full `retain`/`extract_if`. + +## `Vec::into_parts` / `Vec::from_parts` — 1.99 + +**`NonNull`-based decomposition — the modern pairing for `into_raw_parts` (1.93).** + +```rust +// Before (1.93) — raw *mut, nullability re-checked or unchecked at rebuild +let (ptr, len, cap) = v.into_raw_parts(); +let nn = unsafe { NonNull::new_unchecked(ptr) }; + +// After (1.99+) — NonNull straight out, and back +let (ptr, len, cap): (NonNull, usize, usize) = v.into_parts(); +let v = unsafe { Vec::from_parts(ptr, len, cap) }; +``` + +A `Vec`'s buffer pointer is never null (even for capacity 0 it's a dangling well-aligned pointer), so `NonNull` encodes the invariant in the type instead of an `unsafe` assertion at every rebuild site. Prefer this pair over `into_raw_parts`/`from_raw_parts` in new FFI/allocator code; same for `Box::into_non_null`/`from_non_null` (see [sync.md](sync.md)). + +## `IntoIterator for Box<[T; N]>` — 1.99 + +**Consume a boxed array by value directly.** + +```rust +let boxed: Box<[String; 3]> = Box::new(["a".into(), "b".into(), "c".into()]); + +// Before — round-trip through Vec, or clone each element +for s in boxed.into_vec() { /* re-allocates nothing but loses the fixed size */ } + +// After (1.99+) +for s in boxed.into_iter() { /* owned String, no clones, no Vec detour */ } +``` + +`&Box<[T; N]>` and `&mut Box<[T; N]>` also got `IntoIterator`, so `for x in &boxed` works without the explicit deref. Mostly removes friction in generic code that stores large fixed-size arrays on the heap to keep them off the stack. + ## `btree_map::Entry::insert_entry` / `VacantEntry::insert_entry` — 1.92 Returns an `OccupiedEntry` after inserting, letting you continue manipulating the entry without a second lookup: diff --git a/rust-code/skills/rust-modern-apis/references/compiler-cargo.md b/rust-code/skills/rust-modern-apis/references/compiler-cargo.md index d31472a..881468c 100644 --- a/rust-code/skills/rust-modern-apis/references/compiler-cargo.md +++ b/rust-code/skills/rust-modern-apis/references/compiler-cargo.md @@ -116,7 +116,34 @@ Mostly a code-cleanup lint. Covered in [results.md](results.md). Not a warning change for existing correct code, but unblocks patterns where `E = Infallible`. -## Updates to minimum LLVM — 1.87 → LLVM 20; 1.91 → LLVM 21; 1.92 → LLVM 20 minimum external; 1.96 → LLVM 21 minimum external +## Incremental compilation off by default in CI — 1.99 + +Cargo now disables incremental compilation when it detects a CI environment (the `CI` env var). Cold CI builds get faster and caches shrink — incremental artifacts were pure overhead for throwaway build dirs. If your CI genuinely reuses a persistent target dir across runs and benefited from incremental, restore it explicitly: + +```yaml +env: + CARGO_INCREMENTAL: "1" +``` + +Audit CI configs after raising the toolchain to 1.99: pipelines that set `CARGO_INCREMENTAL=0` manually can drop the knob; pipelines with warm caches should measure before deciding. + +## Built-in `debug` profile — 1.99 + +Cargo gained a built-in profile named `debug`, currently equivalent to `dev` — groundwork for renaming the default profile. `cargo build --profile debug` now works; a custom `[profile.debug]` section in existing manifests now collides with the built-in and needs renaming. + +## Workspace `default-features` override — 1.99 (Edition 2024+) + +A workspace member can now turn default features back off when inheriting a dependency: + +```toml +# member Cargo.toml, edition 2024+ +[dependencies] +serde = { workspace = true, default-features = false } +``` + +Previously `default-features = false` on an inherited dep was ignored with a warning if the workspace definition left defaults on. Removes a long-standing reason to duplicate full dependency specs in members that need a leaner feature set. + +## Updates to minimum LLVM — 1.87 → LLVM 20; 1.91 → LLVM 21; 1.92 → LLVM 20 minimum external; 1.96 → LLVM 21 minimum external; 1.99 → LLVM 23 If you're building the compiler or linking against rustc's LLVM, these version bumps matter. For most projects, transparent. diff --git a/rust-code/skills/rust-modern-apis/references/io-files.md b/rust-code/skills/rust-modern-apis/references/io-files.md index ca2ff3e..d37a2dd 100644 --- a/rust-code/skills/rust-modern-apis/references/io-files.md +++ b/rust-code/skills/rust-modern-apis/references/io-files.md @@ -98,9 +98,23 @@ window.seek(SeekFrom::Start(512))?; // seek within the 1 KiB window Useful for reading sub-ranges with a seekable view, e.g., parsing headers in fixed-size records. -## `File::set_times` / `File::set_modified` — stabilized earlier, context here +## `std::fs::set_times` / `set_times_nofollow` — 1.99 -These existed pre-1.89 but are worth mentioning next to `File::lock` because daemon code often cares about both. Use for touch-like operations without shelling out. +**Set file timestamps by path — std replacement for the `filetime` crate.** + +```rust +use std::fs::{self, FileTimes}; +use std::time::SystemTime; + +// Before — open a handle just to touch timestamps, or pull in `filetime` +let f = fs::OpenOptions::new().write(true).open(&path)?; +f.set_times(FileTimes::new().set_modified(SystemTime::now()))?; + +// After (1.99+) — path-based, no handle, works on read-only files +fs::set_times(&path, FileTimes::new().set_modified(SystemTime::now()))?; +``` + +`set_times_nofollow` is the symlink-aware variant: it sets times on the link itself instead of its target (the `lutimes` counterpart). Common sites: build tools preserving mtimes on copy, archive extractors, cache touch-on-read, test fixtures. The handle-based `File::set_times`/`set_modified` (stable since 1.75) remain right when you already hold the `File`. ## What's NOT in std diff --git a/rust-code/skills/rust-modern-apis/references/iterators.md b/rust-code/skills/rust-modern-apis/references/iterators.md index 7395b34..75a9997 100644 --- a/rust-code/skills/rust-modern-apis/references/iterators.md +++ b/rust-code/skills/rust-modern-apis/references/iterators.md @@ -149,6 +149,14 @@ for i in w.span { /* ... */ } // IntoIterator yields RangeIter; w.span still u Not a drop-in replacement everywhere — `..` literals and indexing still produce the `std::ops` types, and you convert with `From`/`into()`. Reach for `core::range::*` specifically when you need a range stored in a `Copy` type or passed by value repeatedly without re-cloning. +## `FusedIterator for StepBy` — 1.99 + +`step_by(n)` adapters now implement `FusedIterator` when the inner iterator does. No code change — `fuse()` on a `StepBy` chain becomes a no-op and generic bounds requiring `FusedIterator` now accept it directly. + +## `IntoIterator for Box<[T; N]>` — 1.99 + +Boxed fixed-size arrays iterate by value (also via `&`/`&mut`). Details in [collections.md](collections.md). + ### NonZero range iteration — 1.96 Ranges bounded by `NonZero`/`NonZero` now iterate directly. Niche, but it removes the old dance of mapping over a primitive range and re-wrapping each element with `NonZero::new(..).unwrap()`. diff --git a/rust-code/skills/rust-modern-apis/references/maybe-uninit.md b/rust-code/skills/rust-modern-apis/references/maybe-uninit.md index bc96d90..7e45f92 100644 --- a/rust-code/skills/rust-modern-apis/references/maybe-uninit.md +++ b/rust-code/skills/rust-modern-apis/references/maybe-uninit.md @@ -94,6 +94,21 @@ Particularly useful for ML/tensor code where you need large zeroed buffers and w No API change, but closes a spec gap. If you're reading crate code that transmutes arrays of `MaybeUninit`, the soundness is now officially blessed rather than "clearly intended." +## Layout from raw pointers — `size_of_val_raw` / `align_of_val_raw` / `Layout::for_value_raw` — 1.99 + +**Query size/alignment through a raw pointer — no reference needed.** + +```rust +// Before — materializing &*ptr just to measure asserts validity/aliasing to the model +let size = std::mem::size_of_val(unsafe { &*ptr }); + +// After (1.99+) — stays in raw-pointer land +let size = unsafe { core::mem::size_of_val_raw(ptr) }; +let layout = unsafe { core::alloc::Layout::for_value_raw(ptr) }; +``` + +All three are `unsafe` (for unsized tails the metadata must be valid), but they avoid creating an intermediate `&T` — which matters for possibly-dangling or not-yet-initialized allocations in custom allocators, `Drop` glue, and vtable-driven deallocation of `dyn Trait` pointers. For ordinary sized `T` behind a healthy reference, plain `size_of_val`/`Layout::for_value` remain correct and safe. + ## When to use MaybeUninit at all - **Custom collections** where you grow capacity before filling (similar to `Vec`'s internal layout). diff --git a/rust-code/skills/rust-modern-apis/references/strings.md b/rust-code/skills/rust-modern-apis/references/strings.md index 160d3d1..db8cc4e 100644 --- a/rust-code/skills/rust-modern-apis/references/strings.md +++ b/rust-code/skills/rust-modern-apis/references/strings.md @@ -162,6 +162,35 @@ let s = String::from_utf16le_lossy(bytes); // String, invalid data → U+FFF Note the input type: the LE/BE variants take `&[u8]` (raw bytes), while the native `from_utf16` takes `&[u16]`. This removes the intermediate `Vec` allocation and the `chunks_exact` boilerplate. Common sites: Windows file formats and registry data, JVM class files, USB string descriptors, wire protocols with declared endianness. +## `String::from_utf8_lossy_owned(Vec)` — 1.99 + +**Lossy UTF-8 conversion that takes ownership — no copy when the input is already valid.** + +```rust +// Before — Cow borrows from the Vec, so into_owned() always copies valid input +let s = String::from_utf8_lossy(&bytes).into_owned(); + +// After (1.99+) — valid input: buffer reused, zero-copy; invalid: replaced with U+FFFD +let s = String::from_utf8_lossy_owned(bytes); +``` + +The borrowing `from_utf8_lossy(&[u8]) -> Cow` stays the right call when you only need a view. Reach for the owned variant exactly when you have a `Vec` you're done with and the result must be a `String` — log ingestion, subprocess output, network payloads. + +## `FromUtf8Error::into_utf8_lossy()` — 1.99 + +**Recover lossily after a failed strict conversion — without re-validating.** + +```rust +// Before — the error path re-reads the bytes from scratch +let s = String::from_utf8(bytes.clone()) + .unwrap_or_else(|_| String::from_utf8_lossy(&bytes).into_owned()); + +// After (1.99+) — the error already owns the bytes and knows where validation stopped +let s = String::from_utf8(bytes).unwrap_or_else(|e| e.into_utf8_lossy()); +``` + +Kills both the `clone` and the second validation pass. This is the idiomatic "strict if possible, lossy otherwise" pipeline as of 1.99. + ## `<[T]>::ceil_char_boundary` parallel for slices There's no slice equivalent — `ceil_char_boundary`/`floor_char_boundary` are `str`-specific because they rely on UTF-8 invariants. diff --git a/rust-code/skills/rust-modern-apis/references/sync.md b/rust-code/skills/rust-modern-apis/references/sync.md index b44433d..4657b88 100644 --- a/rust-code/skills/rust-modern-apis/references/sync.md +++ b/rust-code/skills/rust-modern-apis/references/sync.md @@ -84,6 +84,22 @@ let p: *mut T = Box::as_mut_ptr(&mut boxed); Matters for FFI and self-referential setups: the returned pointer is derived without an intermediate `&`/`&mut`, so under Stacked/Tree Borrows it doesn't invalidate other outstanding raw pointers to the same allocation the way a fresh `&mut *boxed` does. For casual "pass a pointer to C and forget it" code, either spelling works — but the new one is shorter and Miri-friendlier. +## `Box::into_non_null` / `Box::from_non_null` — 1.99 + +**`NonNull` round-trip for owned heap allocations — replaces `into_raw` + `new_unchecked`.** + +```rust +// Before — the non-nullness of Box's pointer re-asserted manually +let ptr: NonNull = unsafe { NonNull::new_unchecked(Box::into_raw(b)) }; +let b: Box = unsafe { Box::from_raw(ptr.as_ptr()) }; + +// After (1.99+) +let ptr: NonNull = Box::into_non_null(b); +let b: Box = unsafe { Box::from_non_null(ptr) }; +``` + +A `Box` pointer is never null, so `into_non_null` is safe and the invariant lives in the type. The 1.99 docs also explicitly recommend this pair over `Box::leak` round-trips ("leak then reconstruct to free") — leak-based patterns interact badly with compiler optimizations and custom allocators. `Vec` got the same treatment via `into_parts`/`from_parts` (see [collections.md](collections.md)). + ## `LazyLock::get` / `LazyCell::get` — 1.94 **Check initialization without forcing it.**