Merge branch 'wrapping' into reparse

This commit is contained in:
Dorota Czaplejewicz
2019-09-04 10:00:49 +00:00
3 changed files with 68 additions and 53 deletions

View File

@ -15,59 +15,20 @@ use std::iter::{ FromIterator, IntoIterator };
/// Gathers stuff defined in C or called by C
pub mod c {
use super::*;
use ::util::c;
use ::util::c::as_cstr;
use std::ffi::CString;
use std::os::raw::c_char;
// traits
use std::borrow::ToOwned;
/// The wrapped structure for KeyState suitable for handling in 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 CKeyState(*const RefCell<KeyState>);
impl Clone for CKeyState {
fn clone(&self) -> Self {
CKeyState(self.0.clone())
}
}
impl CKeyState {
pub fn wrap(state: Rc<RefCell<KeyState>>) -> CKeyState {
CKeyState(Rc::into_raw(state))
}
pub fn unwrap(self) -> Rc<RefCell<KeyState>> {
unsafe { Rc::from_raw(self.0) }
}
fn to_owned(self) -> KeyState {
let rc = self.unwrap();
let state = rc.borrow().to_owned();
Rc::into_raw(rc); // Prevent dropping
state
}
fn borrow_mut<F, T>(self, f: F) -> T where F: FnOnce(&mut KeyState) -> T {
let rc = self.unwrap();
let ret = {
let mut state = rc.borrow_mut();
f(&mut state)
};
Rc::into_raw(rc); // Prevent dropping
ret
}
}
// TODO: unwrapping
pub type CKeyState = c::Wrapped<KeyState>;
// The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
#[no_mangle]
pub extern "C"
fn squeek_key_free(key: CKeyState) {
key.unwrap(); // reference dropped
unsafe { key.unwrap() }; // reference dropped
}
#[no_mangle]
@ -80,7 +41,9 @@ pub mod c {
#[no_mangle]
pub extern "C"
fn squeek_key_set_pressed(key: CKeyState, pressed: u32) {
key.borrow_mut(|key| key.pressed = pressed != 0);
let key = key.clone_ref();
let mut key = key.borrow_mut();
key.pressed = pressed != 0;
}
#[no_mangle]
@ -92,7 +55,9 @@ pub mod c {
#[no_mangle]
pub extern "C"
fn squeek_key_set_locked(key: CKeyState, locked: u32) {
key.borrow_mut(|key| key.locked = locked != 0);
let key = key.clone_ref();
let mut key = key.borrow_mut();
key.locked = locked != 0;
}
#[no_mangle]
@ -116,10 +81,10 @@ pub mod c {
Action::Submit { text: Some(text), .. } => {
Some(
text.clone()
.into_string().expect("Bad symbol text")
.into_string().expect("Bad symbol")
)
},
_ => None
_ => None,
};
let inner = match symbol_name {

View File

@ -194,9 +194,8 @@ pub mod c {
state: ::keyboard::c::CKeyState,
) -> u32 {
let button = unsafe { &*button };
let state = state.unwrap();
let state = state.clone_ref();
let equal = Rc::ptr_eq(&button.state, &state);
Rc::into_raw(state); // Prevent dropping
equal as u32
}
@ -333,13 +332,10 @@ pub mod c {
needle: ::keyboard::c::CKeyState,
) -> ButtonPlace {
let view = unsafe { &*view };
let state = needle.unwrap();
let state = needle.clone_ref();
let paths = ::layout::procedures::find_key_paths(view, &state);
// Iterators used up, can turn the reference back into pointer
Rc::into_raw(state);
// Can only return 1 entry back to C
let (row, button) = match paths.get(0) {
Some((row, button)) => (

View File

@ -1,7 +1,13 @@
pub mod c {
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<Option<&str>, Utf8Error> {
if s.is_null() {
@ -46,4 +52,52 @@ pub mod c {
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<T: Clone>(*const RefCell<T>);
// 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<RefCell>::borrow()` runtime checks.
// Unfortunately, that needs a `Ref` struct with self-referential fields,
// which is a bit too complex for now.
impl<T: Clone> Wrapped<T> {
pub fn wrap(state: Rc<RefCell<T>>) -> Wrapped<T> {
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<RefCell<T>> {
Rc::from_raw(self.0)
}
/// Creates a new Rc reference to the same data
pub fn clone_ref(&self) -> Rc<RefCell<T>> {
// 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
}
/// Create a copy of the underlying data
pub fn to_owned(&self) -> T {
let rc = self.clone_ref();
let r = rc.borrow();
r.to_owned()
}
}
impl<T: Clone> Clone for Wrapped<T> {
fn clone(&self) -> Wrapped<T> {
Wrapped::wrap(self.clone_ref())
}
}
}