auto_correct 0.1.9

A library to provide auto correct suggestions. Currently supporting EN-US.
Documentation
use hashbrown::HashSet;
use std::sync::atomic::{AtomicBool, Ordering};
use candidate::Candidate;
use std::sync::Once;

static mut STORE: Option<HashSet<String>> = None;
static mut RESULTS: Option<HashSet<Candidate>> = None;

static LOCKED: [AtomicBool; 2] = [AtomicBool::new(false), AtomicBool::new(false)];
static READY: AtomicBool = AtomicBool::new(false);
static ONCE: Once = Once::new();

pub(crate) fn get_ready() {
    READY.store(true, Ordering::SeqCst);
    ONCE.call_once(|| unsafe {
        STORE.replace(HashSet::with_capacity(256));
        RESULTS.replace(HashSet::with_capacity(64));
    });
}

pub(crate) fn reset() {
    READY.store(false, Ordering::SeqCst);

    unsafe {
        if let Some(store) = STORE.as_mut() {
            store.clear();
        }

        if let Some(res) = RESULTS.as_mut() {
            res.clear();
        }
    }
}

pub(crate) fn contains(word: &str) -> bool {
    if !READY.load(Ordering::SeqCst) {
        return true;
    }

    let mut contains = true;
    unsafe {
        if let Some(store) = STORE.as_mut() {
            if !store.contains(word) {
                lock(0);
                contains = !store.insert(word.to_owned());
                unlock(0);
            }
        }
    }

    contains
}

pub(crate) fn publish(candidate: Candidate) -> bool {
    if !READY.load(Ordering::SeqCst) {
        return true;
    }

    unsafe {
        if let Some(res) = RESULTS.as_mut() {
            if res.contains(&candidate) {
                return true;
            }

            lock(1);
            res.insert(candidate);
            unlock(1);

            return false;
        }
    }

    true
}

pub(crate) fn collect() -> Vec<Candidate> {
    lock(1);

    let res =
        if let Some(res) = unsafe { RESULTS.as_mut() } {
            let mut vec = Vec::with_capacity(res.len());
            for candidate in res.drain() {
                vec.push(candidate);
            }

            vec
        } else {
            vec![]
        };

    unlock(1);
    return res;
}

fn lock(id: usize) {
    if id < LOCKED.len() {
        let lock = &LOCKED[id];
        loop {
            if lock.compare_and_swap(false, true, Ordering::SeqCst) {
                break;
            }
        }
    }
}

fn unlock(id: usize) {
    if id < LOCKED.len() {
        LOCKED[id].store(false, Ordering::SeqCst);
    }
}