ffi: Use a generic wrapper for opaque Rust structs
This commit is contained in:
104
src/keyboard.rs
104
src/keyboard.rs
@ -5,6 +5,7 @@ use super::symbol;
|
||||
/// Gathers stuff defined in C or called by C
|
||||
pub mod c {
|
||||
use super::*;
|
||||
use ::util::c;
|
||||
use ::util::c::{ as_cstr, into_cstring };
|
||||
|
||||
use std::cell::RefCell;
|
||||
@ -13,10 +14,6 @@ pub mod c {
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
|
||||
// traits
|
||||
|
||||
use std::borrow::ToOwned;
|
||||
|
||||
|
||||
// The following defined in C
|
||||
#[no_mangle]
|
||||
@ -24,44 +21,7 @@ pub mod c {
|
||||
fn eek_keysym_from_name(name: *const c_char) -> u32;
|
||||
}
|
||||
|
||||
/// 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
|
||||
|
||||
@ -84,7 +44,7 @@ pub mod c {
|
||||
#[no_mangle]
|
||||
pub extern "C"
|
||||
fn squeek_key_free(key: CKeyState) {
|
||||
key.unwrap(); // reference dropped
|
||||
unsafe { key.unwrap() }; // reference dropped
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -97,7 +57,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]
|
||||
@ -109,7 +71,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]
|
||||
@ -121,7 +85,9 @@ pub mod c {
|
||||
#[no_mangle]
|
||||
pub extern "C"
|
||||
fn squeek_key_set_keycode(key: CKeyState, code: u32) {
|
||||
key.borrow_mut(|key| key.keycode = code);
|
||||
let key = key.clone_ref();
|
||||
let mut key = key.borrow_mut();
|
||||
key.keycode = code;
|
||||
}
|
||||
|
||||
// TODO: this will receive data from the filesystem,
|
||||
@ -180,38 +146,38 @@ pub mod c {
|
||||
None
|
||||
});
|
||||
|
||||
let key = key.clone_ref();
|
||||
let mut key = key.borrow_mut();
|
||||
|
||||
key.borrow_mut(|key| {
|
||||
if let Some(_) = key.symbol {
|
||||
eprintln!("Key {:?} already has a symbol defined", text);
|
||||
return;
|
||||
}
|
||||
if let Some(_) = key.symbol {
|
||||
eprintln!("Key {:?} already has a symbol defined", text);
|
||||
return;
|
||||
}
|
||||
|
||||
key.symbol = Some(match element.to_bytes() {
|
||||
b"symbol" => Symbol {
|
||||
action: Action::Submit {
|
||||
text: text,
|
||||
keys: Vec::new(),
|
||||
},
|
||||
label: label,
|
||||
tooltip: tooltip,
|
||||
key.symbol = Some(match element.to_bytes() {
|
||||
b"symbol" => Symbol {
|
||||
action: Action::Submit {
|
||||
text: text,
|
||||
keys: Vec::new(),
|
||||
},
|
||||
_ => panic!("unsupported element type {:?}", element),
|
||||
});
|
||||
label: label,
|
||||
tooltip: tooltip,
|
||||
},
|
||||
_ => panic!("unsupported element type {:?}", element),
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C"
|
||||
fn squeek_key_get_symbol(key: CKeyState) -> *const symbol::Symbol {
|
||||
key.borrow_mut(|key| {
|
||||
match key.symbol {
|
||||
// This pointer stays after the function exits,
|
||||
// so it must reference borrowed data and not any copy
|
||||
Some(ref symbol) => symbol as *const symbol::Symbol,
|
||||
None => ptr::null(),
|
||||
}
|
||||
})
|
||||
let key = key.clone_ref();
|
||||
let key = key.borrow();
|
||||
match key.symbol {
|
||||
// This pointer stays after the function exits,
|
||||
// so it must reference borrowed data and not any copy
|
||||
Some(ref symbol) => symbol as *const symbol::Symbol,
|
||||
None => ptr::null(),
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
||||
Reference in New Issue
Block a user