Skip to content

Commit 7cc525c

Browse files
authored
Merge pull request #48 from madsmtm/objc2
Use `objc2-core-foundation` and `objc2-core-services`
2 parents 2922423 + 6f97921 commit 7cc525c

File tree

4 files changed

+109
-89
lines changed

4 files changed

+109
-89
lines changed

Cargo.toml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,25 @@
22

33
name = "fsevent"
44
version = "2.2.0"
5-
authors = [ "Pierre Baillet <[email protected]>" ]
5+
authors = ["Pierre Baillet <[email protected]>"]
66
description = "Rust bindings to the fsevent-sys macOS API for file changes notifications"
77
license = "MIT"
88
repository = "https://github.com/octplane/fsevent-rust"
99
edition = "2018"
1010

1111
[dependencies]
1212
bitflags = "1"
13-
fsevent-sys = "5.1.0"
14-
# fsevent-sys = { path = "fsevent-sys" }
15-
core-foundation = "0.10.1"
13+
objc2-core-foundation = { version = "0.3.2", default-features = false, features = [
14+
"std",
15+
"CFString",
16+
"CFRunLoop",
17+
"CFArray",
18+
"CFDate",
19+
] }
20+
objc2-core-services = { version = "0.3.2", default-features = false, features = [
21+
"std",
22+
"FSEvents",
23+
] }
1624

1725
[dev-dependencies]
1826
tempfile = "3"

fsevent-sys/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![cfg(target_os = "macos")]
2+
#![deprecated = "deprecated in favour of the `objc2-core-services` crate"]
23

34
mod fsevent;
45
pub use fsevent::*;

src/lib.rs

Lines changed: 90 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,41 @@
77
)]
88

