From b70afbe9eb30a347f50fadff23c5f2aaea33e1e5 Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Wed, 14 Aug 2019 11:06:24 +0000 Subject: [PATCH] keystate: Wrap in refconuter --- src/keyboard.rs | 134 ++++++++++++++++++++++++++++++------------------ src/symbol.rs | 12 ++--- 2 files changed, 89 insertions(+), 57 deletions(-) diff --git a/src/keyboard.rs b/src/keyboard.rs index dd7de03c..7aec925b 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -7,9 +7,16 @@ pub mod c { use super::*; use ::util::c::{ as_cstr, into_cstring }; + use std::cell::RefCell; use std::ffi::CString; use std::os::raw::c_char; use std::ptr; + use std::rc::Rc; + + // traits + + use std::borrow::ToOwned; + // The following defined in C #[no_mangle] @@ -17,6 +24,33 @@ 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 + pub struct CKeyState(*const RefCell); + impl CKeyState { + fn unwrap(self) -> Rc> { + 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(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 // The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers @@ -24,63 +58,59 @@ pub mod c { // so it should handle garbled strings in the future #[no_mangle] pub extern "C" - fn squeek_key_new(keycode: u32) -> *mut KeyState { - Box::into_raw(Box::new( + fn squeek_key_new(keycode: u32) -> CKeyState { + let state: Rc> = Rc::new(RefCell::new( KeyState { pressed: false, locked: false, keycode: keycode, symbol: None, } - )) + )); + CKeyState(Rc::into_raw(state)) } #[no_mangle] pub extern "C" - fn squeek_key_free(key: *mut KeyState) { - unsafe { Box::from_raw(key) }; // gets dropped + fn squeek_key_free(key: CKeyState) { + key.unwrap(); // reference dropped } #[no_mangle] pub extern "C" - fn squeek_key_is_pressed(key: *const KeyState) -> u32 { - let key = unsafe { &*key }; - return key.pressed as u32; + fn squeek_key_is_pressed(key: CKeyState) -> u32 { + //let key = unsafe { Rc::from_raw(key.0) }; + return key.to_owned().pressed as u32; } #[no_mangle] pub extern "C" - fn squeek_key_set_pressed(key: *mut KeyState, pressed: u32) { - let key = unsafe { &mut *key }; - key.pressed = pressed != 0; + fn squeek_key_set_pressed(key: CKeyState, pressed: u32) { + key.borrow_mut(|key| key.pressed = pressed != 0); } #[no_mangle] pub extern "C" - fn squeek_key_is_locked(key: *const KeyState) -> u32 { - let key = unsafe { &*key }; - return key.locked as u32; + fn squeek_key_is_locked(key: CKeyState) -> u32 { + return key.to_owned().locked as u32; } #[no_mangle] pub extern "C" - fn squeek_key_set_locked(key: *mut KeyState, locked: u32) { - let key = unsafe { &mut *key }; - key.locked = locked != 0; + fn squeek_key_set_locked(key: CKeyState, locked: u32) { + key.borrow_mut(|key| key.locked = locked != 0); } #[no_mangle] pub extern "C" - fn squeek_key_get_keycode(key: *const KeyState) -> u32 { - let key = unsafe { &*key }; - return key.keycode as u32; + fn squeek_key_get_keycode(key: CKeyState) -> u32 { + return key.to_owned().keycode as u32; } #[no_mangle] pub extern "C" - fn squeek_key_set_keycode(key: *mut KeyState, code: u32) { - let key = unsafe { &mut *key }; - key.keycode = code; + fn squeek_key_set_keycode(key: CKeyState, code: u32) { + key.borrow_mut(|key| key.keycode = code); } // TODO: this will receive data from the filesystem, @@ -88,7 +118,7 @@ pub mod c { #[no_mangle] pub extern "C" fn squeek_key_add_symbol( - key: *mut KeyState, + key: CKeyState, element: *const c_char, text_raw: *const c_char, keyval: u32, label: *const c_char, icon: *const c_char, @@ -110,14 +140,6 @@ pub mod c { } }); - let key = unsafe { &mut *key }; - - if let Some(_) = key.symbol { - eprintln!("Key {:?} already has a symbol defined", text); - return; - } - - let icon = into_cstring(icon) .unwrap_or_else(|e| { eprintln!("Icon name unreadable: {}", e); @@ -147,42 +169,52 @@ pub mod c { None }); - key.symbol = Some(match element.to_bytes() { - b"symbol" => Symbol { - action: Action::Submit { - text: text, - keys: Vec::new(), + + key.borrow_mut(|key| { + 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, }, - label: label, - tooltip: tooltip, - }, - _ => panic!("unsupported element type {:?}", element), + _ => panic!("unsupported element type {:?}", element), + }); }); } #[no_mangle] pub extern "C" - fn squeek_key_get_symbol(key: *const KeyState) -> *const symbol::Symbol { - let key = unsafe { &*key }; - match key.symbol { - Some(ref symbol) => symbol as *const symbol::Symbol, - None => ptr::null(), - } + 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(), + } + }) } #[no_mangle] pub extern "C" fn squeek_key_to_keymap_entry( key_name: *const c_char, - key: *const KeyState, + key: CKeyState, ) -> *const c_char { let key_name = as_cstr(&key_name) .expect("Missing key name") .to_str() .expect("Bad key name"); - let key = unsafe { &*key }; - let symbol_name = match key.symbol { + let symbol_name = match key.to_owned().symbol { Some(ref symbol) => match &symbol.action { symbol::Action::Submit { text: Some(text), .. } => { Some( @@ -209,7 +241,7 @@ pub mod c { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct KeyState { pressed: bool, locked: bool, diff --git a/src/symbol.rs b/src/symbol.rs index ae5bcec3..2cea275b 100644 --- a/src/symbol.rs +++ b/src/symbol.rs @@ -74,7 +74,7 @@ pub mod c { } /// Just defines some int->identifier mappings for convenience -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum KeySym { Unknown = 0, Shift = 0xffe1, @@ -89,10 +89,10 @@ impl KeySym { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct XKeySym(pub u32); -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Label { /// Text used to display the symbol Text(CString), @@ -104,14 +104,14 @@ pub enum Label { type Level = u8; /// Use to send modified keypresses -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Modifier { Control, Alt, } /// Action to perform on the keypress and, in reverse, on keyrelease -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Action { /// Switch to this level TODO: reverse? SetLevel(Level), @@ -127,7 +127,7 @@ pub enum Action { } /// Contains a static description of a particular key's actions -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Symbol { /// The action that this key performs pub action: Action,