tectonic_engine_bibtex 0.2.0

The `bibtex` program as a reusable crate.
Documentation
use crate::c_api::{
    entries::{with_entries, ENT_STR_SIZE},
    hash::{with_hash, with_hash_mut},
    other::with_other_mut,
    pool::with_pool,
    xbuf::XBuf,
    CiteNumber, FindCiteLocs, HashPointer2, StrIlk, StrNumber,
};
use std::{cell::RefCell, cmp::Ordering};

pub const MAX_CITES: usize = 750;

pub struct CiteInfo {
    cite_list: XBuf<StrNumber>,
    cite_info: XBuf<StrNumber>,
    type_list: XBuf<HashPointer2>,
    entry_exists: XBuf<bool>,
    cite_ptr: CiteNumber,

    entry_cite_ptr: CiteNumber,
    num_cites: CiteNumber,
    old_num_cites: CiteNumber,
    all_marker: CiteNumber,
}

impl CiteInfo {
    fn new() -> CiteInfo {
        CiteInfo {
            cite_list: XBuf::new(MAX_CITES),
            cite_info: XBuf::new(MAX_CITES),
            type_list: XBuf::new(MAX_CITES),
            entry_exists: XBuf::new(MAX_CITES),
            cite_ptr: 0,
            entry_cite_ptr: 0,
            num_cites: 0,
            old_num_cites: 0,
            all_marker: 0,
        }
    }

    fn grow(&mut self) {
        self.cite_list.grow(MAX_CITES);
        self.cite_info.grow(MAX_CITES);
        self.type_list.grow(MAX_CITES);
        self.entry_exists.grow(MAX_CITES);
    }

    pub fn get_cite(&self, offset: usize) -> StrNumber {
        self.cite_list[offset]
    }

    pub fn set_cite(&mut self, offset: usize, num: StrNumber) {
        self.cite_list[offset] = num;
    }

    pub fn get_info(&self, offset: usize) -> StrNumber {
        self.cite_info[offset]
    }

    pub fn set_info(&mut self, offset: usize, num: StrNumber) {
        self.cite_info[offset] = num;
    }

    pub fn get_type(&self, offset: usize) -> HashPointer2 {
        self.type_list[offset]
    }

    pub fn set_type(&mut self, offset: usize, ty: HashPointer2) {
        self.type_list[offset] = ty;
    }

    pub fn get_exists(&self, offset: usize) -> bool {
        self.entry_exists[offset]
    }

    pub fn set_exists(&mut self, offset: usize, exists: bool) {
        self.entry_exists[offset] = exists;
    }

    pub fn ptr(&self) -> CiteNumber {
        self.cite_ptr
    }

    pub fn set_ptr(&mut self, ptr: CiteNumber) {
        self.cite_ptr = ptr;
    }

    pub fn num_cites(&self) -> CiteNumber {
        self.num_cites
    }
}

thread_local! {
    pub static CITE_INFO: RefCell<CiteInfo> = RefCell::new(CiteInfo::new());
}

pub fn reset() {
    CITE_INFO.with(|ci| *ci.borrow_mut() = CiteInfo::new());
}

pub fn with_cites<T>(f: impl FnOnce(&CiteInfo) -> T) -> T {
    CITE_INFO.with(|ci| f(&ci.borrow()))
}

pub fn with_cites_mut<T>(f: impl FnOnce(&mut CiteInfo) -> T) -> T {
    CITE_INFO.with(|ci| f(&mut ci.borrow_mut()))
}

fn less_than(arg1: &CiteNumber, arg2: &CiteNumber) -> Ordering {
    with_entries(|entries| {
        let ptr1 = arg1 * entries.num_ent_strs() + entries.sort_key_num();
        let ptr2 = arg2 * entries.num_ent_strs() + entries.sort_key_num();
        let mut char_ptr = 0;
        loop {
            let char1 = entries.strs(ptr1 * (ENT_STR_SIZE + 1) + char_ptr);
            let char2 = entries.strs(ptr2 * (ENT_STR_SIZE + 1) + char_ptr);

            match (char1, char2) {
                (127, 127) => return arg1.cmp(arg2),
                (127, _) => return Ordering::Less,
                (_, 127) => return Ordering::Greater,
                (char1, char2) if char1 != char2 => return char1.cmp(&char2),
                _ => (),
            }

            char_ptr += 1;
        }
    })
}

#[no_mangle]
pub extern "C" fn quick_sort(left_end: CiteNumber, right_end: CiteNumber) {
    with_cites_mut(|cites| cites.cite_info[left_end..=right_end].sort_by(less_than))
}

#[no_mangle]
pub extern "C" fn cite_list(num: CiteNumber) -> StrNumber {
    with_cites(|cites| cites.get_cite(num))
}

