summaryrefslogtreecommitdiffstats
path: root/vendor/core-foundation/src/filedescriptor.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/core-foundation/src/filedescriptor.rs')
-rw-r--r--vendor/core-foundation/src/filedescriptor.rs194
1 files changed, 194 insertions, 0 deletions
diff --git a/vendor/core-foundation/src/filedescriptor.rs b/vendor/core-foundation/src/filedescriptor.rs
new file mode 100644
index 000000000..e153c70b2
--- /dev/null
+++ b/vendor/core-foundation/src/filedescriptor.rs
@@ -0,0 +1,194 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub use core_foundation_sys::filedescriptor::*;
+
+use core_foundation_sys::base::{Boolean, CFIndex};
+use core_foundation_sys::base::{kCFAllocatorDefault, CFOptionFlags};
+
+use base::TCFType;
+use runloop::CFRunLoopSource;
+
+use std::mem::MaybeUninit;
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::ptr;
+
+declare_TCFType!{
+ CFFileDescriptor, CFFileDescriptorRef
+}
+impl_TCFType!(CFFileDescriptor, CFFileDescriptorRef, CFFileDescriptorGetTypeID);
+
+impl CFFileDescriptor {
+ pub fn new(fd: RawFd,
+ closeOnInvalidate: bool,
+ callout: CFFileDescriptorCallBack,
+ context: Option<&CFFileDescriptorContext>) -> Option<CFFileDescriptor> {
+ let context = context.map_or(ptr::null(), |c| c as *const _);
+ unsafe {
+ let fd_ref = CFFileDescriptorCreate(kCFAllocatorDefault,
+ fd,
+ closeOnInvalidate as Boolean,
+ callout,
+ context);
+ if fd_ref.is_null() {
+ None
+ } else {
+ Some(TCFType::wrap_under_create_rule(fd_ref))
+ }
+ }
+ }
+
+ pub fn context(&self) -> CFFileDescriptorContext {
+ unsafe {
+ let mut context = MaybeUninit::<CFFileDescriptorContext>::uninit();
+ CFFileDescriptorGetContext(self.0, context.as_mut_ptr());
+ context.assume_init()
+ }
+ }
+
+ pub fn enable_callbacks(&self, callback_types: CFOptionFlags) {
+ unsafe {
+ CFFileDescriptorEnableCallBacks(self.0, callback_types)
+ }
+ }
+
+ pub fn disable_callbacks(&self, callback_types: CFOptionFlags) {
+ unsafe {
+ CFFileDescriptorDisableCallBacks(self.0, callback_types)
+ }
+ }
+
+ pub fn valid(&self) -> bool {
+ unsafe {
+ CFFileDescriptorIsValid(self.0) != 0
+ }
+ }
+
+ pub fn invalidate(&self) {
+ unsafe {
+ CFFileDescriptorInvalidate(self.0)
+ }
+ }
+
+ pub fn to_run_loop_source(&self, order: CFIndex) -> Option<CFRunLoopSource> {
+ unsafe {
+ let source_ref = CFFileDescriptorCreateRunLoopSource(
+ kCFAllocatorDefault,
+ self.0,
+ order
+ );
+ if source_ref.is_null() {
+ None
+ } else {
+ Some(TCFType::wrap_under_create_rule(source_ref))
+ }
+ }
+ }
+}
+
+impl AsRawFd for CFFileDescriptor {
+ fn as_raw_fd(&self) -> RawFd {
+ unsafe {
+ CFFileDescriptorGetNativeDescriptor(self.0)
+ }
+ }
+}
+
+
+#[cfg(test)]
+mod test {
+ extern crate libc;
+
+ use super::*;
+ use std::ffi::CString;
+ use std::os::raw::c_void;
+ use core_foundation_sys::base::{CFOptionFlags};
+ use core_foundation_sys::runloop::{kCFRunLoopDefaultMode};
+ use libc::O_RDWR;
+ use runloop::{CFRunLoop};
+
+ #[test]
+ fn test_unconsumed() {
+ let path = CString::new("/dev/null").unwrap();
+ let raw_fd = unsafe { libc::open(path.as_ptr(), O_RDWR, 0) };
+ let cf_fd = CFFileDescriptor::new(raw_fd, false, never_callback, None);
+ assert!(cf_fd.is_some());
+ let cf_fd = cf_fd.unwrap();
+
+ assert!(cf_fd.valid());
+ cf_fd.invalidate();
+ assert!(!cf_fd.valid());
+
+ // close() should succeed
+ assert_eq!(unsafe { libc::close(raw_fd) }, 0);
+ }
+
+ extern "C" fn never_callback(_f: CFFileDescriptorRef,
+ _callback_types: CFOptionFlags,
+ _info_ptr: *mut c_void) {
+ unreachable!();
+ }
+
+ struct TestInfo {
+ value: CFOptionFlags
+ }
+
+ #[test]
+ fn test_callback() {
+ let mut info = TestInfo { value: 0 };
+ let context = CFFileDescriptorContext {
+ version: 0,
+ info: &mut info as *mut _ as *mut c_void,
+ retain: None,
+ release: None,
+ copyDescription: None
+ };
+
+ let path = CString::new("/dev/null").unwrap();
+ let raw_fd = unsafe { libc::open(path.as_ptr(), O_RDWR, 0) };
+ let cf_fd = CFFileDescriptor::new(raw_fd, true, callback, Some(&context));
+ assert!(cf_fd.is_some());
+ let cf_fd = cf_fd.unwrap();
+
+ assert!(cf_fd.valid());
+
+ let run_loop = CFRunLoop::get_current();
+ let source = CFRunLoopSource::from_file_descriptor(&cf_fd, 0);
+ assert!(source.is_some());
+ unsafe {
+ run_loop.add_source(&source.unwrap(), kCFRunLoopDefaultMode);
+ }
+
+ info.value = 0;
+ cf_fd.enable_callbacks(kCFFileDescriptorReadCallBack);
+ CFRunLoop::run_current();
+ assert_eq!(info.value, kCFFileDescriptorReadCallBack);
+
+ info.value = 0;
+ cf_fd.enable_callbacks(kCFFileDescriptorWriteCallBack);
+ CFRunLoop::run_current();
+ assert_eq!(info.value, kCFFileDescriptorWriteCallBack);
+
+ info.value = 0;
+ cf_fd.disable_callbacks(kCFFileDescriptorReadCallBack | kCFFileDescriptorWriteCallBack);
+
+ cf_fd.invalidate();
+ assert!(!cf_fd.valid());
+ }
+
+ extern "C" fn callback(_f: CFFileDescriptorRef, callback_types: CFOptionFlags, info_ptr: *mut c_void) {
+ assert!(!info_ptr.is_null());
+
+ let info: *mut TestInfo = info_ptr as *mut TestInfo;
+
+ unsafe { (*info).value = callback_types };
+
+ CFRunLoop::get_current().stop();
+ }
+}