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