99
use bitflags::bitflags;
10-
use core_foundation::{
11-
array::CFArray,
12-
base::{kCFAllocatorDefault, TCFType},
13-
date::CFTimeInterval,
14-
runloop::{
15-
kCFRunLoopDefaultMode, CFRunLoopGetCurrent, CFRunLoopRef, CFRunLoopRun, CFRunLoopStop,
16-
},
17-
string::CFString,
10+
use objc2_core_foundation::{
11+
kCFAllocatorDefault, kCFRunLoopDefaultMode, CFArray, CFRetained, CFRunLoop, CFString,
12+
CFTimeInterval,
13+
};
14+
#[allow(deprecated)]
15+
use objc2_core_services::FSEventStreamScheduleWithRunLoop;
16+
use objc2_core_services::{
17+
kFSEventStreamCreateFlagFileEvents, kFSEventStreamCreateFlagNoDefer,
18+
kFSEventStreamEventFlagEventIdsWrapped, kFSEventStreamEventFlagHistoryDone,
19+
kFSEventStreamEventFlagItemChangeOwner, kFSEventStreamEventFlagItemCloned,
20+
kFSEventStreamEventFlagItemCreated, kFSEventStreamEventFlagItemFinderInfoMod,
21+
kFSEventStreamEventFlagItemInodeMetaMod, kFSEventStreamEventFlagItemIsDir,
22+
kFSEventStreamEventFlagItemIsFile, kFSEventStreamEventFlagItemIsHardlink,
23+
kFSEventStreamEventFlagItemIsLastHardlink, kFSEventStreamEventFlagItemIsSymlink,
24+
kFSEventStreamEventFlagItemModified, kFSEventStreamEventFlagItemRemoved,
25+
kFSEventStreamEventFlagItemRenamed, kFSEventStreamEventFlagItemXattrMod,
26+
kFSEventStreamEventFlagKernelDropped, kFSEventStreamEventFlagMount,
27+
kFSEventStreamEventFlagMustScanSubDirs, kFSEventStreamEventFlagNone,
28+
kFSEventStreamEventFlagOwnEvent, kFSEventStreamEventFlagRootChanged,
29+
kFSEventStreamEventFlagUnmount, kFSEventStreamEventFlagUserDropped,
30+
kFSEventStreamEventIdSinceNow, ConstFSEventStreamRef, FSEventStreamContext,
31+
FSEventStreamCreate, FSEventStreamCreateFlags, FSEventStreamEventFlags, FSEventStreamEventId,
32+
FSEventStreamFlushSync, FSEventStreamStart, FSEventStreamStop,
1833
};
19-
use fsevent_sys as fs;
2034
use std::{
2135
ffi::CStr,
2236
fmt::{Display, Formatter},
2337
os::raw::c_void,
38+
ptr::NonNull,
2439
slice,
2540
sync::mpsc::Sender,
2641
};
2742

2843
// Helper to send the runloop from an observer thread.
29-
struct CFRunLoopSendWrapper(CFRunLoopRef);
44+
struct CFRunLoopSendWrapper(CFRetained<CFRunLoop>);
3045

3146
// Safety: According to the Apple documentation, it is safe to send CFRef types across threads.
3247
//
@@ -35,10 +50,10 @@ unsafe impl Send for CFRunLoopSendWrapper {}
3550

3651
pub struct FsEvent {
3752
paths: Vec<String>,
38-
since_when: fs::FSEventStreamEventId,
53+
since_when: FSEventStreamEventId,
3954
latency: CFTimeInterval,
40-
flags: fs::FSEventStreamCreateFlags,
41-
runloop: Option<CFRunLoopRef>,
55+
flags: FSEventStreamCreateFlags,
56+
runloop: Option<CFRetained<CFRunLoop>>,
4257
}
4358

4459
#[derive(Debug)]
@@ -53,30 +68,30 @@ pub struct Event {
5368
bitflags! {
5469
#[repr(C)]
5570
pub struct StreamFlags: u32 {
56-
const NONE = 0x00000000;
57-
const MUST_SCAN_SUBDIRS = 0x00000001;
58-
const USER_DROPPED = 0x00000002;
59-
const KERNEL_DROPPED = 0x00000004;
60-
const IDS_WRAPPED = 0x00000008;
61-
const HISTORY_DONE = 0x00000010;
62-
const ROOT_CHANGED = 0x00000020;
63-
const MOUNT = 0x00000040;
64-
const UNMOUNT = 0x00000080;
65-
const ITEM_CREATED = 0x00000100;
66-
const ITEM_REMOVED = 0x00000200;
67-
const INODE_META_MOD = 0x00000400;
68-
const ITEM_RENAMED = 0x00000800;
69-
const ITEM_MODIFIED = 0x00001000;
70-
const FINDER_INFO_MOD = 0x00002000;
71-
const ITEM_CHANGE_OWNER = 0x00004000;
72-
const ITEM_XATTR_MOD = 0x00008000;
73-
const IS_FILE = 0x00010000;
74-
const IS_DIR = 0x00020000;
75-
const IS_SYMLINK = 0x00040000;
76-
const OWN_EVENT = 0x00080000;
77-
const IS_HARDLINK = 0x00100000;
78-
const IS_LAST_HARDLINK = 0x00200000;
79-
const ITEM_CLONED = 0x400000;
71+
const NONE = kFSEventStreamEventFlagNone;
72+
const MUST_SCAN_SUBDIRS = kFSEventStreamEventFlagMustScanSubDirs;
73+
const USER_DROPPED = kFSEventStreamEventFlagUserDropped;
74+
const KERNEL_DROPPED = kFSEventStreamEventFlagKernelDropped;
75+
const IDS_WRAPPED = kFSEventStreamEventFlagEventIdsWrapped;
76+
const HISTORY_DONE = kFSEventStreamEventFlagHistoryDone;
77+
const ROOT_CHANGED = kFSEventStreamEventFlagRootChanged;
78+
const MOUNT = kFSEventStreamEventFlagMount;
79+
const UNMOUNT = kFSEventStreamEventFlagUnmount;
80+
const ITEM_CREATED = kFSEventStreamEventFlagItemCreated;
81+
const ITEM_REMOVED = kFSEventStreamEventFlagItemRemoved;
82+
const INODE_META_MOD = kFSEventStreamEventFlagItemInodeMetaMod;
83+
const ITEM_RENAMED = kFSEventStreamEventFlagItemRenamed;
84+
const ITEM_MODIFIED = kFSEventStreamEventFlagItemModified;
85+
const FINDER_INFO_MOD = kFSEventStreamEventFlagItemFinderInfoMod;
86+
const ITEM_CHANGE_OWNER = kFSEventStreamEventFlagItemChangeOwner;
87+
const ITEM_XATTR_MOD = kFSEventStreamEventFlagItemXattrMod;
88+
const IS_FILE = kFSEventStreamEventFlagItemIsFile;
89+
const IS_DIR = kFSEventStreamEventFlagItemIsDir;
90+
const IS_SYMLINK = kFSEventStreamEventFlagItemIsSymlink;
91+
const OWN_EVENT = kFSEventStreamEventFlagOwnEvent;
92+
const IS_HARDLINK = kFSEventStreamEventFlagItemIsHardlink;
93+
const IS_LAST_HARDLINK = kFSEventStreamEventFlagItemIsLastHardlink;
94+
const ITEM_CLONED = kFSEventStreamEventFlagItemCloned;
8095
}
8196
}
8297

@@ -155,14 +170,14 @@ impl Display for StreamFlags {
155170
}
156171
}
157172

158-
fn default_stream_context(event_sender: *const Sender<Event>) -> fs::FSEventStreamContext {
173+
fn default_stream_context(event_sender: *const Sender<Event>) -> FSEventStreamContext {
159174
let ptr = event_sender as *mut c_void;
160-
fs::FSEventStreamContext {
175+
FSEventStreamContext {
161176
version: 0,
162177
info: ptr,
163178
retain: None,
164179
release: None,
165-
copy_description: None,
180+
copyDescription: None,
166181
}
167182
}
168183

@@ -189,9 +204,9 @@ impl FsEvent {
189204
pub fn new(paths: Vec<String>) -> Self {
190205
Self {
191206
paths,
192-
since_when: fs::kFSEventStreamEventIdSinceNow,
207+
since_when: kFSEventStreamEventIdSinceNow,
193208
latency: 0.0,
194-
flags: fs::kFSEventStreamCreateFlagFileEvents | fs::kFSEventStreamCreateFlagNoDefer,
209+
flags: kFSEventStreamCreateFlagFileEvents | kFSEventStreamCreateFlagNoDefer,
195210
runloop: None,
196211
}
197212
}
@@ -202,48 +217,49 @@ impl FsEvent {
202217
Ok(())
203218
}
204219

205-
fn build_native_paths(&self) -> CFArray<CFString> {
206-
let paths: Vec<_> = self.paths.iter().map(|x| CFString::new(x)).collect();
207-
CFArray::from_CFTypes(&paths)
220+
fn build_native_paths(&self) -> CFRetained<CFArray<CFString>> {
221+
let paths: Vec<_> = self.paths.iter().map(|x| CFString::from_str(x)).collect();
222+
CFArray::from_retained_objects(&paths)
208223
}
209224

210225
fn internal_observe(
211-
since_when: fs::FSEventStreamEventId,
226+
since_when: FSEventStreamEventId,
212227
latency: CFTimeInterval,
213-
flags: fs::FSEventStreamCreateFlags,
214-
paths: CFArray<CFString>,
228+
flags: FSEventStreamCreateFlags,
229+
paths: &CFArray<CFString>,
215230
event_sender: Sender<Event>,
216231
runloop_sender: Option<Sender<CFRunLoopSendWrapper>>,
217232
) -> Result<()> {
218233
let stream_context = default_stream_context(&event_sender);
219234

220235
unsafe {
221-
let stream = fs::FSEventStreamCreate(
236+
let stream = FSEventStreamCreate(
222237
kCFAllocatorDefault,
223-
callback,
224-
&stream_context,
225-
paths.as_concrete_TypeRef() as _,
238+
Some(callback),
239+
&stream_context as *const _ as *mut _,
240+
paths.as_opaque(),
226241
since_when,
227242
latency,
228243
flags,
229244
);
230245

231246
if let Some(ret_tx) = runloop_sender {
232-
let runloop = CFRunLoopSendWrapper(CFRunLoopGetCurrent());
247+
let runloop = CFRunLoopSendWrapper(CFRunLoop::current().unwrap());
233248
ret_tx.send(runloop).expect("unabe to send CFRunLoopRef");
234249
}
235250

236-
fs::FSEventStreamScheduleWithRunLoop(
251+
#[allow(deprecated)]
252+
FSEventStreamScheduleWithRunLoop(
237253
stream,
238-
CFRunLoopGetCurrent(),
239-
kCFRunLoopDefaultMode,
254+
&CFRunLoop::current().unwrap(),
255+
kCFRunLoopDefaultMode.unwrap(),
240256
);
241257

242-
fs::FSEventStreamStart(stream);
243-
CFRunLoopRun();
258+
FSEventStreamStart(stream);
259+
CFRunLoop::run();
244260

245-
fs::FSEventStreamFlushSync(stream);
246-
fs::FSEventStreamStop(stream);
261+
FSEventStreamFlushSync(stream);
262+
FSEventStreamStop(stream);
247263
}
248264

249265
Ok(())
@@ -255,7 +271,7 @@ impl FsEvent {
255271
self.since_when,
256272
self.latency,
257273
self.flags,
258-
native_paths,
274+
&native_paths,
259275
event_sender,
260276
None,
261277
)
@@ -266,7 +282,7 @@ impl FsEvent {
266282
let (ret_tx, ret_rx) = std::sync::mpsc::channel();
267283
let native_paths = self.build_native_paths();
268284

269-
struct CFMutableArraySendWrapper(CFArray<CFString>);
285+
struct CFMutableArraySendWrapper(CFRetained<CFArray<CFString>>);
270286

271287
// Safety
272288
// - See comment on `CFRunLoopSendWrapper
@@ -282,7 +298,7 @@ impl FsEvent {
282298
since_when,
283299
latency,
284300
flags,
285-
paths.0,
301+
&paths.0,
286302
event_sender,
287303
Some(ret_tx),
288304
)
@@ -296,24 +312,23 @@ impl FsEvent {
296312
// Shut down the event stream.
297313
pub fn shutdown_observe(&mut self) {
298314
if let Some(runloop) = self.runloop.take() {
299-
unsafe {
300-
CFRunLoopStop(runloop);
301-
}
315+
runloop.stop();
302316
}
303317
}
304318
}
305319

306-
extern "C" fn callback(
307-
_stream_ref: fs::FSEventStreamRef,
320+
unsafe extern "C-unwind" fn callback(
321+
_stream_ref: ConstFSEventStreamRef,
308322
info: *mut c_void,
309-
num_events: usize, // size_t numEvents
310-
event_paths: *mut c_void, // void *eventPaths
311-
event_flags: *const fs::FSEventStreamEventFlags, // const FSEventStreamEventFlags eventFlags[]
312-
event_ids: *const fs::FSEventStreamEventId, // const FSEventStreamEventId eventIds[]
323+
num_events: usize, // size_t numEvents
324+
event_paths: NonNull<c_void>, // void *eventPaths
325+
event_flags: NonNull<FSEventStreamEventFlags>, // const FSEventStreamEventFlags eventFlags[]
326+
event_ids: NonNull<FSEventStreamEventId>, // const FSEventStreamEventId eventIds[]
313327
) {
314-
let event_paths = unsafe { slice::from_raw_parts(event_paths as *const *const i8, num_events) };
315-
let event_flags = unsafe { slice::from_raw_parts(event_flags, num_events) };
316-
let event_ids = unsafe { slice::from_raw_parts(event_ids, num_events) };
328+
let event_paths =
329+
unsafe { slice::from_raw_parts(event_paths.as_ptr() as *const *const i8, num_events) };
330+
let event_flags = unsafe { slice::from_raw_parts(event_flags.as_ptr(), num_events) };
331+
let event_ids = unsafe { slice::from_raw_parts(event_ids.as_ptr(), num_events) };
317332
let sender = unsafe {
318333
(info as *mut Sender<Event>)
319334
.as_mut()

tests/fsevent.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#![cfg(target_os = "macos")]
22

3-
use core_foundation::runloop::{CFRunLoopGetCurrent, CFRunLoopRef, CFRunLoopStop};
43
use fsevent::*;
4+
use objc2_core_foundation::{CFRetained, CFRunLoop};
55
use std::{
66
fs,
77
fs::{read_link, OpenOptions},
@@ -13,7 +13,7 @@ use std::{
1313
};
1414

1515
// Helper to send the runloop from an observer thread.
16-
struct CFRunLoopSendWrapper(CFRunLoopRef);
16+
struct CFRunLoopSendWrapper(CFRetained<CFRunLoop>);
1717

1818
// Safety: According to the Apple documentation, it is safe to send CFRef types across threads.
1919
//
@@ -121,7 +121,7 @@ fn internal_observe_folder(run_async: bool) {
121121
let (tx, rx) = std::sync::mpsc::channel();
122122
let dst_clone = dst.clone();
123123
let observe_thread = thread::spawn(move || {
124-
let runloop = unsafe { CFRunLoopGetCurrent() };
124+
let runloop = CFRunLoop::current().unwrap();
125125
tx.send(CFRunLoopSendWrapper(runloop)).unwrap();
126126

127127
let mut fsevent = fsevent::FsEvent::new(vec![]);
@@ -163,9 +163,7 @@ fn internal_observe_folder(run_async: bool) {
163163
);
164164

165165
if let Some((runloop, thread)) = runloop_and_thread {
166-
unsafe {
167-
CFRunLoopStop(runloop);
168-
}
166+
runloop.stop();
169167

170168
thread.join().unwrap();
171169
} else {
@@ -204,7 +202,7 @@ fn internal_validate_watch_single_file(run_async: bool) {
204202
let dir_path_clone = dir_path.clone();
205203

206204
let observe_thread = thread::spawn(move || {
207-
let runloop = unsafe { CFRunLoopGetCurrent() };
205+
let runloop = CFRunLoop::current().unwrap();
208206
tx.send(CFRunLoopSendWrapper(runloop)).unwrap();
209207

210208
let mut fsevent = fsevent::FsEvent::new(vec![]);
@@ -257,9 +255,7 @@ fn internal_validate_watch_single_file(run_async: bool) {
257255
);
258256

259257
if let Some((runloop, observe_thread)) = runloop_and_thread {
260-
unsafe {
261-
CFRunLoopStop(runloop);
262-
}
258+
runloop.stop();
263259

264260
observe_thread.join().unwrap();
265261
} else {

0 commit comments

Comments
 (0)