#[no_mangle]
pub extern "C" fn set_cite_list(num: CiteNumber, str: StrNumber) {
    with_cites_mut(|cites| cites.set_cite(num, str))
}

#[no_mangle]
pub extern "C" fn cite_ptr() -> CiteNumber {
    with_cites(|cites| cites.ptr())
}

#[no_mangle]
pub extern "C" fn set_cite_ptr(num: CiteNumber) {
    with_cites_mut(|cites| cites.set_ptr(num))
}

#[no_mangle]
pub extern "C" fn check_cite_overflow(last_cite: CiteNumber) {
    with_cites_mut(|cites| {
        if last_cite == cites.cite_list.len() {
            cites.grow();
        }
    })
}

#[no_mangle]
pub extern "C" fn max_cites() -> usize {
    with_cites(|cites| cites.cite_list.len())
}

#[no_mangle]
pub extern "C" fn cite_info(num: CiteNumber) -> StrNumber {
    with_cites(|cites| cites.get_info(num))
}

#[no_mangle]
pub extern "C" fn set_cite_info(num: CiteNumber, info: StrNumber) {
    with_cites_mut(|cites| cites.set_info(num, info))
}

#[no_mangle]
pub extern "C" fn type_list(num: CiteNumber) -> HashPointer2 {
    with_cites(|cites| cites.get_type(num))
}

#[no_mangle]
pub extern "C" fn set_type_list(num: CiteNumber, ty: HashPointer2) {
    with_cites_mut(|cites| cites.set_type(num, ty))
}

#[no_mangle]
pub extern "C" fn entry_exists(num: CiteNumber) -> bool {
    with_cites(|cites| cites.get_exists(num))
}

#[no_mangle]
pub extern "C" fn set_entry_exists(num: CiteNumber, exists: bool) {
    with_cites_mut(|cites| cites.set_exists(num, exists))
}

#[no_mangle]
pub extern "C" fn entry_cite_ptr() -> CiteNumber {
    with_cites(|cites| cites.entry_cite_ptr)
}

#[no_mangle]
pub extern "C" fn set_entry_cite_ptr(val: CiteNumber) {
    with_cites_mut(|cites| cites.entry_cite_ptr = val)
}

#[no_mangle]
pub extern "C" fn num_cites() -> CiteNumber {
    with_cites(|cites| cites.num_cites)
}

#[no_mangle]
pub extern "C" fn set_num_cites(val: CiteNumber) {
    with_cites_mut(|cites| cites.num_cites = val)
}

#[no_mangle]
pub extern "C" fn old_num_cites() -> CiteNumber {
    with_cites(|cites| cites.old_num_cites)
}

#[no_mangle]
pub extern "C" fn set_old_num_cites(val: CiteNumber) {
    with_cites_mut(|cites| cites.old_num_cites = val)
}

#[no_mangle]
pub extern "C" fn all_marker() -> CiteNumber {
    with_cites(|cites| cites.all_marker)
}

#[no_mangle]
pub extern "C" fn set_all_marker(val: CiteNumber) {
    with_cites_mut(|cites| cites.all_marker = val)
}

#[no_mangle]
pub extern "C" fn add_database_cite(
    new_cite: CiteNumber,
    cite_loc: CiteNumber,
    lc_cite_loc: CiteNumber,
) -> CiteNumber {
    with_cites_mut(|cites| {
        if new_cite == cites.cite_list.len() {
            cites.grow();
        }
        with_other_mut(|other| other.check_field_overflow(other.num_fields() * (new_cite + 1)));

        with_hash_mut(|hash| {
            cites.set_cite(new_cite, hash.text(cite_loc));
            hash.set_ilk_info(cite_loc, new_cite as i32);
            hash.set_ilk_info(lc_cite_loc, cite_loc as i32);
        });
    });
    new_cite + 1
}

#[no_mangle]
pub extern "C" fn find_cite_locs_for_this_cite_key(cite_str: StrNumber) -> FindCiteLocs {
    with_pool(|pool| {
        let val = pool.get_str(cite_str);

        let (cite_hash, lc_cite_hash) = with_hash(|hash| {
            let cite_hash = pool.lookup_str(hash, val, StrIlk::Cite);
            let lc_cite_hash = pool.lookup_str(hash, &val.to_ascii_lowercase(), StrIlk::LcCite);
            (cite_hash, lc_cite_hash)
        });

        FindCiteLocs {
            cite_loc: cite_hash.loc,
            cite_found: cite_hash.exists,
            lc_cite_loc: lc_cite_hash.loc,
            lc_found: lc_cite_hash.exists,
        }
    })
}