Rust Internals
internals.rust-lang.org.web.brid.gy
Rust Internals
@internals.rust-lang.org.web.brid.gy
Discussions around the design and implementation of The Rust Programming Language

[bridged from https://internals.rust-lang.org/ on the web: https://fed.brid.gy/web/internals.rust-lang.org ]
Re-opening deprecating Option::unwrap and Result::unwrap
> Especially for people relatively new to rust, I think I would prefer the default were to lint against most unwraps. @toc > I believe a better approach is to change the default lint level of `unwrap` to a warning. @jmjoy I don't think linting would solve anything. And I think the number of false positives would be huge too, as someone above me said. And furthermore, anyone with more than 6 months (or 6 hours) of experience in rust knows `unwrap` can panic. I need to stress that for me, this isn't a safety/stability issue, imho, lints or renaming would _maybe_ make programmers think a bit more about `unwrap()`s but not in any impactful way. **I think the main issue is simply that the name doesn't say what the function does.** Yeah, everyone knows it, it's easy-ish to get used to, but it's just such a perpetual thorn in my side. **I thought that's why we even have crate-scope editions? So Rust can continually improve with breaking changes without actually breaking anything?** I personally would prefer Rust's stdlib not become like C++'s with 30+ years of historical baggage. * * * > For folks maintaining older MSRVs @burntsushi Do I understand correctly that Rust's crates are edition isolated? So if a crate needs no active work, needs no new rust features, needs to just continue working, it would not need to upgrade. And newer editions crates could still use it. I feel like the answer to the stable mature maintenance-mode software issue is just _well don't upgrade editions then_ * * * I do however like the symbolic variants of `unwrap_or_panic()`, like adding `unwrap_or_unreachable()` which would be the same as unwrap_or_panic but with the symbolic difference. * * * > Another strong reason against this is the confusion that I think is likely to result. And this is especially relevant to routines like `unwrap()` and `expect()` that have pervasive usage That I understand and I think it's the single biggest reason not to change it - it would instantly invalidate `unwrap`s in like one million community tutorials, docs and resources * * * > There simply isn't _that_ much wrong with the standard library. It has plenty of small annoyances, but I don't think they add up to something significant enough for an big edition-like overhaul to be worth it. @Mara I understand, and that's fair. I would disagree but I suppose this is purely subjective. * * * > As with any proposal, we must always start with the following question: "what is the problem that people are having with Rust today?" @Noratrieb The problem _I personally_ am having is that I do not like that name. I uhhhh might not be objective. * * * > If we do want to make the developers more cautious about unwrapping, a definite solution is to invent something similar to `unsafe` keyword, for example, `may_panic`, which means the it's the developers' responsibility to make sure the code does not panic: @Evian-Zhang I would love that, unfortunately, basically everything can panic. + operator can panic in Debug. Most containers can panic on many operations (`HashMap::index`). Oh and don't forget malloc() can fail at any time, so any `T::new()` can panic. * * * > `Regex::new` isn't `const` though. It may never be. I think I could come around to your perspective if `const` were more expressive, but it's a non-starter today IMO. There's just too many things that can't reasonably be `const`. > Yeah, I'm hoping at some point `const` and future `comptime` support essentially all of Rust. > We should have good tools for correctness checking -- I'm really excited by the contracts work Didn't hear of contracts before but it looks awesome! I do believe that good `comptime` + good contracts, would get rid of like 90% uses of `unwarp()` (a number i very scientifically made up). **I believe that most reasonable uses of unwrap() should be eventually replaced by contracts or`comptime`** _However_ , there would still be cases where one would need to use `unwrap` and I still think introducing `unwrap_or_panic()` and `unwrap_or_unreachable()` would be good for the stdlib
internals.rust-lang.org
November 26, 2025 at 1:25 PM
💡 Proposal: Add `include_c_str!` Macro to Rust
(post deleted by author)
internals.rust-lang.org
November 26, 2025 at 11:26 AM
💡 Proposal: Add `include_c_str!` Macro to Rust
The Rust language provides excellent build-time embedding tools with the existing `include_str!` and `include_bytes!` macros, allowing us to embed static file content directly into the final binary. These are incredibly useful for configuration, static assets, or templates. However, when working with **Foreign Function Interfaces (FFI)** , especially those leveraging C libraries, we often encounter a common friction point: safely and efficiently embedding null-terminated C-style strings. ## The Current Situation 1. **`include_str!`** : Returns `&'static str` (a UTF-8 slice). Converting this to a safe C string (e.g., `CStr`) at runtime requires an allocation (via `CString::new`) and checks for internal null bytes, which can panic. If the included file is known to be ASCII/valid C-string data, this conversion overhead is unnecessary. 2. **`include_bytes!`** : Returns `&'static [u8]`. While this gives us the raw bytes, we still need to manually verify it is null-terminated and safely create a `&'static core::ffi::CStr` from it, often requiring `unsafe` code and careful handling of the final null byte. ## The Case for `include_c_str!` I propose adding a new macro, `include_c_str!`, that would work as follows: * **Signature:** It would take a file path literal, similar to the existing macros. // Example usage: let c_string: &'static core::ffi::CStr = include_c_str!("path/to/my_c_string.txt"); * **Return Type:** It would return a `&'static core::ffi::CStr`. * **Compile-Time Guarantee:** The macro would perform **compile-time validation** on the file's contents to ensure: 1. The file contains no internal null bytes (`\0`) other than the optional, final terminator. 2. The file is properly **null-terminated**. If the file itself is not null-terminated, the macro should potentially append a null byte during embedding. 3. If any of these conditions are violated, the compilation should **fail** with a descriptive error. ## Benefits * **Safety & Ergonomics:** Eliminates the need for manual `unsafe` code to convert raw bytes or runtime `CString` allocation/error handling when dealing with embedded C-style strings. * **Performance:** Provides zero-cost abstraction for passing static C strings to FFI functions. * **Clarity:** Clearly expresses the intent of embedding a file specifically as a static C string. This addition would provide a complete set of static file inclusion tools for the most common embedded data types in Rust: Macro | Return Type | Use Case ---|---|--- `include_bytes!` | `&'static [u8]` | Arbitrary binary data. `include_str!` | `&'static str` | UTF-8 text. **`include_c_str!`** | **`&'static core::ffi::CStr`** | **Null-terminated C-style strings.** What are your thoughts on this proposal? Would this improve your FFI workflow?
internals.rust-lang.org
November 26, 2025 at 7:22 AM
Bad optimization for continuous memory access with redundant early check
> What happens if you move the b0 check after the let/else and remove the first redundant check and `buf.get?` Rust code: fn u64_fetch3(buf: &[u8], pos: usize) -> bool { let Some([b0, b1, b2, b3, b4, b5, b6, b7]) = buf.get(pos..(pos + 8)) else { return false; }; if *b0 != 0x78 { return false; } let target = u64::from_le_bytes([*b0, *b1, *b2, *b3, *b4, *b5, *b6, *b7]); target == 0x1234567812345678 } > what happens if you include the test it in the match? Rust code: fn u64_fetch4(buf: &[u8], pos: usize) -> bool { let Some([b0 @ 0x78, b1, b2, b3, b4, b5, b6, b7]) = buf.get(pos..(pos + 8)) else { return false; }; let target = u64::from_le_bytes([*b0, *b1, *b2, *b3, *b4, *b5, *b6, *b7]); target == 0x1234567812345678 } Both of the above Rust codes generate the same assembly: u64_fetch3: cmp rdx, -8 setae al lea rcx, [rdx + 8] cmp rcx, rsi seta cl or cl, al jne .LBB4_1 cmp byte ptr [rdi + rdx], 120 jne .LBB4_1 movzx eax, byte ptr [rdi + rdx + 1] movzx ecx, byte ptr [rdi + rdx + 2] mov esi, dword ptr [rdi + rdx + 4] shl rsi, 32 movzx edx, byte ptr [rdi + rdx + 3] shl edx, 24 shl ecx, 16 shl eax, 8 or eax, ecx or eax, edx or rax, rsi movabs rcx, 1311768465173140992 cmp rax, rcx sete al ret Still five memory accesses. > you can also give a name for the whole array to avoid repetition when passing to from_bytes Thank you very much for this suggestion! But I rarely use this feature, could you give me an example about how to write such code?
internals.rust-lang.org
November 26, 2025 at 7:22 AM