Sto scrivendo un wrapper/FFI per una libreria C che richiede una chiamata di inizializzazione globale nel thread principale e uno per la distruzione.Modo consigliato di avvolgere routine di inizializzazione/distruzione C lib.
Ecco come Attualmente sto maneggiarlo:
struct App;
impl App {
fn init() -> Self {
unsafe { ffi::InitializeMyCLib(); }
App
}
}
impl Drop for App {
fn drop(&mut self) {
unsafe { ffi::DestroyMyCLib(); }
}
}
che può essere usato come:
fn main() {
let _init_ = App::init();
// ...
}
Questo funziona bene, ma ci si sente come un hack, legando queste chiamate alla vita di una struttura non necessaria. Avere il distruttore in un blocco finally
(Java) o at_exit
(Ruby) sembra in teoria più appropriato.
Esiste un modo più aggraziato per farlo in Rust?
EDIT
Sarebbe possibile/sicuro da usare questa configurazione in questo modo (usando il lazy_static
cassa), invece del mio secondo blocco di cui sopra:
lazy_static! {
static ref APP: App = App::new();
}
Sarebbe questo riferimento essere garantito a essere inizializzato prima di qualsiasi altro codice e distrutto all'uscita? È una cattiva pratica usare lazy_static
in una libreria?
Ciò renderebbe anche più semplice facilitare l'accesso alla FFI attraverso questa struttura, poiché non dovrei preoccuparmi di passare il riferimento alla struttura istanziata (chiamata nel mio esempio originale _init_
).
Ciò renderebbe anche più sicuro in alcuni modi, poiché potrei rendere privato il costruttore di struct default App
.
Side-Note: A seconda della sicurezza del wrapper, è necessario rendere la funzione 'init' non sicura (poiché nessuno può chiamarla più volte) e implementare tutte le funzioni che richiedono l'inizializzazione del clib come metodi sull'oggetto 'App'. In questo modo nessuno può chiamare le funzioni senza averle inizializzate. È anche possibile implementarlo come una sorta di singolo conteggio di riferimento per renderlo sicuro da inizializzare. Questa è una grande vittoria su Java e Ruby, perché lì puoi chiamare le funzioni senza aver inizializzato la lib –
* nel thread principale * - sei ** sicuro ** che deve essere il thread principale? Potrebbe essere un thread qualsiasi, purché sia inizializzato prima dell'uso? – Shepmaster
@ker, grazie per il commento. Non ci avevo pensato in quel modo (avendo tutti accesso attraverso la struttura "App", ma questo ha senso. Dovrò pensare se questo funzionerebbe per il mio caso. –