I am attempting to test a JSON bridge which I set up for use with Dart, JS and Python UI frameworks. It works fine for those, but when I attempted the same UI/logic split in a Rust program using tui-rs, I get a lifetime error when trying to deserialize a logic thread result on the UI thread.
I understand that using JSON for communication between layers both written in Rust is not the ideal way to do things, but given my goals, I hope it is understandable.
I've tried cloning which worked for things to be serialized and sent from UI to logic but this did not work for deserializing from logic to UI
use std::sync::mpsc;
use std::sync::mpsc::{Receiver, Sender};
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
use serde::{Deserialize, Serialize};
#[macro_export]
macro_rules! BridgeResult {
($result:expr, $data:expr) => {
BridgeResult {
result: $result,
data: vec![$data.to_string()],
}
};
}
#[derive(Serialize, Deserialize)]
struct BridgeResult {
result: &'static str,
data: Vec<String>,
}
#[derive(Serialize, Deserialize)]
struct App {
state: i64,
}
impl Default for App {
fn default() -> App {
App { state: 0 }
}
}
fn main() {
let (to_logic, from_ui) = mpsc::channel();
let (to_ui, from_logic) = mpsc::channel();
ui(to_logic, from_logic);
logic(to_ui, from_ui);
}
fn ui(tx: Sender<(String, String)>, rx: Receiver<(String)>) {
let app = App::default();
let app_string = serde_json::to_string(&app)
.expect("failed to encode app struct for sending to logic heard");
tx.send(("binary_switch".to_string(), app_string))
.expect("failed to send binary_switch call and data to logic thread");
let output_string = rx
.recv()
.expect("failed to get a result from logic's initialize");
let output: BridgeResult = serde_json::from_str(&output_string)
.expect("failed to decode result from logic's binary_switch");
if output.result != "Ok()" {
panic!("init failed due to: \n {:?}", output.data);
} else {
println!("{:?}", output.data);
}
}
fn logic(tx: Sender<(String)>, rx: Receiver<(String, String)>) {
loop {
let (function, arguments) = rx
.recv()
.expect("failed to receive function and arguments from ui thread");
let result = match function.as_str() {
"binary_switch" => binary_switch(&arguments),
_ => {
BridgeResult! {"Err()", format!("cannot find rust function branch matching {}", function)}
}
};
let output = match serde_json::to_string(&result) {
Ok(output) => output,
Err(_) => "{'result' : 'Err()', 'data': 'failed exit encoding!!!'}".to_string(),
};
tx.send(output)
.expect("failed to send the output back to the ui thread");
}
}
fn binary_switch(data: &String) -> BridgeResult {
#[derive(Deserialize)]
struct Arguments {
state: i64,
}
let mut arguments: Arguments = match serde_json::from_str(&data) {
Ok(data) => data,
Err(err) => return BridgeResult! {"Err()", format!("failed to parse arguments\n, {}", err)},
};
if arguments.state == 0 {
arguments.state += 1;
} else {
arguments.state -= 1;
}
BridgeResult! {"Ok()", arguments.state}
}
I expect this to deserialize the BridgeResult
type and use the data field which should have a string 1 in it. In reality I get:
error[E0597]: `output_string` does not live long enough
--> src/main.rs:55:53
|
55 | let output: BridgeResult = serde_json::from_str(&output_string)
| ---------------------^^^^^^^^^^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `output_string` is borrowed for `'static`
...
63 | }
| - `output_string` dropped here while still borrowed