aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTeddy Wing2018-09-03 18:00:56 +0200
committerTeddy Wing2018-09-06 04:03:20 +0200
commit84d29715900209b8ab4c600ad40ef99cdad03bd6 (patch)
tree598fc93981cc3a1109ce1fa29136b264a093ed43
parent4b31eb9b8412e429949aca73ef475787910e4b0b (diff)
downloaddome-key-map-84d29715900209b8ab4c600ad40ef99cdad03bd6.tar.bz2
Trying to fix pointer lifetime of mode `CKeyActionResult` (WIP)
Can't get this working. Tried a bunch of things. Decided to commit this at a stopping point before messing any further. Sort of getting there, with some things that seem like they're pointing in the right direction, but it's not working out so far. Still getting a segfault. Actually, with the `Box::into_raw` addition, the lifetime of the mode result actually lasts for a single call (printf), and then gets freed (weirdly). Makefile: * Add `-W` error flags to see if those would give me any extra information about the pointer problems, but didn't get anything. The fact that I didn't get errors indicated it was a problem on the Rust side. * Change `clean` dependency to `moder.c` so we don't rebuild if the C file (and lib) hasn't changed. c_run_key_action(): * Add some `println!`s and debug clutter * Add a separate `let` binding for `run_key_action_for_mode()` because that seemed to fix some weirdness in control flow when I was debugging the code at one point in `lldb`. Not sure it this change still makes sense to keep. * Changed function/closure version of `in_mode` to `if`/`else` because that may have made a difference in some dumb things I was experimenting with at some point. * Unsuccessful tries of `mem::forget()`, ultimately commented out. * Return a `Box::into_raw` pointer to the `CKeyActionResult` instead of the Rust pointer we were previously returning. This allows the value to live beyond the function and beyond Rust's control into the calling C code. This does, however, mean that the value leaks memory, and will need to be freed manually in the calling C code. run_key_action_for_mode(): * Wrap map handler in a check to verify `in_mode` is `None`. This ensures that if we should be returning a `KeyActionResult` for a mapping inside a mode, we don't run this code that's meant for mappings outside a mode.
-rw-r--r--Makefile4
-rw-r--r--moder.c2
-rw-r--r--src/cocoa_bridge.rs100
3 files changed, 70 insertions, 36 deletions
diff --git a/Makefile b/Makefile
index c5bd2e2..b4e76fa 100644
--- a/Makefile
+++ b/Makefile
@@ -8,8 +8,8 @@ $(LIB): $(SOURCE_FILES)
includer: clean $(LIB)
gcc -o $@ includer.c $(LIB)
-moder: clean $(LIB)
- gcc -o $@ $@.c $(LIB)
+moder: moder.c $(LIB)
+ gcc -g -Wall -Wextra -Werror -o $@ $< $(LIB)
.PHONY: clean
clean:
diff --git a/moder.c b/moder.c
index a10a6da..c50a7d5 100644
--- a/moder.c
+++ b/moder.c
@@ -10,7 +10,7 @@ int main() {
.length = SIZE
};
const CKeyActionResult *mode = c_run_key_action(mode_trigger, NULL);
- printf("%d\n", *mode->kind);
+ /* printf("%d\n", *mode->kind); */
HeadphoneButton buttons[] = {HeadphoneButton_Down};
Trigger trigger = {
diff --git a/src/cocoa_bridge.rs b/src/cocoa_bridge.rs
index 15cee95..8581b46 100644
--- a/src/cocoa_bridge.rs
+++ b/src/cocoa_bridge.rs
@@ -1,4 +1,5 @@
use std::ffi::{CStr, CString};
+use std::mem;
use std::ptr;
use std::slice;
@@ -42,6 +43,7 @@ struct renameMeMapGroup {
// Somehow: switch mode inside Rust
#[repr(C)]
+#[derive(Debug)]
pub struct Trigger {
pub buttons: *const HeadphoneButton,
pub length: size_t,
@@ -83,6 +85,7 @@ impl<'a> KeyActionResult<'a> {
}
#[repr(C)]
+#[derive(Debug)]
pub struct CKeyActionResult {
pub action: *const c_char,
pub kind: *const ActionKind,
@@ -104,6 +107,7 @@ pub extern "C" fn c_run_key_action(
if mode.is_null() {
None
} else {
+ println!("{:?}", *mode);
assert!(!(*mode).buttons.is_null());
Some(
@@ -111,30 +115,52 @@ pub extern "C" fn c_run_key_action(
)
}
};
+ println!("{:?}", mode);
- let result = match run_key_action_for_mode(trigger, mode) {
+ let result = run_key_action_for_mode(trigger, mode);
+ let result = match result {
Some(k) => {
let action = k.action.map_or_else(
|| ptr::null(),
|a| a.into_raw(),
);
- let in_mode = k.in_mode.map_or_else(
- || ptr::null(),
- |m| {
- let trigger = Trigger {
- buttons: m.as_ptr(),
- length: m.len(),
- };
-
- &trigger
- },
- );
-
- CKeyActionResult {
+ // let in_mode = k.in_mode.map_or_else(
+ // || ptr::null(),
+ // |m| {
+ // let trigger = Trigger {
+ // buttons: m.as_ptr(),
+ // length: m.len(),
+ // };
+ // mem::forget(m);
+ //
+ // &trigger
+ // },
+ // );
+ let trigger;
+ let in_mode = if let Some(m) = k.in_mode {
+ trigger = Trigger {
+ buttons: m.as_ptr(),
+ length: m.len(),
+ };
+
+ &trigger
+ } else {
+ ptr::null()
+ };
+ // mem::forget(k.in_mode);
+ // mem::forget(in_mode);
+ // println!("IN MODE: {:?}", &in_mode);
+ // let in_mode2 = Box::new(k.in_mode);
+ // let in_mode_ptr = Box::into_raw(in_mode2);
+
+ let result = CKeyActionResult {
action: action, // memory leak, must be freed from Rust
kind: &k.kind,
in_mode: in_mode,
- }
+ };
+ println!("{:?}", result);
+ // mem::forget(result);
+ result
},
None => {
CKeyActionResult {
@@ -144,8 +170,13 @@ pub extern "C" fn c_run_key_action(
}
}
};
+ // println!("hey result: {:?}", result);
+ // mem::forget(result);
+ let r = Box::new(result);
+ let r2 = Box::into_raw(r);
- &result as *const CKeyActionResult
+ // &result as *const CKeyActionResult
+ r2 as *const CKeyActionResult
}
#[no_mangle]
@@ -189,23 +220,26 @@ mode <play><up> {
}
}
- if let Some(map) = map {
- return match map.kind {
- MapKind::Map => {
- Some(
- KeyActionResult::new(ActionKind::Map)
- .with_action(&map.action)
- )
- },
- MapKind::Command => {
- Some(
- KeyActionResult::new(ActionKind::Command)
- )
- },
- // MapKind::Mode => {
- // TODO: Maybe make a new type just for KeyActionResult that
- // combines regular MapKinds and Mode
- // },
+ // TODO: make sure this doesn't run when in_mode
+ if in_mode.is_none() {
+ if let Some(map) = map {
+ return match map.kind {
+ MapKind::Map => {
+ Some(
+ KeyActionResult::new(ActionKind::Map)
+ .with_action(&map.action)
+ )
+ },
+ MapKind::Command => {
+ Some(
+ KeyActionResult::new(ActionKind::Command)
+ )
+ },
+ // MapKind::Mode => {
+ // TODO: Maybe make a new type just for KeyActionResult that
+ // combines regular MapKinds and Mode
+ // },
+ }
}
}