veryl-parser 0.20.2

A modern hardware description language
Documentation
use crate::resource_table::PathId;
use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::Arc;

#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct TextId(pub usize);

thread_local!(static TEXT_ID: RefCell<usize> = const { RefCell::new(0) });

pub fn new_text_id() -> TextId {
    TEXT_ID.with(|f| {
        let mut ret = f.borrow_mut();
        *ret += 1;
        TextId(*ret)
    })
}

/// Returns the last issued text ID value. Used to delimit per-file ID
/// windows for fragment caching.
pub fn peek_text_id() -> usize {
    TEXT_ID.with(|f| *f.borrow())
}

/// Reserves `count` consecutive text IDs and returns the value the counter
/// had before the reservation. The reserved IDs are `base+1..=base+count`.
pub fn reserve_text_ids(count: usize) -> usize {
    TEXT_ID.with(|f| {
        let mut ret = f.borrow_mut();
        let base = *ret;
        *ret += count;
        base
    })
}

/// Inserts a text entry under a caller-provided (reserved) ID without
/// touching `current_text`. Used by fragment restore.
pub fn insert_with_id(id: TextId, info: TextInfo) {
    TEXT_TABLE.with(|f| {
        f.borrow_mut().table.insert(id, Arc::new(info));
    })
}

#[derive(Clone, Debug)]
pub struct TextInfo {
    pub text: String,
    pub path: PathId,
}

#[derive(Clone, Default, Debug)]
pub struct TextTable {
    current_text: TextId,
    // `Arc`-shared so `export_tables`/`import_tables` bumps refcounts
    // instead of duplicating every source file (MB per entry on large designs).
    table: HashMap<TextId, Arc<TextInfo>>,
}

impl TextTable {
    pub fn set_current_text(&mut self, info: TextInfo) -> TextId {
        let id = new_text_id();
        self.table.insert(id, Arc::new(info));
        self.current_text = id;
        id
    }

    pub fn get_current_text(&self) -> TextId {
        self.current_text
    }

    pub fn get(&self, id: TextId) -> Option<TextInfo> {
        self.table.get(&id).map(|x| (**x).clone())
    }

    pub fn drop(&mut self, id: PathId) {
        self.table.retain(|_, x| x.path != id);
    }
}

thread_local!(static TEXT_TABLE: RefCell<TextTable> = RefCell::new(TextTable::default()));

pub fn set_current_text(info: TextInfo) -> TextId {
    TEXT_TABLE.with(|f| f.borrow_mut().set_current_text(info))
}

pub fn get_current_text() -> TextId {
    TEXT_TABLE.with(|f| f.borrow().get_current_text())
}

pub fn get(id: TextId) -> Option<TextInfo> {
    TEXT_TABLE.with(|f| f.borrow().get(id))
}

pub fn drop(id: PathId) {
    TEXT_TABLE.with(|f| f.borrow_mut().drop(id))
}

/// Snapshot of the calling thread's `text_table`. Cheap to pass between
/// threads — `TextInfo` payloads are `Arc`-shared.
pub struct TextTableSnapshot {
    text_table: TextTable,
}

pub fn export_tables() -> TextTableSnapshot {
    TextTableSnapshot {
        text_table: TEXT_TABLE.with(|f| f.borrow().clone()),
    }
}

pub fn import_tables(snapshot: &TextTableSnapshot) {
    TEXT_TABLE.with(|f| *f.borrow_mut() = snapshot.text_table.clone());
}