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/fd.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

224 lines
6.4 KiB
Rust

// SPDX-License-Identifier: Apache-2.0 OR MIT
//! Owned and borrowed Unix-like file descriptors.
//!
//! This is identical to [`std::os::fd`](https://doc.rust-lang.org/std/os/fd/index.html),
//! but available with no-std.
//!
//! Note that this crate does not provide `{As,Into,From}RawFd` traits. They have been effectively
//! obsoleted by io-safety, and now using `AsFd`, `From<... > for OwnedFd`, or `Into<OwnedFd>`
//! is recommended. To convert to `RawFd`, you need first convert it to `BorrowedFd` or
//! `OwnedFd` the above way and then call `BorrowedFd::as_raw_fd` or `OwnedFd::{as,into}_raw_fd`.
//! This redundancy is intentional, as it serves as a reminder that it is usually not
//! recommended.
#![allow(clippy::undocumented_unsafe_blocks)] // TODO
use core::{ffi::c_int, fmt, marker::PhantomData, mem::ManuallyDrop};
use crate::sys;
/// Raw file descriptors.
pub type RawFd = c_int;
// 16-bit targets has 16-bit c_int.
const _: () = {
#[cfg(not(target_pointer_width = "16"))]
assert!(core::mem::size_of::<RawFd>() == core::mem::size_of::<u32>());
#[cfg(target_pointer_width = "16")]
assert!(core::mem::size_of::<RawFd>() == core::mem::size_of::<u16>());
};
/// A borrowed file descriptor.
///
/// This has a lifetime parameter to tie it to the lifetime of something that
/// owns the file descriptor.
///
/// This uses `repr(transparent)` and has the representation of a host file
/// descriptor, so it can be used in FFI in places where a file descriptor is
/// passed as an argument, it is not captured or consumed, and it never has the
/// value `-1`.
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct BorrowedFd<'fd> {
fd: RawFd,
_phantom: PhantomData<&'fd OwnedFd>,
}
/// An owned file descriptor.
///
/// This closes the file descriptor on drop.
///
/// This uses `repr(transparent)` and has the representation of a host file
/// descriptor, so it can be used in FFI in places where a file descriptor is
/// passed as a consumed argument or returned as an owned value, and it never
/// has the value `-1`.
#[repr(transparent)]
pub struct OwnedFd {
fd: RawFd,
}
impl BorrowedFd<'_> {
/// Return a `BorrowedFd` holding the given raw file descriptor.
///
/// # Safety
///
/// The resource pointed to by `fd` must remain open for the duration of
/// the returned `BorrowedFd`, and it must not have the value `-1`.
#[inline]
pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
assert!(fd != -1);
Self { fd, _phantom: PhantomData }
}
/// Extracts the raw file descriptor.
#[allow(clippy::trivially_copy_pass_by_ref)] // align to AsRawFd::as_raw_fd
#[inline]
pub const fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
impl OwnedFd {
/// Constructs a new instance of `Self` from the given raw file descriptor.
///
/// # Safety
///
/// The resource pointed to by `fd` must be open and suitable for assuming
/// ownership. The resource must not require any cleanup other than `close`.
#[inline]
pub const unsafe fn from_raw_fd(fd: RawFd) -> Self {
assert!(fd != -1);
Self { fd }
}
/// Extracts the raw file descriptor.
#[inline]
pub const fn as_raw_fd(&self) -> RawFd {
self.fd
}
/// Consumes this object, returning the raw underlying file descriptor.
#[inline]
#[must_use = "losing the raw file descriptor may leak resources"]
pub fn into_raw_fd(self) -> RawFd {
let this = ManuallyDrop::new(self);
this.fd
}
}
impl Drop for OwnedFd {
#[inline]
fn drop(&mut self) {
#[cfg(feature = "stdio")]
if !sys::stdio::should_close(self) {
return;
}
// Note that errors are ignored when closing a file descriptor. The
// reason for this is that if an error occurs we don't actually know if
// the file descriptor was closed or not, and if we retried (for
// something like EINTR), we might close another valid file descriptor
// opened after we closed ours.
let _ = unsafe { sys::close(self.as_raw_fd()) };
}
}
impl fmt::Debug for BorrowedFd<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BorrowedFd").field("fd", &self.fd).finish()
}
}
impl fmt::Debug for OwnedFd {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OwnedFd").field("fd", &self.fd).finish()
}
}
/// A trait to borrow the file descriptor from an underlying object.
pub trait AsFd {
/// Borrows the file descriptor.
fn as_fd(&self) -> BorrowedFd<'_>;
}
impl<T: ?Sized + AsFd> AsFd for &T {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
T::as_fd(self)
}
}
impl<T: ?Sized + AsFd> AsFd for &mut T {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
T::as_fd(self)
}
}
impl AsFd for BorrowedFd<'_> {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
*self
}
}
impl AsFd for OwnedFd {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
// SAFETY: `OwnedFd` and `BorrowedFd` have the same validity
// invariants, and the `BorrowedFd` is bounded by the lifetime
// of `&self`.
unsafe { BorrowedFd::borrow_raw(self.fd) }
}
}
#[cfg(feature = "alloc")]
impl<T: ?Sized + AsFd> AsFd for alloc::boxed::Box<T> {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
(**self).as_fd()
}
}
#[cfg(feature = "alloc")]
impl<T: ?Sized + AsFd> AsFd for alloc::rc::Rc<T> {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
(**self).as_fd()
}
}
#[cfg(target_has_atomic = "ptr")]
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl<T: ?Sized + AsFd> AsFd for alloc::sync::Arc<T> {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
(**self).as_fd()
}
}
#[cfg(any(feature = "stdio", feature = "fs"))]
macro_rules! impl_as_fd {
($($ty:ty),* $(,)?) => {$(
impl crate::fd::AsFd for $ty {
#[inline]
fn as_fd(&self) -> crate::fd::BorrowedFd<'_> {
self.0.as_fd()
}
}
)*};
}
#[cfg(feature = "fs")]
macro_rules! impl_from_fd {
($($ty:ty),* $(,)?) => {$(
impl From<$ty> for OwnedFd {
#[inline]
fn from(this: $ty) -> Self {
this.0
}
}
impl From<OwnedFd> for $ty {
#[inline]
fn from(owned_fd: OwnedFd) -> Self {
Self(owned_fd)
}
}
)*};
}