diff --git a/Cargo.toml b/Cargo.toml index a299a5a..483d2e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,8 +10,9 @@ edition = "2018" [dependencies] bitflags = "1" -fsevent-sys = "4.0.0" -# fsevent-sys = { path = "fsevent-sys" } +# fsevent-sys = "5.0.0" +fsevent-sys = { path = "fsevent-sys" } +core-foundation = "0.9.4" [dev-dependencies] tempfile = "3" diff --git a/examples/fsevent-async-demo.rs b/examples/fsevent-async-demo.rs index 5d6abc2..4372949 100644 --- a/examples/fsevent-async-demo.rs +++ b/examples/fsevent-async-demo.rs @@ -1,12 +1,9 @@ -extern crate fsevent; +use std::{sync::mpsc::channel, thread}; -use std::sync::mpsc::channel; -use std::thread; - -#[cfg(not(target_os="macos"))] +#[cfg(not(target_os = "macos"))] fn main() {} -#[cfg(target_os="macos")] +#[cfg(target_os = "macos")] fn main() { let (sender, receiver) = channel(); @@ -24,7 +21,7 @@ fn main() { Err(e) => match e { std::sync::mpsc::RecvTimeoutError::Disconnected => break, _ => {} // This is the case where nothing entered the channel buffer (no file mods). - } + }, } } diff --git a/examples/fsevent-demo.rs b/examples/fsevent-demo.rs index 3d3cad8..31b3ffb 100644 --- a/examples/fsevent-demo.rs +++ b/examples/fsevent-demo.rs @@ -1,11 +1,9 @@ -extern crate fsevent; -use std::sync::mpsc::channel; -use std::thread; +use std::{sync::mpsc::channel, thread}; -#[cfg(not(target_os="macos"))] +#[cfg(not(target_os = "macos"))] fn main() {} -#[cfg(target_os="macos")] +#[cfg(target_os = "macos")] fn main() { let (sender, receiver) = channel(); diff --git a/fsevent-sys/Cargo.toml b/fsevent-sys/Cargo.toml index 523dee4..81009d2 100644 --- a/fsevent-sys/Cargo.toml +++ b/fsevent-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fsevent-sys" -version = "4.1.0" +version = "5.0.0" authors = ["Pierre Baillet "] description = "Rust bindings to the fsevent macOS API for file changes notifications" license = "MIT" @@ -8,7 +8,11 @@ repository = "https://github.com/octplane/fsevent-rust/tree/master/fsevent-sys" edition = "2018" [dependencies] -libc = "0.2.68" +dispatch2 = { version = "0.2.0", default-features = false, features = ["alloc"] } +core-foundation = "0.9.2" [package.metadata.docs.rs] -targets = ["x86_64-apple-darwin"] +targets = [ + "x86_64-apple-darwin", + "aarch64-apple-darwin", +] diff --git a/fsevent-sys/src/core_foundation.rs b/fsevent-sys/src/core_foundation.rs deleted file mode 100644 index 47792f7..0000000 --- a/fsevent-sys/src/core_foundation.rs +++ /dev/null @@ -1,230 +0,0 @@ -#![allow(non_upper_case_globals, non_camel_case_types)] - -extern crate libc; - -use std::ffi::CString; -use std::ptr; -use std::str; - -pub type Boolean = ::std::os::raw::c_uchar; - -pub type CFRef = *mut ::std::os::raw::c_void; - -pub type CFIndex = ::std::os::raw::c_long; -pub type CFTimeInterval = f64; -pub type CFAbsoluteTime = CFTimeInterval; - -#[doc(hidden)] -pub enum CFError {} - -pub type CFAllocatorRef = CFRef; -pub type CFArrayRef = CFRef; -pub type CFMutableArrayRef = CFRef; -pub type CFURLRef = CFRef; -pub type CFErrorRef = *mut CFError; -pub type CFStringRef = CFRef; -pub type CFRunLoopRef = CFRef; - -pub const NULL: CFRef = 0 as CFRef; -pub const NULL_REF_PTR: *mut CFRef = 0 as *mut CFRef; - -pub type CFAllocatorRetainCallBack = - extern "C" fn(*const ::std::os::raw::c_void) -> *const ::std::os::raw::c_void; -pub type CFAllocatorReleaseCallBack = extern "C" fn(*const ::std::os::raw::c_void); -pub type CFAllocatorCopyDescriptionCallBack = - extern "C" fn(*const ::std::os::raw::c_void) -> *const CFStringRef; - -pub type CFURLPathStyle = CFIndex; - -pub const kCFAllocatorDefault: CFAllocatorRef = NULL; -pub const kCFURLPOSIXPathStyle: CFURLPathStyle = 0; -pub const kCFURLHFSPathStyle: CFURLPathStyle = 1; -pub const kCFURLWindowsPathStyle: CFURLPathStyle = 2; - -pub const kCFStringEncodingUTF8: CFStringEncoding = 0x08000100; -pub type CFStringEncoding = u32; - -pub const kCFCompareEqualTo: CFIndex = 0; -pub type CFComparisonResult = CFIndex; - -// MacOS uses Case Insensitive path -pub const kCFCompareCaseInsensitive: CFStringCompareFlags = 1; -pub type CFStringCompareFlags = ::std::os::raw::c_ulong; - -pub type CFArrayRetainCallBack = - extern "C" fn(CFAllocatorRef, *const ::std::os::raw::c_void) -> *const ::std::os::raw::c_void; -pub type CFArrayReleaseCallBack = extern "C" fn(CFAllocatorRef, *const ::std::os::raw::c_void); -pub type CFArrayCopyDescriptionCallBack = - extern "C" fn(*const ::std::os::raw::c_void) -> CFStringRef; -pub type CFArrayEqualCallBack = - extern "C" fn(*const ::std::os::raw::c_void, *const ::std::os::raw::c_void) -> Boolean; - -#[repr(C)] -pub struct CFArrayCallBacks { - version: CFIndex, - retain: Option, - release: Option, - cp: Option, - equal: Option, -} -//impl Clone for CFArrayCallBacks { } - -#[link(name = "CoreFoundation", kind = "framework")] -extern "C" { - pub static kCFTypeArrayCallBacks: CFArrayCallBacks; - pub static kCFRunLoopDefaultMode: CFStringRef; - - pub fn CFRelease(res: CFRef); - pub fn CFShow(res: CFRef); - pub fn CFCopyDescription(cf: CFRef) -> CFStringRef; - - pub fn CFRunLoopRun(); - pub fn CFRunLoopStop(run_loop: CFRunLoopRef); - pub fn CFRunLoopGetCurrent() -> CFRunLoopRef; - - pub fn CFArrayCreateMutable( - allocator: CFRef, - capacity: CFIndex, - callbacks: *const CFArrayCallBacks, - ) -> CFMutableArrayRef; - pub fn CFArrayInsertValueAtIndex(arr: CFMutableArrayRef, position: CFIndex, element: CFRef); - pub fn CFArrayAppendValue(aff: CFMutableArrayRef, element: CFRef); - pub fn CFArrayGetCount(arr: CFMutableArrayRef) -> CFIndex; - pub fn CFArrayGetValueAtIndex(arr: CFMutableArrayRef, index: CFIndex) -> CFRef; - - pub fn CFURLCreateFileReferenceURL( - allocator: CFRef, - url: CFURLRef, - err: *mut CFErrorRef, - ) -> CFURLRef; - pub fn CFURLCreateFilePathURL( - allocator: CFRef, - url: CFURLRef, - err: *mut CFErrorRef, - ) -> CFURLRef; - pub fn CFURLCreateFromFileSystemRepresentation( - allocator: CFRef, - path: *const ::std::os::raw::c_char, - len: CFIndex, - is_directory: bool, - ) -> CFURLRef; - pub fn CFURLCopyAbsoluteURL(res: CFURLRef) -> CFURLRef; - pub fn CFURLCopyLastPathComponent(res: CFURLRef) -> CFStringRef; - pub fn CFURLCreateCopyDeletingLastPathComponent(allocator: CFRef, url: CFURLRef) -> CFURLRef; - pub fn CFURLCreateCopyAppendingPathComponent( - allocation: CFRef, - url: CFURLRef, - path: CFStringRef, - is_directory: bool, - ) -> CFURLRef; - pub fn CFURLCopyFileSystemPath(anUrl: CFURLRef, path_style: CFURLPathStyle) -> CFStringRef; - - pub fn CFURLResourceIsReachable(res: CFURLRef, err: *mut CFErrorRef) -> bool; - - pub fn CFShowStr(str: CFStringRef); - pub fn CFStringGetCString( - theString: CFStringRef, - buffer: *mut ::std::os::raw::c_char, - buffer_size: CFIndex, - encoding: CFStringEncoding, - ) -> bool; - pub fn CFStringGetCStringPtr( - theString: CFStringRef, - encoding: CFStringEncoding, - ) -> *const ::std::os::raw::c_char; - pub fn CFStringCreateWithCString( - alloc: CFRef, - source: *const ::std::os::raw::c_char, - encoding: CFStringEncoding, - ) -> CFStringRef; - - pub fn CFStringCompare( - theString1: CFStringRef, - theString2: CFStringRef, - compareOptions: CFStringCompareFlags, - ) -> CFComparisonResult; - pub fn CFArrayRemoveValueAtIndex(theArray: CFMutableArrayRef, idx: CFIndex); -} - -pub unsafe fn str_path_to_cfstring_ref(source: &str, err: &mut CFErrorRef) -> CFStringRef { - let c_path = CString::new(source).unwrap(); - let c_len = libc::strlen(c_path.as_ptr()); - let mut url = CFURLCreateFromFileSystemRepresentation( - kCFAllocatorDefault, - c_path.as_ptr(), - c_len as CFIndex, - false, - ); - if url.is_null() { - return ptr::null_mut(); - } - - let mut placeholder = CFURLCopyAbsoluteURL(url); - CFRelease(url); - if placeholder.is_null() { - return ptr::null_mut(); - } - - let mut imaginary: CFRef = ptr::null_mut(); - - while !CFURLResourceIsReachable(placeholder, ptr::null_mut()) { - if imaginary.is_null() { - imaginary = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - if imaginary.is_null() { - CFRelease(placeholder); - return ptr::null_mut(); - } - } - - let child = CFURLCopyLastPathComponent(placeholder); - CFArrayInsertValueAtIndex(imaginary, 0, child); - CFRelease(child); - - url = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, placeholder); - CFRelease(placeholder); - placeholder = url; - } - - url = CFURLCreateFileReferenceURL(kCFAllocatorDefault, placeholder, err); - CFRelease(placeholder); - if url.is_null() { - if !imaginary.is_null() { - CFRelease(imaginary); - } - return ptr::null_mut(); - } - - placeholder = CFURLCreateFilePathURL(kCFAllocatorDefault, url, err); - CFRelease(url); - if placeholder.is_null() { - if !imaginary.is_null() { - CFRelease(imaginary); - } - return ptr::null_mut(); - } - - if !imaginary.is_null() { - let mut count = 0; - while count < CFArrayGetCount(imaginary) { - let component = CFArrayGetValueAtIndex(imaginary, count); - url = CFURLCreateCopyAppendingPathComponent( - kCFAllocatorDefault, - placeholder, - component, - false, - ); - CFRelease(placeholder); - if url.is_null() { - CFRelease(imaginary); - return ptr::null_mut(); - } - placeholder = url; - count += 1; - } - CFRelease(imaginary); - } - - let cf_path = CFURLCopyFileSystemPath(placeholder, kCFURLPOSIXPathStyle); - CFRelease(placeholder); - cf_path -} diff --git a/fsevent-sys/src/fsevent.rs b/fsevent-sys/src/fsevent.rs index 25c8ba3..a244721 100644 --- a/fsevent-sys/src/fsevent.rs +++ b/fsevent-sys/src/fsevent.rs @@ -1,12 +1,21 @@ #![allow(non_upper_case_globals, non_camel_case_types)] -use crate::core_foundation::{ - Boolean, CFAbsoluteTime, CFAllocatorCopyDescriptionCallBack, CFAllocatorRef, - CFAllocatorReleaseCallBack, CFAllocatorRetainCallBack, CFArrayRef, CFIndex, CFRunLoopRef, - CFStringRef, CFTimeInterval, +use core_foundation::{ + array::{CFArrayRef, CFIndex}, + base::{ + Boolean, CFAllocatorCopyDescriptionCallBack, CFAllocatorReleaseCallBack, + CFAllocatorRetainCallBack, + }, + date::{CFAbsoluteTime, CFTimeInterval}, + mach_port::CFAllocatorRef, + runloop::CFRunLoopRef, + string::CFStringRef, +}; +use dispatch2::ffi::dispatch_queue_t; +use std::os::{ + raw::{c_uint, c_void}, + unix::raw::dev_t, }; -use libc::dev_t; -use std::os::raw::{c_uint, c_void}; pub type FSEventStreamRef = *mut c_void; pub type ConstFSEventStreamRef = *const c_void; @@ -74,7 +83,7 @@ pub struct FSEventStreamContext { // https://developer.apple.com/documentation/coreservices/file_system_events #[link(name = "CoreServices", kind = "framework")] -extern "C" { +unsafe extern "C" { pub fn FSEventStreamCopyDescription(stream_ref: ConstFSEventStreamRef) -> CFStringRef; pub fn FSEventStreamCopyPathsBeingWatched(streamRef: ConstFSEventStreamRef) -> CFArrayRef; pub fn FSEventStreamCreate( @@ -109,7 +118,7 @@ extern "C" { run_loop: CFRunLoopRef, run_loop_mode: CFStringRef, ); - // pub fn FSEventStreamSetDispatchQueue(streamRef: FSEventStreamRef, q: DispatchQueue); + pub fn FSEventStreamSetDispatchQueue(stream_ref: FSEventStreamRef, q: dispatch_queue_t); pub fn FSEventStreamSetExclusionPaths( stream_ref: FSEventStreamRef, paths_to_exclude: CFArrayRef, diff --git a/fsevent-sys/src/lib.rs b/fsevent-sys/src/lib.rs index 07b9b51..ae10a35 100644 --- a/fsevent-sys/src/lib.rs +++ b/fsevent-sys/src/lib.rs @@ -1,7 +1,4 @@ #![cfg(target_os = "macos")] -#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))] -pub mod core_foundation; mod fsevent; - pub use fsevent::*; diff --git a/src/lib.rs b/src/lib.rs index 822c19b..4de85d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,25 +5,28 @@ unused_import_braces, unused_qualifications )] -#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))] -#[macro_use] -extern crate bitflags; - -extern crate fsevent_sys as fsevent; - -use fsevent as fs; -use fsevent::core_foundation as cf; - -use std::ffi::CStr; -use std::fmt::{Display, Formatter}; -use std::os::raw::{c_char, c_void}; -use std::ptr; - -use std::sync::mpsc::Sender; +use bitflags::bitflags; +use core_foundation::{ + array::CFArray, + base::{kCFAllocatorDefault, TCFType}, + date::CFTimeInterval, + runloop::{ + kCFRunLoopDefaultMode, CFRunLoopGetCurrent, CFRunLoopRef, CFRunLoopRun, CFRunLoopStop, + }, + string::CFString, +}; +use fsevent_sys as fs; +use std::{ + ffi::CStr, + fmt::{Display, Formatter}, + os::raw::c_void, + slice, + sync::mpsc::Sender, +}; // Helper to send the runloop from an observer thread. -struct CFRunLoopSendWrapper(cf::CFRunLoopRef); +struct CFRunLoopSendWrapper(CFRunLoopRef); // Safety: According to the Apple documentation, it is safe to send CFRef types across threads. // @@ -33,9 +36,9 @@ unsafe impl Send for CFRunLoopSendWrapper {} pub struct FsEvent { paths: Vec, since_when: fs::FSEventStreamEventId, - latency: cf::CFTimeInterval, + latency: CFTimeInterval, flags: fs::FSEventStreamCreateFlags, - runloop: Option, + runloop: Option, } #[derive(Debug)] @@ -163,7 +166,7 @@ fn default_stream_context(event_sender: *const Sender) -> fs::FSEventStre } } -pub type Result = std::result::Result; +pub type Result = std::result::Result; #[derive(Debug)] pub struct Error { @@ -182,14 +185,6 @@ impl Display for Error { } } -impl From for Error { - fn from(err: std::sync::mpsc::RecvTimeoutError) -> Error { - Self { - msg: err.to_string(), - } - } -} - impl FsEvent { pub fn new(paths: Vec) -> Self { Self { @@ -207,83 +202,45 @@ impl FsEvent { Ok(()) } - fn build_native_paths(&self) -> Result { - let native_paths = unsafe { - cf::CFArrayCreateMutable(cf::kCFAllocatorDefault, 0, &cf::kCFTypeArrayCallBacks) - }; - - if native_paths == std::ptr::null_mut() { - Err(Error { - msg: "Unable to allocate CFMutableArrayRef".to_string(), - }) - } else { - for path in &self.paths { - unsafe { - let mut err = ptr::null_mut(); - let cf_path = cf::str_path_to_cfstring_ref(path, &mut err); - if !err.is_null() { - let cf_str = cf::CFCopyDescription(err as cf::CFRef); - let mut buf = [0; 1024]; - cf::CFStringGetCString( - cf_str, - buf.as_mut_ptr(), - buf.len() as cf::CFIndex, - cf::kCFStringEncodingUTF8, - ); - return Err(Error { - msg: CStr::from_ptr(buf.as_ptr()) - .to_str() - .unwrap_or("Unknown error") - .to_string(), - }); - } else { - cf::CFArrayAppendValue(native_paths, cf_path); - cf::CFRelease(cf_path); - } - } - } - - Ok(native_paths) - } + fn build_native_paths(&self) -> CFArray { + let paths: Vec<_> = self.paths.iter().map(|x| CFString::new(x)).collect(); + CFArray::from_CFTypes(&paths) } fn internal_observe( since_when: fs::FSEventStreamEventId, - latency: cf::CFTimeInterval, + latency: CFTimeInterval, flags: fs::FSEventStreamCreateFlags, - paths: cf::CFMutableArrayRef, + paths: CFArray, event_sender: Sender, runloop_sender: Option>, ) -> Result<()> { let stream_context = default_stream_context(&event_sender); - let paths = paths.into(); unsafe { let stream = fs::FSEventStreamCreate( - cf::kCFAllocatorDefault, + kCFAllocatorDefault, callback, &stream_context, - paths, + paths.as_concrete_TypeRef() as _, since_when, latency, flags, ); if let Some(ret_tx) = runloop_sender { - let runloop = CFRunLoopSendWrapper(cf::CFRunLoopGetCurrent()); - ret_tx - .send(runloop) - .expect("unabe to send CFRunLoopRef"); + let runloop = CFRunLoopSendWrapper(CFRunLoopGetCurrent()); + ret_tx.send(runloop).expect("unabe to send CFRunLoopRef"); } fs::FSEventStreamScheduleWithRunLoop( stream, - cf::CFRunLoopGetCurrent(), - cf::kCFRunLoopDefaultMode, + CFRunLoopGetCurrent(), + kCFRunLoopDefaultMode, ); fs::FSEventStreamStart(stream); - cf::CFRunLoopRun(); + CFRunLoopRun(); fs::FSEventStreamFlushSync(stream); fs::FSEventStreamStop(stream); @@ -293,9 +250,7 @@ impl FsEvent { } pub fn observe(&self, event_sender: Sender) { - let native_paths = self - .build_native_paths() - .expect("Unable to build CFMutableArrayRef of watched paths."); + let native_paths = self.build_native_paths(); Self::internal_observe( self.since_when, self.latency, @@ -309,16 +264,15 @@ impl FsEvent { pub fn observe_async(&mut self, event_sender: Sender) -> Result<()> { let (ret_tx, ret_rx) = std::sync::mpsc::channel(); - let native_paths = self.build_native_paths()?; + let native_paths = self.build_native_paths(); - struct CFMutableArraySendWrapper(cf::CFMutableArrayRef); + struct CFMutableArraySendWrapper(CFArray); // Safety // - See comment on `CFRunLoopSendWrapper unsafe impl Send for CFMutableArraySendWrapper {} - let safe_native_paths = CFMutableArraySendWrapper(native_paths); - + let paths = CFMutableArraySendWrapper(native_paths); let since_when = self.since_when; let latency = self.latency; let flags = self.flags; @@ -328,7 +282,7 @@ impl FsEvent { since_when, latency, flags, - safe_native_paths.0, + paths.0, event_sender, Some(ret_tx), ) @@ -342,7 +296,9 @@ impl FsEvent { // Shut down the event stream. pub fn shutdown_observe(&mut self) { if let Some(runloop) = self.runloop.take() { - unsafe { cf::CFRunLoopStop(runloop); } + unsafe { + CFRunLoopStop(runloop); + } } } } @@ -355,25 +311,30 @@ extern "C" fn callback( event_flags: *const fs::FSEventStreamEventFlags, // const FSEventStreamEventFlags eventFlags[] event_ids: *const fs::FSEventStreamEventId, // const FSEventStreamEventId eventIds[] ) { - unsafe { - let event_paths = event_paths as *const *const c_char; - let sender = info as *mut Sender; - - for pos in 0..num_events { - let path = CStr::from_ptr(*event_paths.add(pos)) - .to_str() - .expect("Invalid UTF8 string."); - let flag = *event_flags.add(pos); - let event_id = *event_ids.add(pos); - - let event = Event { - event_id: event_id, - flag: StreamFlags::from_bits(flag).unwrap_or_else(|| { - panic!("Unable to decode StreamFlags: {} for {}", flag, path) - }), - path: path.to_string(), - }; - let _s = (*sender).send(event); - } + let event_paths = unsafe { slice::from_raw_parts(event_paths as *const *const i8, num_events) }; + let event_flags = unsafe { slice::from_raw_parts(event_flags, num_events) }; + let event_ids = unsafe { slice::from_raw_parts(event_ids, num_events) }; + let sender = unsafe { + (info as *mut Sender) + .as_mut() + .expect("Invalid Sender.") + }; + for event in + event_paths + .iter() + .zip(event_flags) + .zip(event_ids) + .map(|((&path, &flag), &id)| unsafe { + let path = CStr::from_ptr(path).to_str().expect("Invalid UTF8 string."); + Event { + event_id: id, + flag: StreamFlags::from_bits(flag).unwrap_or_else(|| { + panic!("Unable to decode StreamFlags: {} for {}", flag, path) + }), + path: path.to_string(), + } + }) + { + let _s = sender.send(event); } } diff --git a/tests/fsevent.rs b/tests/fsevent.rs index 959e469..e143f73 100644 --- a/tests/fsevent.rs +++ b/tests/fsevent.rs @@ -1,19 +1,19 @@ -#![cfg(target_os="macos")] +#![cfg(target_os = "macos")] -use fsevent_sys::core_foundation as cf; +use core_foundation::runloop::{CFRunLoopGetCurrent, CFRunLoopRef, CFRunLoopStop}; use fsevent::*; -use std::fs; -use std::fs::read_link; -use std::fs::OpenOptions; -use std::io::Write; -use std::path::{Component, PathBuf}; -use std::thread; -use std::time::{Duration, SystemTime}; - -use std::sync::mpsc::{channel, Receiver}; +use std::{ + fs, + fs::{read_link, OpenOptions}, + io::Write, + path::{Component, PathBuf}, + sync::mpsc::{channel, Receiver}, + thread, + time::{Duration, SystemTime}, +}; // Helper to send the runloop from an observer thread. -struct CFRunLoopSendWrapper(cf::CFRunLoopRef); +struct CFRunLoopSendWrapper(CFRunLoopRef); // Safety: According to the Apple documentation, it is safe to send CFRef types across threads. // @@ -128,7 +128,7 @@ fn internal_observe_folder(run_async: bool) { } else { let (tx, rx) = std::sync::mpsc::channel(); let observe_thread = thread::spawn(move || { - let runloop = unsafe { cf::CFRunLoopGetCurrent() }; + let runloop = unsafe { CFRunLoopGetCurrent() }; tx.send(CFRunLoopSendWrapper(runloop)).unwrap(); let mut fsevent = fsevent::FsEvent::new(vec![]); @@ -168,7 +168,9 @@ fn internal_observe_folder(run_async: bool) { ); if let Some((runloop, thread)) = runloop_and_thread { - unsafe { cf::CFRunLoopStop(runloop); } + unsafe { + CFRunLoopStop(runloop); + } thread.join().unwrap(); } else { @@ -217,7 +219,7 @@ fn internal_validate_watch_single_file(run_async: bool) { // Leak the thread. let observe_thread = thread::spawn(move || { - let runloop = unsafe { cf::CFRunLoopGetCurrent() }; + let runloop = unsafe { CFRunLoopGetCurrent() }; tx.send(CFRunLoopSendWrapper(runloop)).unwrap(); let mut fsevent = fsevent::FsEvent::new(vec![]); @@ -256,7 +258,9 @@ fn internal_validate_watch_single_file(run_async: bool) { ); if let Some((runloop, observe_thread)) = runloop_and_thread { - unsafe { cf::CFRunLoopStop(runloop); } + unsafe { + CFRunLoopStop(runloop); + } observe_thread.join().unwrap(); } else {