From 7cee3a0fe3e261cf1885da401db3aebf901e6745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Gibrowski=20Fa=C3=A9?= Date: Sun, 5 Oct 2025 21:39:14 -0300 Subject: [PATCH] implement a `no_std` cargo feature The strategy is as follows: * anything that included `memmap` now also depends on `std` * change all imports from `std::*` to either `core::*` or `::alloc::*` as appropriate. * `new_from_locale` accepts a CStr in `no_std` environments * other load functions that depend on `std::fs` will not be included in `no_std` environments --- Cargo.toml | 3 ++- src/lib.rs | 9 ++++++- src/xkb/compose.rs | 35 ++++++++++++++++---------- src/xkb/ffi.rs | 2 +- src/xkb/mod.rs | 61 +++++++++++++++++++++++++++++----------------- src/xkb/x11/ffi.rs | 2 +- src/xkb/x11/mod.rs | 2 +- 7 files changed, 74 insertions(+), 40 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fa41dbed..5391df50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,8 @@ xkeysym = "0.2.0" evdev = "0.11.4" [features] -default = ["wayland"] +default = ["wayland", "std" ] +std = [] x11 = ["as-raw-xcb-connection"] wayland = ["memmap2"] diff --git a/src/lib.rs b/src/lib.rs index 4589bde7..980ffd9f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,12 @@ +#![no_std] + +#[cfg(feature = "std")] +extern crate std; + +extern crate alloc; + extern crate libc; -#[cfg(feature = "wayland")] +#[cfg(all(feature = "wayland", feature = "std"))] extern crate memmap2; pub mod xkb; diff --git a/src/xkb/compose.rs b/src/xkb/compose.rs index a68aac49..4039c264 100644 --- a/src/xkb/compose.rs +++ b/src/xkb/compose.rs @@ -1,11 +1,11 @@ use super::{Context, Keysym}; use crate::xkb::ffi::compose::*; -use std::borrow::Cow; -use std::ffi::CStr; -use std::ffi::CString; -use std::ffi::OsStr; -use std::mem; -use std::str; +use ::alloc::borrow::Cow; +use ::alloc::ffi::CString; +use ::alloc::string::String; +use core::ffi::CStr; +use core::mem; +use core::str; pub type CompileFlags = u32; pub const COMPILE_NO_FLAGS: CompileFlags = 0; @@ -45,15 +45,24 @@ impl Table { #[allow(clippy::result_unit_err, clippy::missing_errors_doc)] pub fn new_from_locale( context: &Context, - locale: &OsStr, + #[cfg(feature = "std")] locale: &std::ffi::OsStr, + #[cfg(not(feature = "std"))] locale: &CStr, flags: CompileFlags, ) -> Result { - use std::os::unix::ffi::OsStrExt; - - let locale_cstr = CStr::from_bytes_with_nul(locale.as_bytes()); - let locale_cstr = match locale_cstr { - Ok(loc) => Cow::from(loc), - Err(_) => Cow::from(CString::new(locale.as_bytes().to_vec()).unwrap()), + let locale_cstr = { + #[cfg(feature = "std")] + { + use std::os::unix::ffi::OsStrExt; + let locale_cstr = CStr::from_bytes_with_nul(locale.as_bytes()); + match locale_cstr { + Ok(loc) => Cow::from(loc), + Err(_) => Cow::from(CString::new(locale.as_bytes().to_vec()).unwrap()), + } + } + #[cfg(not(feature = "std"))] + { + locale + } }; let ptr = unsafe { diff --git a/src/xkb/ffi.rs b/src/xkb/ffi.rs index 59d21400..7823df75 100644 --- a/src/xkb/ffi.rs +++ b/src/xkb/ffi.rs @@ -1,7 +1,7 @@ #![allow(non_camel_case_types)] +use core::ffi::{c_char, c_int, c_uint, c_void}; use libc::{size_t, FILE}; -use std::os::raw::{c_char, c_int, c_uint, c_void}; pub enum xkb_context {} diff --git a/src/xkb/mod.rs b/src/xkb/mod.rs index c47a64d0..536be90f 100644 --- a/src/xkb/mod.rs +++ b/src/xkb/mod.rs @@ -15,23 +15,24 @@ pub mod x11; pub use self::compose::*; use crate::xkb::ffi::*; -#[cfg(feature = "wayland")] +#[cfg(all(feature = "wayland", feature = "std"))] use memmap2::MmapOptions; -#[cfg(feature = "wayland")] +#[cfg(all(feature = "wayland", feature = "std"))] use std::os::unix::io::OwnedFd; +use ::alloc::borrow::ToOwned; +use ::alloc::boxed::Box; +use ::alloc::ffi::CString; +use ::alloc::string::String; + +use core::borrow::Borrow; +use core::ffi::CStr; +use core::iter::Iterator; +use core::mem; +use core::ptr::{null, null_mut}; +use core::slice; +use core::str; use libc::{self, c_char, c_int, c_uint}; -use std::borrow::Borrow; -use std::ffi::{CStr, CString}; -use std::fs; -use std::io::Read; -use std::iter::Iterator; -use std::mem; -use std::os::raw; -use std::path::Path; -use std::ptr::{null, null_mut}; -use std::slice; -use std::str; /// A number used to represent a physical key on a keyboard. /// @@ -435,7 +436,8 @@ impl Context { /// append a new entry to the context's include path /// returns true on success, or false if the include path could not be added /// or is inaccessible - pub fn include_path_append(&mut self, path: &Path) -> bool { + #[cfg(feature = "std")] + pub fn include_path_append(&mut self, path: &std::path::Path) -> bool { path.to_str().map_or(false, |s| unsafe { let cstr = CString::from_vec_unchecked(s.as_bytes().to_owned()); xkb_context_include_path_append(self.ptr, cstr.as_ptr()) == 1 @@ -545,8 +547,11 @@ pub struct ContextIncludePaths<'a> { } impl<'a> Iterator for ContextIncludePaths<'a> { - type Item = &'a Path; - fn next(&mut self) -> Option<&'a Path> { + #[cfg(feature = "std")] + type Item = &'a std::path::Path; + #[cfg(not(feature = "std"))] + type Item = &'a CStr; + fn next(&mut self) -> Option { if self.ind == self.len { None } else { @@ -554,7 +559,16 @@ impl<'a> Iterator for ContextIncludePaths<'a> { let ptr = xkb_context_include_path_get(self.context.ptr, self.ind); self.ind += 1; let cstr = CStr::from_ptr(ptr); - Some(Path::new(str::from_utf8_unchecked(cstr.to_bytes()))) + #[cfg(feature = "std")] + { + Some(std::path::Path::new(str::from_utf8_unchecked( + cstr.to_bytes(), + ))) + } + #[cfg(not(feature = "std"))] + { + Some(cstr) + } } } } @@ -562,8 +576,9 @@ impl<'a> Iterator for ContextIncludePaths<'a> { #[test] fn check_include_paths() { + extern crate std; let mut c = Context::new(CONTEXT_NO_DEFAULT_INCLUDES); - let test_path = Path::new("/"); + let test_path = std::path::Path::new("/"); assert_eq!(true, c.include_path_append(&test_path)); assert_eq!(test_path, c.include_paths().nth(0).unwrap()); } @@ -695,12 +710,14 @@ impl Keymap { /// /// bindings implementation get the content in a `String` /// and call `new_from_string()`. + #[cfg(feature = "std")] pub fn new_from_file( context: &Context, - file: &mut fs::File, + file: &mut std::fs::File, format: KeymapFormat, flags: KeymapCompileFlags, ) -> Option { + use std::io::Read; let mut string = String::new(); file.read_to_string(&mut string) .ok() @@ -731,7 +748,7 @@ impl Keymap { } } - #[cfg(feature = "wayland")] + #[cfg(all(feature = "wayland", feature = "std"))] /// Create a keymap from a file descriptor. /// The file is mapped to memory and the keymap is created from the mapped memory buffer. /// @@ -749,7 +766,7 @@ impl Keymap { let map = MmapOptions::new() .len(size as usize) // Starting in version 7 of the wl_keyboard protocol, the keymap must be mapped using MAP_PRIVATE. - .map_copy_read_only(&fs::File::from(fd))?; + .map_copy_read_only(&std::fs::File::from(fd))?; let ptr = xkb_keymap_new_from_buffer(context.ptr, map.as_ptr().cast(), size, format, flags); if ptr.is_null() { Ok(None) @@ -799,7 +816,7 @@ impl Keymap { unsafe extern "C" fn callback( pkeymap: *mut ffi::xkb_keymap, key: ffi::xkb_keycode_t, - data: *mut raw::c_void, + data: *mut core::ffi::c_void, ) where F: FnMut(&Keymap, Keycode), { diff --git a/src/xkb/x11/ffi.rs b/src/xkb/x11/ffi.rs index d451b245..2577dc8e 100644 --- a/src/xkb/x11/ffi.rs +++ b/src/xkb/x11/ffi.rs @@ -1,7 +1,7 @@ use crate::xkb::ffi::{xkb_context, xkb_keymap, xkb_keymap_compile_flags, xkb_state}; use as_raw_xcb_connection::xcb_connection_t; -use std::os::raw::c_int; +use core::ffi::c_int; pub const XKB_X11_MIN_MAJOR_XKB_VERSION: u16 = 1; pub const XKB_X11_MIN_MINOR_XKB_VERSION: u16 = 0; diff --git a/src/xkb/x11/mod.rs b/src/xkb/x11/mod.rs index ac75091f..f0bb02da 100644 --- a/src/xkb/x11/mod.rs +++ b/src/xkb/x11/mod.rs @@ -3,7 +3,7 @@ pub mod ffi; use self::ffi::*; use super::{Context, Keymap, KeymapCompileFlags, State}; use as_raw_xcb_connection::AsRawXcbConnection; -use std::mem; +use core::mem; pub const MIN_MAJOR_XKB_VERSION: u16 = 1; pub const MIN_MINOR_XKB_VERSION: u16 = 0;