Hello experts,
I am trying to implement a shared library in Rust (essentially porting from C, so I have to maintain the compatibility for existing applications).
I know Rust discourages shared global state and recommends to passaround the shared data like ctx back to the calling client and then make it part of the calls, but unfortunately, I have to maintain portability to existing apps, so that is not an option.
What is the best way to handle this. There are many articles, QnA etc., and nothing seems to perfectly work.
I have tried OnceLock that seems to leak some memory and does not solve it perfectly (especially cleaning up - terminate fn below).
Could you share your expert opinions on the best way, and if there are existing code solving this problem, point to them please?
Roughly, the code looks like this. The problem seems to also originate from having to store dyn Trait
// trait.rs
pub trait Trait {
fn t_process(&self);
}
// file_type1.rs
pub FileType1 {
field1: type1
field2: type2
}
impl FileType1 {
pub fn init(f1: type1, f2: type2) -> Self {
}
// other methods
}
impl Trait for FileType1 {
fn t_process(&self) {
}
}
// file_type2.rs
pub FileType2 {
field1: type1
field2: type2
}
impl FileType2 {
pub fn init(f1: type1, f2: type2) -> Self {
}
// other methods
}
impl Trait for FileType1 {
fn t_process(&self) {
}
}
// handler.rs
pub struct Handler {
inst: Box<dyn Trait + Send + Sync>
}
impl Handler {
pub fn init(field0: inst_type, field1: type1, field2: type2) -> Self {
// init self.inst based on field0 passed
}
pub fn f_process(&self) {
self.inst.t_process()
}
pub fn terminate() {
// cleanup
// two problems - if I use static OnceLock, I cannot pass &mut self
// I cannot clean Box<dyn Trait> by getting into_raw and freeing it up
}
}
//lib.rs
pub unsafe extern "C" init(field0: inst_type, field1: type1, field2: type2) {
// init handler
}
pub unsafe extern "C" f_process() {
//call handler.f_process()
}