I'm currently wrapping the posix readdir{,_r}() in the manner performed by the rust stdlib for fs::read_dir(), which delegates to readdir_r() by default except for a specified list of platforms: rust/library/std/src/sys/fs/unix.rs at aa95b9648ad0383a3fd73b5271dd86f848b7c00c · rust-lang/rust · GitHub. If I understand correctly, the stdlib is relying on the result of readdir_r() always fitting into the stack-allocated dirent struct initialized with mem::zeroed() in the linked method body. In particular, contrast to the fs::read_dir() implementation immediately above used for linux, which must allocate an owned CString upon each iteration: rust/library/std/src/sys/fs/unix.rs at aa95b9648ad0383a3fd73b5271dd86f848b7c00c · rust-lang/rust · GitHub.
The dirent struct used for these platforms has a d_name field which is a fixed-size array of c_char, which is why the rust stdlib is able to avoid allocating a new CString on these platforms without introducing unsafety. See macos (libc/src/unix/bsd/apple/mod.rs at c6a3cd61445c38160c07b507617bb6099602759a · rust-lang/libc · GitHub):
pub struct dirent {
pub d_ino: u64,
pub d_seekoff: u64,
pub d_reclen: u16,
pub d_namlen: u16,
pub d_type: u8,
pub d_name: [c_char; 1024],
}
I am looking to get that array length in const context so I can make a trait like:
trait HasMaxSizedName {
const LEN: usize;
fn name(&self) -> &[c_char; Self::LEN];
}
#[cfg(target_vendor = "apple")]
impl HasMaxSizedName for libc::dirent {
// want # of array elements instead of byte length here
const LEN: usize = field_size!(Self, d_name);
fn name(&self) -> &[c_char; Self::LEN] { &self.d_name }
}
I would like to have this information available in the type system so I can use something like CStr::from_bytes_until_nul() on a bounded-size array, as opposed to using the unsafe method CStr::from_ptr() like the stdlib currently does (rust/library/std/src/sys/fs/unix.rs at aa95b9648ad0383a3fd73b5271dd86f848b7c00c · rust-lang/rust · GitHub).
For the stdlib's purposes, it actually could use CStr::from_bytes_until_nul(), since it's dealing with a concrete type. But I'm trying to make this HasMaxSizedName trait to differentiate platforms with a fixed-size immediate buffer from platforms like linux which must always eagerly allocate a new CString before moving to the next iteration result from fs::read_dir(). This is opposed to the stdlib's approach here, which forces all platforms into a single struct and uses unsafe methods for all of them, even though some of them could be safer. As of now, I am using lifetimes to propagate this ownership information, but being able to get the size of an array field in a type-level context like an associated constant would be much more ergonomic.