Skip to main content

rexlang_engine/libraries/
types.rs

1use std::collections::{HashMap, HashSet};
2use std::fmt;
3use std::path::{Path, PathBuf};
4
5use rexlang_ast::expr::{Symbol, intern};
6use rexlang_typesystem::Type;
7
8use crate::Pointer;
9
10#[derive(Clone, Debug, PartialEq, Eq, Hash)]
11pub enum LibraryId {
12    Local { path: PathBuf },
13    Remote(String),
14    Virtual(String),
15}
16
17impl fmt::Display for LibraryId {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        match self {
20            LibraryId::Local { path } => write!(f, "file:{}", path.display()),
21            LibraryId::Remote(url) => write!(f, "{url}"),
22            LibraryId::Virtual(name) => write!(f, "virtual:{name}"),
23        }
24    }
25}
26
27#[derive(Clone, Debug)]
28pub struct ResolveRequest {
29    pub library_name: String,
30    pub importer: Option<LibraryId>,
31}
32
33#[derive(Clone, Debug)]
34pub struct ResolvedLibrary {
35    pub id: LibraryId,
36    pub source: String,
37}
38
39#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
40pub struct LibraryKey(u64);
41
42impl LibraryKey {
43    pub fn as_u64(self) -> u64 {
44        self.0
45    }
46}
47
48#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
49pub enum SymbolKind {
50    Value,
51    Type,
52    Class,
53}
54
55#[derive(Clone, Debug, PartialEq, Eq, Hash)]
56pub struct CanonicalSymbol {
57    pub library: LibraryKey,
58    pub kind: SymbolKind,
59    pub local: Symbol,
60    symbol: Symbol,
61}
62
63impl CanonicalSymbol {
64    pub fn new(library: LibraryKey, kind: SymbolKind, local: Symbol) -> Self {
65        let symbol = intern(&format!(
66            "{}.{}",
67            prefix_for_library_key(library),
68            local.as_ref()
69        ));
70        Self {
71            library,
72            kind,
73            local,
74            symbol,
75        }
76    }
77
78    pub fn from_symbol(
79        library: LibraryKey,
80        kind: SymbolKind,
81        local: Symbol,
82        symbol: Symbol,
83    ) -> Self {
84        Self {
85            library,
86            kind,
87            local,
88            symbol,
89        }
90    }
91
92    pub fn symbol(&self) -> &Symbol {
93        &self.symbol
94    }
95}
96
97#[derive(Clone)]
98pub struct LibraryExports {
99    pub values: HashMap<Symbol, CanonicalSymbol>,
100    pub types: HashMap<Symbol, CanonicalSymbol>,
101    pub classes: HashMap<Symbol, CanonicalSymbol>,
102}
103
104#[derive(Clone, Default)]
105pub struct ReplState {
106    pub(crate) alias_exports: HashMap<Symbol, LibraryExports>,
107    pub(crate) imported_values: HashMap<Symbol, CanonicalSymbol>,
108    pub(crate) defined_values: HashSet<Symbol>,
109    pub(crate) importer_path: Option<PathBuf>,
110}
111
112impl ReplState {
113    pub fn new() -> Self {
114        Self::default()
115    }
116
117    pub fn with_importer_path(path: impl AsRef<Path>) -> Self {
118        Self {
119            importer_path: Some(path.as_ref().to_path_buf()),
120            ..Self::default()
121        }
122    }
123}
124
125#[derive(Clone)]
126pub struct LibraryInstance {
127    pub id: LibraryId,
128    pub exports: LibraryExports,
129    pub init_value: Pointer,
130    pub init_type: Type,
131    pub source_fingerprint: Option<String>,
132}
133
134pub(crate) fn library_key_for_library(id: &LibraryId) -> LibraryKey {
135    // Use a stable hash over stable identity bytes so canonical internal symbols
136    // are deterministic across process runs/toolchains.
137    // FNV-1a reference:
138    // - Fowler, Noll, Vo hash function (public domain), 64-bit variant.
139    let mut hash: u64 = 0xcbf29ce484222325;
140    hash_library_identity(&mut hash, id);
141    LibraryKey(hash)
142}
143
144fn hash_library_identity(state: &mut u64, id: &LibraryId) {
145    fn hash_bytes(state: &mut u64, bytes: &[u8]) {
146        for b in bytes {
147            *state ^= u64::from(*b);
148            *state = state.wrapping_mul(0x0000_0100_0000_01B3);
149        }
150    }
151
152    match id {
153        LibraryId::Local { path } => {
154            hash_bytes(state, b"local:");
155            hash_bytes(state, path.as_os_str().as_encoded_bytes());
156        }
157        LibraryId::Remote(url) => {
158            hash_bytes(state, b"remote:");
159            hash_bytes(state, url.as_bytes());
160        }
161        LibraryId::Virtual(name) => {
162            hash_bytes(state, b"virtual:");
163            hash_bytes(state, name.as_bytes());
164        }
165    }
166}
167
168pub(crate) fn prefix_for_library_key(key: LibraryKey) -> String {
169    format!("@m{:016x}", key.as_u64())
170}
171
172pub(crate) fn prefix_for_library(id: &LibraryId) -> String {
173    prefix_for_library_key(library_key_for_library(id))
174}
175
176pub(crate) fn qualify(prefix: &str, name: &Symbol) -> Symbol {
177    intern(&format!("{prefix}.{}", name.as_ref()))
178}
179
180pub fn virtual_export_name(library: &str, export: &str) -> String {
181    let id = LibraryId::Virtual(library.to_string());
182    let key = library_key_for_library(&id);
183    CanonicalSymbol::new(key, SymbolKind::Value, intern(export))
184        .symbol()
185        .to_string()
186}