/*! Assorted helpers */ use std::collections::HashMap; use std::iter::FromIterator; pub mod c { use super::*; use std::cell::RefCell; use std::ffi::{ CStr, CString }; use std::os::raw::c_char; use std::rc::Rc; use std::str::Utf8Error; // traits use std::borrow::ToOwned; pub fn as_str(s: &*const c_char) -> Result, Utf8Error> { if s.is_null() { Ok(None) } else { unsafe {CStr::from_ptr(*s)} .to_str() .map(Some) } } pub fn as_cstr(s: &*const c_char) -> Option<&CStr> { if s.is_null() { None } else { Some(unsafe {CStr::from_ptr(*s)}) } } pub fn into_cstring(s: *const c_char) -> Result, std::ffi::NulError> { if s.is_null() { Ok(None) } else { CString::new( unsafe {CStr::from_ptr(s)}.to_bytes() ).map(Some) } } #[cfg(test)] mod tests { use super::*; use std::ptr; #[test] fn test_null_cstring() { assert_eq!(into_cstring(ptr::null()), Ok(None)) } #[test] fn test_null_str() { assert_eq!(as_str(&ptr::null()), Ok(None)) } } /// Wraps structures to pass them safely to/from C /// Since C doesn't respect borrowing rules, /// RefCell will enforce them dynamically (only 1 writer/many readers) /// Rc is implied and will ensure timely dropping #[repr(transparent)] pub struct Wrapped(*const RefCell); // It would be nice to implement `Borrow` // directly on the raw pointer to avoid one conversion call, // but the `borrow()` call needs to extract a `Rc`, // and at the same time return a reference to it (`std::cell::Ref`) // to take advantage of `Rc::borrow()` runtime checks. // Unfortunately, that needs a `Ref` struct with self-referential fields, // which is a bit too complex for now. impl Wrapped { pub fn wrap(state: Rc>) -> Wrapped { Wrapped(Rc::into_raw(state)) } /// Extracts the reference to the data. /// It may cause problems if attempted in more than one place pub unsafe fn unwrap(self) -> Rc> { Rc::from_raw(self.0) } /// Creates a new Rc reference to the same data pub fn clone_ref(&self) -> Rc> { // A bit dangerous: the Rc may be in use elsewhere let used_rc = unsafe { Rc::from_raw(self.0) }; let rc = used_rc.clone(); Rc::into_raw(used_rc); // prevent dropping the original reference rc } } impl Clone for Wrapped { fn clone(&self) -> Wrapped { Wrapped::wrap(self.clone_ref()) } } /// ToOwned won't work here /// because it's really difficult to implement Borrow on Wrapped /// with the Rc> chain on the way to the data impl CloneOwned for Wrapped { type Owned = T; fn clone_owned(&self) -> T { let rc = self.clone_ref(); let r = rc.borrow(); r.to_owned() } } } pub trait CloneOwned { type Owned; fn clone_owned(&self) -> Self::Owned; } pub fn hash_map_map(map: HashMap, mut f: F) -> HashMap where F: FnMut(K, V) -> (K1, V1), K1: std::cmp::Eq + std::hash::Hash { HashMap::from_iter( map.into_iter().map(|(key, value)| f(key, value)) ) }