This repository has been archived on 2026-08-31. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
donglora/vendor/semihosting/src/c_str.rs
T
swaitsandClaude Opus 4.6 3102fc747a feat: add display UI with splash screen, dashboard, and RSSI sparkline
Implement full SSD1306 OLED display support:
- Splash screen on boot (1.5s) with project name, version, board
- Dashboard showing radio state, config, counters, RSSI/SNR
- RSSI history sparkline (64-sample ring buffer, 2px-wide bars)
- DisplayOn/DisplayOff host commands routed via dedicated channel
- Pure render functions against generic DrawTarget (no hardware coupling)
- Display on/off control bypasses radio task entirely

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 20:42:54 -06:00

127 lines
3.9 KiB
Rust

// SPDX-License-Identifier: Apache-2.0 OR MIT
// Provide safe abstraction (c! macro) for creating static C strings without runtime checks.
// (c"..." requires Rust 1.77)
/// [`CStr`] literal macro.
///
/// **Note:** Since Rust 1.77, this macro is soft-deprecated in favor of C string literals (`c"..."`).
///
/// [`Path`] is not available in `core`, so this crate uses [`CStr`] instead in the API where
/// `std` uses [`Path`]. This macro makes it safe and zero-cost to create a [`CStr`] from a literal.
///
/// ```no_run
/// use semihosting::{c, fs};
///
/// fs::write(c!("a.txt"), "abc")?;
/// // concat! in c! is also supported
/// fs::write(c!(concat!("b", ".txt")), "def")?;
/// # Ok::<(), semihosting::io::Error>(())
/// ```
///
/// This macro guarantees the correctness of the input by compile-time validation.
/// Incorrect input will cause compile-time errors.
///
/// ```compile_fail,E0080
/// use semihosting::c;
///
/// let s = c!("ab\0c"); // CStr must not contain any interior nul bytes.
/// ```
///
/// ```text
/// error[E0080]: evaluation of constant value failed
/// --> semihosting/src/c_str.rs:48:9
/// |
/// 48 | assert!(byte != 0, "input contained interior nul");
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'input contained interior nul', semihosting/src/c_str.rs:48:9
/// |
/// note: inside `const_c_str_check`
/// --> semihosting/src/c_str.rs:48:9
/// |
/// 48 | assert!(byte != 0, "input contained interior nul");
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/// note: inside `_`
/// --> src/c_str.rs:18:9
/// |
/// 5 | let s = c!("ab\0c"); // CStr must not contain any interior nul bytes.
/// | ^^^^^^^^^^^
/// ```
///
/// [`CStr`]: core::ffi::CStr
/// [`Path`]: https://doc.rust-lang.org/std/path/struct.Path.html
#[macro_export]
macro_rules! c {
($s:expr) => {{
const BYTES: &[u8] = $crate::__private::concat!($s, "\0").as_bytes();
const _: () = $crate::__private::const_c_str_check(BYTES);
#[allow(unused_unsafe)]
// SAFETY: we've checked `BYTES` is a valid C string
unsafe {
$crate::__private::CStr::from_bytes_with_nul_unchecked(BYTES)
}
}};
}
// Based on https://github.com/rust-lang/rust/blob/1.84.0/library/core/src/ffi/c_str.rs#L417
// - bytes must be nul-terminated.
// - bytes must not contain any interior nul bytes.
#[doc(hidden)]
pub const fn const_c_str_check(bytes: &[u8]) {
// Saturating so that an empty slice panics in the assert with a good
// message, not here due to underflow.
let mut i = bytes.len().saturating_sub(1);
assert!(!bytes.is_empty() && bytes[i] == 0, "input was not nul-terminated");
// Ending null byte exists, skip to the rest.
while i != 0 {
i -= 1;
let byte = bytes[i];
assert!(byte != 0, "input contained interior nul");
}
}
#[allow(
clippy::alloc_instead_of_core,
clippy::std_instead_of_alloc,
clippy::std_instead_of_core,
clippy::undocumented_unsafe_blocks,
clippy::wildcard_imports
)]
#[cfg(test)]
mod tests {
use core::ffi::CStr;
#[test]
fn test_c_macro() {
#[track_caller]
fn t(s: &CStr, raw: &[u8]) {
assert_eq!(s.to_bytes_with_nul(), raw);
}
t(c!(""), b"\0");
t(c!("a"), b"a\0");
t(c!("abc"), b"abc\0");
t(c!(concat!("abc", "d")), b"abcd\0");
}
#[test]
fn test_is_c_str() {
#[track_caller]
fn t(bytes: &[u8]) {
assert_eq!(
std::panic::catch_unwind(|| super::const_c_str_check(bytes)).is_ok(),
CStr::from_bytes_with_nul(bytes).is_ok()
);
}
t(b"\0");
t(b"a\0");
t(b"abc\0");
t(b"");
t(b"a");
t(b"abc");
t(b"\0a");
t(b"\0a\0");
t(b"ab\0c\0");
t(b"\0\0");
}
}