I want to access data that is protected by a RwLock. Unfortunately, I am forced to return a reference.
Background: I am using rust-qt-binding-generator with QtQuick and I want to visualize data that is being received on the rust side asynchronously. The data comes as Vec, and consequently, I want to use QByteArray on the Qt side. rust-qt-binding-generator offers this data type.
My problem is that the generated trait requires a getter function with the following signature:
fn channels(&self) -> &[u8]
Code:
#![allow(unused_imports)]
#![allow(unused_variables)]
#![allow(dead_code)]
use interface::*;
use std::sync::{Arc, RwLock, RwLockWriteGuard};
use std::time::Duration;
use std::thread;
pub struct RustController {
emit: RustControllerEmitter,
ch_vals: Vec<u8>,
channels: Arc<RwLock<Vec<u8>>>
}
impl RustControllerTrait for RustController {
fn new(emit: RustControllerEmitter) -> RustController {
let mut ret = RustController {
emit: emit.clone(),
ch_vals: vec!(),
channels: Arc::new(RwLock::new(create_empty_vector())),
};
update_thread(emit, ret.channels.clone());
ret
}
fn emit(&self) -> &RustControllerEmitter {
&self.emit
}
fn channels(&self) -> &[u8] {
// *((*self.channels).read().unwrap()).clone()
// does not work of course (and nothing else I tried obviously)
// because I can only get the value as a temporary one. writing
// them into self.ch_vals would solve the problem, but I am not
// allowed to get a &mut self
//&self.ch_vals // <-- this would work, but does not contain
// the values generated in the thread.
}
}
fn create_empty_vector() -> Vec<u8> {
let mut ret: Vec<u8> = Vec::with_capacity(512);
for i in 0..512 {
ret.push((i/2) as u8);
}
ret
}
fn update_thread(
emit: RustControllerEmitter,
channels: Arc<RwLock<Vec<u8>>>,
) {
thread::spawn(move || {
loop {
{
let mut w: RwLockWriteGuard<Vec<u8>> = (*channels).write().unwrap();
(*w)[0] += 1;
// changing values in the mutex is no problem, but no
// reference to the RustController here to store value
}
emit.channels_changed();
thread::sleep(Duration::from_secs(1));
}
});
}
If you want to run it yourself, here is my bindings.json:
{
"cppFile": "src/Bindings.cpp",
"rust": {
"dir": "rust",
"interfaceModule": "interface",
"implementationModule": "implementation"
},
"objects": {
"RustController": {
"type": "Object",
"properties": {
"channels": {
"type": "QByteArray"
}
}
}
}
}
With this setup I am able to transfer an i32 without problems, but Vec does not work because of the getter. My understanding of the problem is that I am unable to store the values generated in the extra thread in a place which can be referenced in the getter (and lives long enough, ideally as long as the RustController in use).