#![allow(clippy::module_name_repetitions)]
use core::fmt;
use std::clone::Clone;
use std::convert::Into;
use std::hash::{Hash, Hasher};
use std::iter::Iterator;
use more_asserts::assert_le;
use ahash::AHashMap;
use bumpalo::Bump;
use crate::symbol::keywords::EMPTY_SYMBOL;
use crate::symbol::statics::with_interner;
use crate::Span;
#[derive(Copy, Clone, Debug)]
pub struct Ident {
pub name: Symbol,
pub span: Span,
}
const DUMMY_SPAN: Span = Span::new_short_empty_span(0);
impl Ident {
#[inline]
#[must_use]
pub const fn new(name: Symbol, span: Span) -> Self {
Self { name, span }
}
#[must_use]
pub const fn empty() -> Self {
Self {
name: EMPTY_SYMBOL,
span: DUMMY_SPAN,
}
}
#[must_use]
pub const fn spanned_empty(span: Span) -> Self {
Self {
name: EMPTY_SYMBOL,
span,
}
}
#[allow(clippy::should_implement_trait)]
#[must_use]
pub fn from_str(string: &str) -> Self {
Self::new(Symbol::intern(string), DUMMY_SPAN)
}
#[must_use]
pub fn from_str_and_span(string: &str, span: Span) -> Self {
Self::new(Symbol::intern(string), span)
}
#[must_use]
pub fn without_first_quote(self) -> Self {
Self::new(
Symbol::intern(self.as_str().trim_start_matches('\'')),
self.span,
)
}
#[must_use]
pub fn as_str(self) -> SymbolStr {
self.name.as_str()
}
}
impl PartialEq for Ident {
fn eq(&self, rhs: &Self) -> bool {
self.name == rhs.name
}
}
impl Eq for Ident {}
impl Hash for Ident {
fn hash<H: Hasher>(&self, state: &mut H) {
self.name.hash(state);
}
}
impl fmt::Display for Ident {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.name, f)
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Symbol(SymbolIndex);
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
struct SymbolIndex(u32);
impl SymbolIndex {
pub const fn as_usize(self) -> usize {
self.0 as usize
}
pub const fn as_u32(self) -> u32 {
self.0
}
}
impl Symbol {
#[must_use]
const fn new(n: u32) -> Self {
Self(SymbolIndex(n))
}
#[must_use]
pub fn intern(string: &str) -> Self {
with_interner(|interner| interner.intern(string))
}
pub fn with<F: FnOnce(&str) -> R, R>(self, f: F) -> R {
with_interner(|interner| f(interner.get(self)))
}
#[must_use]
pub fn as_str(self) -> SymbolStr {
with_interner(|interner| unsafe {
SymbolStr {
string: std::mem::transmute::<&str, &str>(interner.get(self)),
}
})
}
#[must_use]
pub const fn as_u32(self) -> u32 {
let index = self.0;
index.0
}
}
impl fmt::Debug for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.with(|str| fmt::Debug::fmt(&str, f))?;
fmt::Debug::fmt(&self.0, f)
}
}
impl fmt::Display for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.with(|str| fmt::Display::fmt(&str, f))
}
}
#[derive(Default)]
pub struct Interner {
arena: Bump,
names: AHashMap<&'static str, Symbol>,
strings: Vec<&'static str>,
}
impl Interner {
fn prefill(init: &[&'static str]) -> Self {
Self {
strings: init.into(),
names: init.iter().copied().zip((0..).map(Symbol::new)).collect(),
..Default::default()
}
}
pub fn intern(&mut self, string: &str) -> Symbol {
if let Some(&name) = self.names.get(string) {
return name;
}
assert_le!(self.strings.len(),u32::MAX as usize);
#[allow(clippy::cast_possible_truncation)]
let name = Symbol::new(self.strings.len() as u32);
let string = self.arena.alloc_str(string);
let string: &'static str = unsafe { &*(string as *const str) };
self.strings.push(string);
self.names.insert(string, name);
name
}
pub fn get(&self, symbol: Symbol) -> &str {
self.strings[symbol.0.as_usize()]
}
}
pub mod keywords {
use crate::symbol::{Symbol, SymbolIndex};
pub(super) static EMPTY_SYMBOL_STR: &str = " ";
pub const EMPTY_SYMBOL: Symbol = Symbol(SymbolIndex(0));
pub(super) static FLOW_STR: &str = "flow";
pub const FLOW: Symbol = Symbol(SymbolIndex(1));
pub(super) static POTENTIAL_STR: &str = "potential";
pub const POTENTIAL: Symbol = Symbol(SymbolIndex(2));
pub(super) static TEMPERATURE_STR: &str = "$temperature";
pub const TEMPERATURE: Symbol = Symbol(SymbolIndex(3));
pub(super) static ABSTOL_STR: &str = "abstol";
pub const ABSTOL: Symbol = Symbol(SymbolIndex(4));
pub(super) static ACCESS_STR: &str = "access";
pub const ACCESS: Symbol = Symbol(SymbolIndex(5));
pub(super) static UNITS_STR: &str = "units";
pub const UNITS: Symbol = Symbol(SymbolIndex(6));
pub(super) static IDT_NATURE_STR: &str = "idt_nature";
pub const IDT_NATURE: Symbol = Symbol(SymbolIndex(7));
pub(super) static DDT_NATURE_STR: &str = "ddt_nature";
pub const DDT_NATURE: Symbol = Symbol(SymbolIndex(8));
pub(super) static DESC_STR: &str = "desc";
pub const DESC: Symbol = Symbol(SymbolIndex(9));
pub(super) static IMPLICIT_SOLVER_STR: &str = "ImplicitFunctionSolver";
pub const IMPLICIT_SOLVER: Symbol = Symbol(SymbolIndex(9));
}
mod statics {
#![allow(clippy::wildcard_imports)]
use parking_lot::Mutex;
use crate::symbol::keywords::*;
use crate::symbol::Interner;
lazy_static! {
static ref INTERNER: Mutex<Interner> = Mutex::new(Interner::prefill(&[
EMPTY_SYMBOL_STR,
FLOW_STR,
POTENTIAL_STR,
TEMPERATURE_STR,
ABSTOL_STR,
ACCESS_STR,
UNITS_STR,
IDT_NATURE_STR,
DDT_NATURE_STR,
IMPLICIT_SOLVER_STR,
DESC_STR
]));
}
#[inline]
pub(super) fn with_interner<T, F: FnOnce(&mut Interner) -> T>(f: F) -> T {
f(&mut *INTERNER.lock())
}
}
#[derive(Clone, Eq, PartialOrd, Ord)]
pub struct SymbolStr {
string: &'static str,
}
impl<T: std::ops::Deref<Target = str>> std::cmp::PartialEq<T> for SymbolStr {
fn eq(&self, other: &T) -> bool {
self.string == other.deref()
}
}
impl std::ops::Deref for SymbolStr {
type Target = str;
#[inline]
fn deref(&self) -> &str {
self.string
}
}
impl fmt::Debug for SymbolStr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.string, f)
}
}
impl fmt::Display for SymbolStr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.string, f)
}
}