use std::{ ffi::{CStr, OsStr}, os::unix::ffi::OsStrExt as _, }; pub trait SliceExt { fn split_once_ch(&self, ch: u8) -> Option<(&[u8], &[u8])>; } impl SliceExt for [u8] { fn split_once_ch(&self, ch: u8) -> Option<(&[u8], &[u8])> { let (idx, _) = self.iter().enumerate().find(|(_, b)| **b == ch)?; // SAFETY: idx is IN-OF-BOUNDS index of the slice unsafe { Some((self.get_unchecked(0..idx), self.get_unchecked((idx + 1)..))) } } } pub trait CStrExt { fn to_os_str(&self) -> &OsStr; fn split_ch(&self, ch: u8) -> Option<(&[u8], &CStr)>; } impl CStrExt for CStr { fn to_os_str(&self) -> &OsStr { OsStr::from_bytes(self.to_bytes()) } fn split_ch(&self, ch: u8) -> Option<(&[u8], &CStr)> { let self_slice = self.to_bytes_with_nul(); self_slice.split_once_ch(ch).map(|(k, v)| { // # SAFETY split originated in a slice with final null byte, hence second split will be // null terminated (k, unsafe { Self::from_bytes_with_nul_unchecked(v) }) }) } } pub trait StrExt { fn as_os_str(&self) -> &OsStr; } impl StrExt for str { fn as_os_str(&self) -> &OsStr { OsStr::from_bytes(self.as_bytes()) } }