Есть ли чистый способ иметь глобальное изменяемое состояние в плагине Rust?

Единственный способ сделать это - небезопасная одноэлементная функция:

fn singleton() -> &'static mut HashSet<String> {
    static mut hash_map: *mut HashSet<String> = 0 as *mut HashSet<String>;

    let map: HashSet<String> = HashSet::new();
    unsafe {
        if hash_map == 0 as *mut HashSet<String> {
            hash_map = mem::transmute(Box::new(map));
        }
        &mut *hash_map
    }
}

Есть ли способ лучше? Возможно, мы могли бы сделать что-то в plugin_registrar функционировать?

Под глобальным изменяемым состоянием я подразумеваю изменчивую переменную, которая может использоваться несколькими процедурными макросами и / или атрибутами.

Обновить:

Я пишу плагин компилятора, чтобы обеспечить sql! процедурный макрос. у меня есть #[sql_table] атрибут, который будет использоваться в структурах, чтобы я мог получить имя и столбцы таблицы SQL.

Мне нужно глобальное изменяемое состояние, чтобы сохранить имя и поля struct в атрибуте, так что процедурный макрос может проверить, что все идентификаторы существуют.

1 ответ

Решение

lazy_static! макрос может помочь с глобальным инициализатором, который не является статическим. https://crates.io/crates/lazy_static/ Это делает что-то похожее на ваш if hash_map == 0 as *mut HashSet<String>, но заботится о гонке данных в случае, если более чем один поток пытается сделать это одновременно.

Что касается изменчивости, чтобы избежать новых гонок данных, вам придется как-то защитить ее, возможно, с Mutex,

Все вместе:

#[macro_use] extern crate lazy_static;
use std::sync::Mutex;
use std::collections::HashSet;

lazy_static! {
    static ref THINGS: Mutex<HashSet<String>> = Mutex::new(HashSet::new());
}

fn usage() {
    // unwrap only fails if the lock is poisoned:
    // if another thread panicked while holding the lock.
    THINGS.lock().unwrap().insert("thing".to_owned())
}
Другие вопросы по тегам