diff --git a/Rakefile b/Rakefile index 049fec0..69d9904 100644 --- a/Rakefile +++ b/Rakefile @@ -126,6 +126,7 @@ task :bindgen do bindgen --use-core --allowlist-function sysdir.* --allowlist-type sysdir.* + --blocklist-type sysdir_search_path_enumeration_state --allowlist-var PATH_MAX --default-enum-style rust_non_exhaustive --constified-enum sysdir_search_path_domain_mask_t @@ -150,6 +151,29 @@ task :bindgen do f.puts '' IO.copy_stream(bindgen_io, f) + + f.puts '' + f.puts <<~NEWTYPE + /// Opaque type for holding sysdir enumeration state. + #[repr(transparent)] + #[derive(Debug)] + #[allow(missing_copy_implementations)] + pub struct sysdir_search_path_enumeration_state(::core::ffi::c_uint); + + impl PartialEq<::core::ffi::c_uint> for sysdir_search_path_enumeration_state { + fn eq(&self, other: &::core::ffi::c_uint) -> bool { + self.0 == *other + } + } + + impl sysdir_search_path_enumeration_state { + /// Return true if the state indicates the enumeration is finished. + #[must_use] + pub fn is_finished(&self) -> bool { + self.0 == 0 + } + } + NEWTYPE end end diff --git a/src/lib.rs b/src/lib.rs index 7cabcee..cc32fc5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -143,4 +143,30 @@ mod tests { assert_eq!(count, 1, "Should iterate once and find `/Users`"); } + + #[test] + fn example_and_linkage_with_opaque_state_helpers() { + let mut count = 0_usize; + let mut path = [0; PATH_MAX as usize]; + + let dir = sysdir_search_path_directory_t::SYSDIR_DIRECTORY_USER; + let domain_mask = SYSDIR_DOMAIN_MASK_LOCAL; + + unsafe { + let mut state = sysdir_start_search_path_enumeration(dir, domain_mask); + loop { + let path = path.as_mut_ptr().cast::(); + state = sysdir_get_next_search_path_enumeration(state, path); + if state.is_finished() { + break; + } + let path = CStr::from_ptr(path); + let s = path.to_str().unwrap(); + assert_eq!(s, "/Users"); + count += 1; + } + } + + assert_eq!(count, 1, "Should iterate once and find `/Users`"); + } } diff --git a/src/sys.rs b/src/sys.rs index 22967fd..0eb70bd 100644 --- a/src/sys.rs +++ b/src/sys.rs @@ -48,7 +48,6 @@ pub const SYSDIR_DOMAIN_MASK_NETWORK: sysdir_search_path_domain_mask_t = 4; pub const SYSDIR_DOMAIN_MASK_SYSTEM: sysdir_search_path_domain_mask_t = 8; pub const SYSDIR_DOMAIN_MASK_ALL: sysdir_search_path_domain_mask_t = 65535; pub type sysdir_search_path_domain_mask_t = ::core::ffi::c_uint; -pub type sysdir_search_path_enumeration_state = ::core::ffi::c_uint; extern "C" { pub fn sysdir_start_search_path_enumeration( dir: sysdir_search_path_directory_t, @@ -61,3 +60,23 @@ extern "C" { path: *mut ::core::ffi::c_char, ) -> sysdir_search_path_enumeration_state; } + +/// Opaque type for holding sysdir enumeration state. +#[repr(transparent)] +#[derive(Debug)] +#[allow(missing_copy_implementations)] +pub struct sysdir_search_path_enumeration_state(::core::ffi::c_uint); + +impl PartialEq<::core::ffi::c_uint> for sysdir_search_path_enumeration_state { + fn eq(&self, other: &::core::ffi::c_uint) -> bool { + self.0 == *other + } +} + +impl sysdir_search_path_enumeration_state { + /// Return true if the state indicates the enumeration is finished. + #[must_use] + pub fn is_finished(&self) -> bool { + self.0 == 0 + } +}