summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-11-30 18:31:56 +0100
committerLaurenz <laurmaedje@gmail.com>2023-11-30 18:31:56 +0100
commitf16a9ea9ad362b71d37774870080f5b6545e4f2f (patch)
treeee5934b5cd7086fad27e337f1b0a961b65143746
parentde40124adb3c7bd064e9dbdcb4d82db6843889c3 (diff)
Drop dependency on `DashMap`
DashMap doesn't work in multi-threaded WebAssembly in Safari: https://bugs.webkit.org/show_bug.cgi?id=265581
-rw-r--r--Cargo.lock22
-rw-r--r--Cargo.toml2
-rw-r--r--crates/typst-cli/src/world.rs2
-rw-r--r--crates/typst/Cargo.toml2
-rw-r--r--crates/typst/src/introspection/introspector.rs34
-rw-r--r--crates/typst/src/introspection/locator.rs4
-rw-r--r--crates/typst/src/util/pico.rs36
7 files changed, 58 insertions, 44 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 2dcef771..caa55d21 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -783,15 +783,6 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
-version = "0.13.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
-dependencies = [
- "ahash",
-]
-
-[[package]]
-name = "hashbrown"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
@@ -1232,17 +1223,6 @@ dependencies = [
]
[[package]]
-name = "lasso"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4644821e1c3d7a560fe13d842d13f587c07348a1a05d3a797152d41c90c56df2"
-dependencies = [
- "ahash",
- "dashmap",
- "hashbrown 0.13.2",
-]
-
-[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2644,7 +2624,6 @@ dependencies = [
"ciborium",
"comemo",
"csv",
- "dashmap",
"ecow",
"fontdb",
"hayagriva",
@@ -2657,7 +2636,6 @@ dependencies = [
"image",
"indexmap 2.1.0",
"kurbo",
- "lasso",
"lipsum",
"log",
"once_cell",
diff --git a/Cargo.toml b/Cargo.toml
index 2aca6f18..913d875b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -38,7 +38,6 @@ clap_mangen = "0.2.10"
codespan-reporting = "0.11"
comemo = "0.3.1"
csv = "1"
-dashmap = "5.5"
dirs = "5"
ecow = { version = "0.2", features = ["serde"] }
env_proxy = "0.4"
@@ -59,7 +58,6 @@ include_dir = "0.7"
indexmap = { version = "2", features = ["serde"] }
inferno = "0.11.15"
kurbo = "0.9"
-lasso = { version = "0.7.2", features = ["ahasher", "multi-threaded"] }
lipsum = "0.9"
log = "0.4"
miniz_oxide = "0.7"
diff --git a/crates/typst-cli/src/world.rs b/crates/typst-cli/src/world.rs
index f375c648..99456679 100644
--- a/crates/typst-cli/src/world.rs
+++ b/crates/typst-cli/src/world.rs
@@ -111,7 +111,7 @@ impl SystemWorld {
/// Reset the compilation state in preparation of a new compilation.
pub fn reset(&mut self) {
- for slot in self.slots.borrow_mut().values_mut() {
+ for slot in self.slots.get_mut().values_mut() {
slot.reset();
}
self.now.take();
diff --git a/crates/typst/Cargo.toml b/crates/typst/Cargo.toml
index 93cdfd8a..af90a1d8 100644
--- a/crates/typst/Cargo.toml
+++ b/crates/typst/Cargo.toml
@@ -24,7 +24,6 @@ chinese-number = { workspace = true }
ciborium = { workspace = true }
comemo = { workspace = true }
csv = { workspace = true }
-dashmap = { workspace = true }
ecow = { workspace = true}
fontdb = { workspace = true }
hayagriva = { workspace = true }
@@ -37,7 +36,6 @@ icu_segmenter = { workspace = true }
image = { workspace = true }
indexmap = { workspace = true }
kurbo = { workspace = true }
-lasso = { workspace = true }
lipsum = { workspace = true }
log = { workspace = true }
once_cell = { workspace = true }
diff --git a/crates/typst/src/introspection/introspector.rs b/crates/typst/src/introspection/introspector.rs
index ff9d6c64..bbf43472 100644
--- a/crates/typst/src/introspection/introspector.rs
+++ b/crates/typst/src/introspection/introspector.rs
@@ -2,9 +2,9 @@ use std::collections::{BTreeSet, HashMap};
use std::fmt::{self, Debug, Formatter};
use std::hash::Hash;
use std::num::NonZeroUsize;
+use std::sync::RwLock;
use comemo::Prehashed;
-use dashmap::DashMap;
use ecow::{eco_format, EcoVec};
use indexmap::IndexMap;
use smallvec::SmallVec;
@@ -32,7 +32,7 @@ pub struct Introspector {
/// even if all top-level queries are distinct, they often have shared
/// subqueries. Example: Individual counter queries with `before` that
/// all depend on a global counter query.
- queries: DashMap<u128, EcoVec<Prehashed<Content>>>,
+ queries: QueryCache,
}
impl Introspector {
@@ -118,8 +118,8 @@ impl Introspector {
/// Query for all matching elements.
pub fn query(&self, selector: &Selector) -> EcoVec<Prehashed<Content>> {
let hash = crate::util::hash128(selector);
- if let Some(output) = self.queries.get(&hash) {
- return output.clone();
+ if let Some(output) = self.queries.get(hash) {
+ return output;
}
let output = match selector {
@@ -256,7 +256,7 @@ impl Default for Introspector {
elems: IndexMap::new(),
labels: HashMap::new(),
page_numberings: vec![],
- queries: DashMap::new(),
+ queries: QueryCache::default(),
}
}
}
@@ -266,3 +266,27 @@ impl Debug for Introspector {
f.pad("Introspector(..)")
}
}
+
+/// Caches queries.
+#[derive(Default)]
+struct QueryCache(RwLock<HashMap<u128, EcoVec<Prehashed<Content>>>>);
+
+impl QueryCache {
+ fn get(&self, hash: u128) -> Option<EcoVec<Prehashed<Content>>> {
+ self.0.read().unwrap().get(&hash).cloned()
+ }
+
+ fn insert(&self, hash: u128, output: EcoVec<Prehashed<Content>>) {
+ self.0.write().unwrap().insert(hash, output);
+ }
+
+ fn clear(&mut self) {
+ self.0.get_mut().unwrap().clear();
+ }
+}
+
+impl Clone for QueryCache {
+ fn clone(&self) -> Self {
+ Self(RwLock::new(self.0.read().unwrap().clone()))
+ }
+}
diff --git a/crates/typst/src/introspection/locator.rs b/crates/typst/src/introspection/locator.rs
index c9c34b9c..586f841d 100644
--- a/crates/typst/src/introspection/locator.rs
+++ b/crates/typst/src/introspection/locator.rs
@@ -66,7 +66,7 @@ impl<'a> Locator<'a> {
let disambiguator = self.disambiguator_impl(hash);
// Bump the next disambiguator up by one.
- self.hashes.borrow_mut().insert(hash, disambiguator + 1);
+ self.hashes.get_mut().insert(hash, disambiguator + 1);
// Create the location in its default variant.
Location { hash, disambiguator, variant: 0 }
@@ -78,7 +78,7 @@ impl<'a> Locator<'a> {
match item {
FrameItem::Group(group) => self.visit_frame(&group.frame),
FrameItem::Meta(Meta::Elem(elem), _) => {
- let mut hashes = self.hashes.borrow_mut();
+ let hashes = self.hashes.get_mut();
let loc = elem.location().unwrap();
let entry = hashes.entry(loc.hash).or_default();
diff --git a/crates/typst/src/util/pico.rs b/crates/typst/src/util/pico.rs
index 9b0e46f1..827d6b5b 100644
--- a/crates/typst/src/util/pico.rs
+++ b/crates/typst/src/util/pico.rs
@@ -1,13 +1,21 @@
+use std::collections::HashMap;
use std::fmt::{self, Debug, Formatter};
+use std::sync::RwLock;
use ecow::EcoString;
-use lasso::{Spur, ThreadedRodeo};
use once_cell::sync::Lazy;
use crate::foundations::cast;
/// The global string interner.
-static INTERNER: Lazy<ThreadedRodeo> = Lazy::new(ThreadedRodeo::new);
+static INTERNER: Lazy<RwLock<Interner>> =
+ Lazy::new(|| RwLock::new(Interner { to_id: HashMap::new(), from_id: Vec::new() }));
+
+/// A string interner.
+struct Interner {
+ to_id: HashMap<&'static str, PicoStr>,
+ from_id: Vec<&'static str>,
+}
/// An interned string.
///
@@ -16,22 +24,30 @@ static INTERNER: Lazy<ThreadedRodeo> = Lazy::new(ThreadedRodeo::new);
/// unnecessarily. For this reason, the user should use the [`PicoStr::resolve`]
/// method to get the underlying string, such that the lookup is done only once.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
-pub struct PicoStr(Spur);
+pub struct PicoStr(u32);
impl PicoStr {
/// Creates a new interned string.
- pub fn new(s: impl AsRef<str>) -> Self {
- Self(INTERNER.get_or_intern(s.as_ref()))
- }
+ pub fn new(string: &str) -> Self {
+ if let Some(&id) = INTERNER.read().unwrap().to_id.get(string) {
+ return id;
+ }
+
+ let mut interner = INTERNER.write().unwrap();
+ let num = interner.from_id.len().try_into().expect("out of string ids");
- /// Creates a new interned string from a static string.
- pub fn static_(s: &'static str) -> Self {
- Self(INTERNER.get_or_intern_static(s))
+ // Create a new entry forever by leaking the string. PicoStr is only
+ // used for strings that aren't created en masse, so it is okay.
+ let id = Self(num);
+ let string = Box::leak(string.to_string().into_boxed_str());
+ interner.to_id.insert(string, id);
+ interner.from_id.push(string);
+ id
}
/// Resolves the interned string.
pub fn resolve(&self) -> &'static str {
- INTERNER.resolve(&self.0)
+ INTERNER.read().unwrap().from_id[self.0 as usize]
}
}