From 47dff3765de863554ca296448555599fc50d4a8a Mon Sep 17 00:00:00 2001 From: Laurenz Date: Thu, 11 May 2023 10:50:30 +0200 Subject: [PATCH] Remove 'static bound on `World` Thanks to improvements in comemo, tracked types don't need to be 'static anymore. This means that the 'static bound on the `World` is now lifted and that the `Route` doesn't need to use unsafe code anymore to manage its lifetime. --- Cargo.lock | 6 ++--- Cargo.toml | 2 +- cli/Cargo.toml | 2 +- docs/Cargo.toml | 2 +- library/Cargo.toml | 2 +- library/src/layout/mod.rs | 4 +-- library/src/layout/par.rs | 2 +- library/src/meta/bibliography.rs | 6 ++--- library/src/meta/counter.rs | 2 +- library/src/meta/state.rs | 2 +- library/src/text/shaping.rs | 4 +-- library/src/visualize/image.rs | 2 +- src/diag.rs | 4 +-- src/eval/func.rs | 4 +-- src/eval/library.rs | 2 +- src/eval/mod.rs | 43 ++++++++++++++++++++------------ src/image.rs | 6 ++--- src/lib.rs | 2 +- src/model/mod.rs | 10 ++++---- tests/Cargo.toml | 2 +- 20 files changed, 59 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ec4d60ef1..9235c7b6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -369,8 +369,7 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "comemo" version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba423e212681b51c5452a458bb24e88165f4c09857a783c802719cc46313f3f" +source = "git+https://github.com/typst/comemo#0c141bbe47ca2d8c123fffc3f7f1ce35bb693993" dependencies = [ "comemo-macros", "siphasher", @@ -379,8 +378,7 @@ dependencies = [ [[package]] name = "comemo-macros" version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fca5ceeb99665bad04a32fe297d1581a68685e36fb6da92a1c9b7d9693638c01" +source = "git+https://github.com/typst/comemo#0c141bbe47ca2d8c123fffc3f7f1ce35bb693993" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index f604a442d..570b0b79e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ bench = false typst-macros = { path = "macros" } bitflags = { version = "2", features = ["serde"] } bytemuck = "1" -comemo = "0.2.2" +comemo = { git = "https://github.com/typst/comemo" } ecow = "0.1" flate2 = "1" fontdb = "0.13" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 73cbe3f6d..a6ebdd969 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -25,7 +25,7 @@ typst-library = { path = "../library" } chrono = { version = "0.4", default-features = false, features = ["clock", "std"] } clap = { version = "4.2.4", features = ["derive", "env"] } codespan-reporting = "0.11" -comemo = "0.2.2" +comemo = { git = "https://github.com/typst/comemo" } dirs = "5" elsa = "1.8" inferno = "0.11.15" diff --git a/docs/Cargo.toml b/docs/Cargo.toml index a87ca340b..df6a42e3a 100644 --- a/docs/Cargo.toml +++ b/docs/Cargo.toml @@ -13,7 +13,7 @@ bench = false [dependencies] typst = { path = ".." } typst-library = { path = "../library" } -comemo = "0.2.2" +comemo = { git = "https://github.com/typst/comemo" } heck = "0.4" include_dir = "0.7" once_cell = "1" diff --git a/library/Cargo.toml b/library/Cargo.toml index c21df83c7..d094c7ead 100644 --- a/library/Cargo.toml +++ b/library/Cargo.toml @@ -19,7 +19,7 @@ bench = false typst = { path = ".." } az = "1.2" chinese-number = { version = "0.7.2", default-features = false, features = ["number-to-chinese"] } -comemo = "0.2.2" +comemo = { git = "https://github.com/typst/comemo" } csv = "1" ecow = "0.1" hayagriva = "0.3" diff --git a/library/src/layout/mod.rs b/library/src/layout/mod.rs index 250144986..adfc433a2 100644 --- a/library/src/layout/mod.rs +++ b/library/src/layout/mod.rs @@ -73,7 +73,7 @@ impl LayoutRoot for Content { #[comemo::memoize] fn cached( content: &Content, - world: Tracked, + world: Tracked, tracer: TrackedMut, provider: TrackedMut, introspector: Tracked, @@ -139,7 +139,7 @@ impl Layout for Content { #[comemo::memoize] fn cached( content: &Content, - world: Tracked, + world: Tracked, tracer: TrackedMut, provider: TrackedMut, introspector: Tracked, diff --git a/library/src/layout/par.rs b/library/src/layout/par.rs index 0c3a9a3c5..c7bc5359c 100644 --- a/library/src/layout/par.rs +++ b/library/src/layout/par.rs @@ -139,7 +139,7 @@ impl ParElem { #[allow(clippy::too_many_arguments)] fn cached( par: &ParElem, - world: Tracked, + world: Tracked, tracer: TrackedMut, provider: TrackedMut, introspector: Tracked, diff --git a/library/src/meta/bibliography.rs b/library/src/meta/bibliography.rs index c3046dfce..cdb6a5d69 100644 --- a/library/src/meta/bibliography.rs +++ b/library/src/meta/bibliography.rs @@ -121,7 +121,7 @@ impl BibliographyElem { /// Find all bibliography keys. pub fn keys( - world: Tracked, + world: Tracked, introspector: Tracked, ) -> Vec<(EcoString, Option)> { Self::find(introspector) @@ -426,7 +426,7 @@ impl Works { /// Generate all citations and the whole bibliography. #[comemo::memoize] fn create( - world: Tracked, + world: Tracked, bibliography: BibliographyElem, citations: Vec, ) -> Arc { @@ -582,7 +582,7 @@ fn create( /// Load bibliography entries from a path. #[comemo::memoize] fn load( - world: Tracked, + world: Tracked, paths: &BibPaths, ) -> StrResult> { let mut result = EcoVec::new(); diff --git a/library/src/meta/counter.rs b/library/src/meta/counter.rs index 394c46560..50a097afa 100644 --- a/library/src/meta/counter.rs +++ b/library/src/meta/counter.rs @@ -405,7 +405,7 @@ impl Counter { #[comemo::memoize] fn sequence_impl( &self, - world: Tracked, + world: Tracked, tracer: TrackedMut, provider: TrackedMut, introspector: Tracked, diff --git a/library/src/meta/state.rs b/library/src/meta/state.rs index 71c651259..b466bd664 100644 --- a/library/src/meta/state.rs +++ b/library/src/meta/state.rs @@ -320,7 +320,7 @@ impl State { #[comemo::memoize] fn sequence_impl( &self, - world: Tracked, + world: Tracked, tracer: TrackedMut, provider: TrackedMut, introspector: Tracked, diff --git a/library/src/text/shaping.rs b/library/src/text/shaping.rs index 7d5703bc2..e670d0d11 100644 --- a/library/src/text/shaping.rs +++ b/library/src/text/shaping.rs @@ -448,8 +448,8 @@ impl Debug for ShapedText<'_> { } /// Holds shaping results and metadata common to all shaped segments. -struct ShapingContext<'a> { - vt: &'a Vt<'a>, +struct ShapingContext<'a, 'v> { + vt: &'a Vt<'v>, spans: &'a SpanMapper, glyphs: Vec, used: Vec, diff --git a/library/src/visualize/image.rs b/library/src/visualize/image.rs index 69eaa5bdc..917f483ec 100644 --- a/library/src/visualize/image.rs +++ b/library/src/visualize/image.rs @@ -165,7 +165,7 @@ pub enum ImageFit { /// Load an image from a path. #[comemo::memoize] fn load( - world: Tracked, + world: Tracked, full: &str, fallback_family: Option<&str>, alt: Option, diff --git a/src/diag.rs b/src/diag.rs index 556d32557..a122fe1f7 100644 --- a/src/diag.rs +++ b/src/diag.rs @@ -130,13 +130,13 @@ impl Display for Tracepoint { /// Enrich a [`SourceResult`] with a tracepoint. pub trait Trace { /// Add the tracepoint to all errors that lie outside the `span`. - fn trace(self, world: Tracked, make_point: F, span: Span) -> Self + fn trace(self, world: Tracked, make_point: F, span: Span) -> Self where F: Fn() -> Tracepoint; } impl Trace for SourceResult { - fn trace(self, world: Tracked, make_point: F, span: Span) -> Self + fn trace(self, world: Tracked, make_point: F, span: Span) -> Self where F: Fn() -> Tracepoint, { diff --git a/src/eval/func.rs b/src/eval/func.rs index 51eba564e..060e72cfb 100644 --- a/src/eval/func.rs +++ b/src/eval/func.rs @@ -4,7 +4,7 @@ use std::fmt::{self, Debug, Formatter}; use std::hash::{Hash, Hasher}; use std::sync::Arc; -use comemo::{Prehashed, Track, Tracked, TrackedMut}; +use comemo::{Prehashed, Tracked, TrackedMut}; use ecow::eco_format; use once_cell::sync::Lazy; @@ -317,7 +317,7 @@ impl Closure { #[allow(clippy::too_many_arguments)] fn call( this: &Func, - world: Tracked, + world: Tracked, route: Tracked, tracer: TrackedMut, provider: TrackedMut, diff --git a/src/eval/library.rs b/src/eval/library.rs index 25f715f8b..0067bf571 100644 --- a/src/eval/library.rs +++ b/src/eval/library.rs @@ -67,7 +67,7 @@ pub struct LangItems { /// The keys contained in the bibliography and short descriptions of them. #[allow(clippy::type_complexity)] pub bibliography_keys: fn( - world: Tracked, + world: Tracked, introspector: Tracked, ) -> Vec<(EcoString, Option)>, /// A section heading: `= Introduction`. diff --git a/src/eval/mod.rs b/src/eval/mod.rs index a837c9e02..958225307 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -41,7 +41,7 @@ use std::collections::HashSet; use std::mem; use std::path::{Path, PathBuf}; -use comemo::{Track, Tracked, TrackedMut}; +use comemo::{Track, Tracked, TrackedMut, Validate}; use ecow::{EcoString, EcoVec}; use unicode_segmentation::UnicodeSegmentation; @@ -67,7 +67,7 @@ const MAX_CALL_DEPTH: usize = 64; #[comemo::memoize] #[tracing::instrument(skip(world, route, tracer, source))] pub fn eval( - world: Tracked, + world: Tracked, route: Tracked, tracer: TrackedMut, source: &Source, @@ -84,7 +84,7 @@ pub fn eval( set_lang_items(library.items.clone()); // Evaluate the module. - let route = unsafe { Route::insert(route, id) }; + let route = Route::insert(route, id); let scopes = Scopes::new(Some(library)); let mut provider = StabilityProvider::new(); let introspector = Introspector::new(&[]); @@ -117,7 +117,7 @@ pub fn eval( /// Everything in the output is associated with the given `span`. #[comemo::memoize] pub fn eval_string( - world: Tracked, + world: Tracked, code: &str, span: Span, ) -> SourceResult { @@ -164,7 +164,7 @@ pub struct Vm<'a> { /// The language items. items: LangItems, /// The route of source ids the VM took to reach its current location. - route: Tracked<'a, Route>, + route: Tracked<'a, Route<'a>>, /// The current location. location: SourceId, /// A control flow event that is currently happening. @@ -200,7 +200,7 @@ impl<'a> Vm<'a> { } /// Access the underlying world. - pub fn world(&self) -> Tracked<'a, dyn World> { + pub fn world(&self) -> Tracked<'a, dyn World + 'a> { self.vt.world } @@ -263,34 +263,45 @@ impl Flow { /// A route of source ids. #[derive(Default)] -pub struct Route { - parent: Option>, +pub struct Route<'a> { + // We need to override the constraint's lifetime here so that `Tracked` is + // covariant over the constraint. If it becomes invariant, we're in for a + // world of lifetime pain. + outer: Option as Validate>::Constraint>>, id: Option, } -impl Route { +impl<'a> Route<'a> { /// Create a new route with just one entry. pub fn new(id: SourceId) -> Self { - Self { id: Some(id), parent: None } + Self { id: Some(id), outer: None } } /// Insert a new id into the route. /// /// You must guarantee that `outer` lives longer than the resulting /// route is ever used. - unsafe fn insert(outer: Tracked, id: SourceId) -> Route { - Route { - parent: Some(std::mem::transmute(outer)), - id: Some(id), + pub fn insert(outer: Tracked<'a, Self>, id: SourceId) -> Self { + Route { outer: Some(outer), id: Some(id) } + } + + /// Start tracking this locator. + /// + /// In comparison to [`Track::track`], this method skips this chain link + /// if it does not contribute anything. + pub fn track(&self) -> Tracked<'_, Self> { + match self.outer { + Some(outer) if self.id.is_none() => outer, + _ => Track::track(self), } } } #[comemo::track] -impl Route { +impl<'a> Route<'a> { /// Whether the given id is part of the route. fn contains(&self, id: SourceId) -> bool { - self.id == Some(id) || self.parent.map_or(false, |parent| parent.contains(id)) + self.id == Some(id) || self.outer.map_or(false, |outer| outer.contains(id)) } } diff --git a/src/image.rs b/src/image.rs index d78c74285..f99745990 100644 --- a/src/image.rs +++ b/src/image.rs @@ -53,7 +53,7 @@ impl Image { pub fn with_fonts( data: Buffer, format: ImageFormat, - world: Tracked, + world: Tracked, fallback_family: Option<&str>, alt: Option, ) -> StrResult { @@ -240,7 +240,7 @@ fn decode_svg(data: &Buffer) -> StrResult> { #[comemo::memoize] fn decode_svg_with_fonts( data: &Buffer, - world: Tracked, + world: Tracked, fallback_family: Option<&str>, ) -> StrResult> { let mut opts = usvg::Options::default(); @@ -269,7 +269,7 @@ fn decode_svg_with_fonts( /// Discover and load the fonts referenced by an SVG. fn load_svg_fonts( tree: &usvg::Tree, - world: Tracked, + world: Tracked, fallback_family: Option<&str>, ) -> fontdb::Database { let mut referenced = BTreeMap::::new(); diff --git a/src/lib.rs b/src/lib.rs index 4a5f0c150..f54bf0adf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,7 +65,7 @@ use crate::util::Buffer; /// Compile a source file into a fully layouted document. #[tracing::instrument(skip(world))] -pub fn compile(world: &(dyn World + 'static)) -> SourceResult { +pub fn compile(world: &dyn World) -> SourceResult { // Evaluate the source file into a module. let route = Route::default(); let mut tracer = Tracer::default(); diff --git a/src/model/mod.rs b/src/model/mod.rs index 4ec7311a9..92c4293b2 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -14,7 +14,7 @@ pub use self::styles::*; pub use typst_macros::element; -use comemo::{Constraint, Track, Tracked, TrackedMut}; +use comemo::{Track, Tracked, TrackedMut, Validate}; use crate::diag::SourceResult; use crate::doc::Document; @@ -25,7 +25,7 @@ use crate::World; #[comemo::memoize] #[tracing::instrument(skip(world, tracer, content))] pub fn typeset( - world: Tracked, + world: Tracked, mut tracer: TrackedMut, content: &Content, ) -> SourceResult { @@ -42,8 +42,8 @@ pub fn typeset( loop { tracing::info!("Layout iteration {iter}"); - let constraint = Constraint::new(); let mut provider = StabilityProvider::new(); + let constraint = ::Constraint::new(); let mut vt = Vt { world, tracer: TrackedMut::reborrow_mut(&mut tracer), @@ -56,7 +56,7 @@ pub fn typeset( introspector = Introspector::new(&document.pages); - if iter >= 5 || introspector.valid(&constraint) { + if iter >= 5 || introspector.validate(&constraint) { break; } } @@ -69,7 +69,7 @@ pub fn typeset( /// Holds the state needed to [typeset] content. pub struct Vt<'a> { /// The compilation environment. - pub world: Tracked<'a, dyn World>, + pub world: Tracked<'a, dyn World + 'a>, /// The tracer for inspection of the values an expression produces. pub tracer: TrackedMut<'a, Tracer>, /// Provides stable identities to elements. diff --git a/tests/Cargo.toml b/tests/Cargo.toml index c544f7cf1..7d7823b95 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -9,7 +9,7 @@ publish = false [dev-dependencies] typst = { path = ".." } typst-library = { path = "../library" } -comemo = "0.2.2" +comemo = { git = "https://github.com/typst/comemo" } elsa = "1.8" iai = { git = "https://github.com/reknih/iai" } once_cell = "1"