From 20b1a38414101f842a6d9201133a5aaaa45a7cec Mon Sep 17 00:00:00 2001 From: Laurenz Date: Mon, 31 Jan 2022 16:06:44 +0100 Subject: [PATCH] Switch from `Rc` to `Arc` --- src/eval/array.rs | 26 ++++++++++++------------- src/eval/capture.rs | 4 ++-- src/eval/dict.rs | 24 +++++++++++------------ src/eval/function.rs | 12 ++++++------ src/eval/node.rs | 4 ++-- src/eval/scope.rs | 8 ++++---- src/eval/styles.rs | 12 ++++++------ src/eval/value.rs | 16 +++++++-------- src/export/pdf.rs | 8 ++++---- src/font.rs | 20 +++++++++---------- src/frame.rs | 10 +++++----- src/image.rs | 6 +++--- src/layout/constraints.rs | 8 ++++---- src/layout/incremental.rs | 14 ++++++------- src/layout/mod.rs | 41 ++++++++++++++++++--------------------- src/lib.rs | 16 +++++++-------- src/library/align.rs | 4 ++-- src/library/columns.rs | 2 +- src/library/flow.rs | 10 +++++----- src/library/grid.rs | 6 +++--- src/library/heading.rs | 4 ++-- src/library/hidden.rs | 4 ++-- src/library/image.rs | 2 +- src/library/link.rs | 5 +++-- src/library/list.rs | 4 ++-- src/library/mod.rs | 2 +- src/library/pad.rs | 4 ++-- src/library/page.rs | 2 +- src/library/par.rs | 14 ++++++------- src/library/place.rs | 4 ++-- src/library/shape.rs | 6 +++--- src/library/stack.rs | 8 ++++---- src/library/table.rs | 2 +- src/library/text.rs | 6 +++--- src/library/transform.rs | 6 +++--- src/loading/fs.rs | 8 ++++---- src/loading/mem.rs | 8 ++++---- src/parse/incremental.rs | 8 ++++---- src/parse/mod.rs | 4 ++-- src/parse/tokens.rs | 12 ++++++------ src/source.rs | 10 +++++----- src/syntax/mod.rs | 18 ++++++++--------- src/util/eco_string.rs | 32 +++++++++++++++++------------- src/util/mod.rs | 8 ++++---- tests/typeset.rs | 8 ++++---- 45 files changed, 222 insertions(+), 218 deletions(-) diff --git a/src/eval/array.rs b/src/eval/array.rs index 912aa3c04..45f6fcc7c 100644 --- a/src/eval/array.rs +++ b/src/eval/array.rs @@ -3,11 +3,11 @@ use std::convert::TryFrom; use std::fmt::{self, Debug, Formatter, Write}; use std::iter::FromIterator; use std::ops::{Add, AddAssign}; -use std::rc::Rc; +use std::sync::Arc; use super::Value; use crate::diag::StrResult; -use crate::util::RcExt; +use crate::util::ArcExt; /// Create a new [`Array`] from values. #[allow(unused_macros)] @@ -23,7 +23,7 @@ macro_rules! array { /// An array of values with clone-on-write value semantics. #[derive(Default, Clone, PartialEq)] -pub struct Array(Rc>); +pub struct Array(Arc>); impl Array { /// Create a new, empty array. @@ -33,7 +33,7 @@ impl Array { /// Create a new array from a vector of values. pub fn from_vec(vec: Vec) -> Self { - Self(Rc::new(vec)) + Self(Arc::new(vec)) } /// Whether the array is empty. @@ -59,19 +59,19 @@ impl Array { let len = self.len(); usize::try_from(index) .ok() - .and_then(move |i| Rc::make_mut(&mut self.0).get_mut(i)) + .and_then(move |i| Arc::make_mut(&mut self.0).get_mut(i)) .ok_or_else(|| out_of_bounds(index, len)) } /// Push a value to the end of the array. pub fn push(&mut self, value: Value) { - Rc::make_mut(&mut self.0).push(value); + Arc::make_mut(&mut self.0).push(value); } /// Clear the array. pub fn clear(&mut self) { - if Rc::strong_count(&self.0) == 1 { - Rc::make_mut(&mut self.0).clear(); + if Arc::strong_count(&self.0) == 1 { + Arc::make_mut(&mut self.0).clear(); } else { *self = Self::new(); } @@ -87,7 +87,7 @@ impl Array { /// Returns an error if two values could not be compared. pub fn sorted(mut self) -> StrResult { let mut result = Ok(()); - Rc::make_mut(&mut self.0).sort_by(|a, b| { + Arc::make_mut(&mut self.0).sort_by(|a, b| { a.partial_cmp(b).unwrap_or_else(|| { if result.is_ok() { result = Err(format!( @@ -146,7 +146,7 @@ impl Add for Array { impl AddAssign for Array { fn add_assign(&mut self, rhs: Array) { - match Rc::try_unwrap(rhs.0) { + match Arc::try_unwrap(rhs.0) { Ok(vec) => self.extend(vec), Err(rc) => self.extend(rc.iter().cloned()), } @@ -155,13 +155,13 @@ impl AddAssign for Array { impl Extend for Array { fn extend>(&mut self, iter: T) { - Rc::make_mut(&mut self.0).extend(iter); + Arc::make_mut(&mut self.0).extend(iter); } } impl FromIterator for Array { fn from_iter>(iter: T) -> Self { - Self(Rc::new(iter.into_iter().collect())) + Self(Arc::new(iter.into_iter().collect())) } } @@ -170,7 +170,7 @@ impl IntoIterator for Array { type IntoIter = std::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { - Rc::take(self.0).into_iter() + Arc::take(self.0).into_iter() } } diff --git a/src/eval/capture.rs b/src/eval/capture.rs index e47831dfd..8585776a0 100644 --- a/src/eval/capture.rs +++ b/src/eval/capture.rs @@ -1,4 +1,4 @@ -use std::rc::Rc; +use std::sync::Arc; use super::{Scope, Scopes, Value}; use crate::syntax::ast::{ClosureParam, Expr, Ident, Imports, TypedNode}; @@ -35,7 +35,7 @@ impl<'a> CapturesVisitor<'a> { pub fn capture(&mut self, ident: Ident) { if self.internal.get(&ident).is_none() { if let Some(slot) = self.external.get(&ident) { - self.captures.def_slot(ident.take(), Rc::clone(slot)); + self.captures.def_slot(ident.take(), Arc::clone(slot)); } } } diff --git a/src/eval/dict.rs b/src/eval/dict.rs index 0d7198e1e..2ce3c3f90 100644 --- a/src/eval/dict.rs +++ b/src/eval/dict.rs @@ -2,11 +2,11 @@ use std::collections::BTreeMap; use std::fmt::{self, Debug, Formatter, Write}; use std::iter::FromIterator; use std::ops::{Add, AddAssign}; -use std::rc::Rc; +use std::sync::Arc; use super::Value; use crate::diag::StrResult; -use crate::util::{EcoString, RcExt}; +use crate::util::{ArcExt, EcoString}; /// Create a new [`Dict`] from key-value pairs. #[allow(unused_macros)] @@ -21,7 +21,7 @@ macro_rules! dict { /// A dictionary from strings to values with clone-on-write value semantics. #[derive(Default, Clone, PartialEq)] -pub struct Dict(Rc>); +pub struct Dict(Arc>); impl Dict { /// Create a new, empty dictionary. @@ -31,7 +31,7 @@ impl Dict { /// Create a new dictionary from a mapping of strings to values. pub fn from_map(map: BTreeMap) -> Self { - Self(Rc::new(map)) + Self(Arc::new(map)) } /// Whether the dictionary is empty. @@ -54,18 +54,18 @@ impl Dict { /// This inserts the key with [`None`](Value::None) as the value if not /// present so far. pub fn get_mut(&mut self, key: EcoString) -> &mut Value { - Rc::make_mut(&mut self.0).entry(key).or_default() + Arc::make_mut(&mut self.0).entry(key).or_default() } /// Insert a mapping from the given `key` to the given `value`. pub fn insert(&mut self, key: EcoString, value: Value) { - Rc::make_mut(&mut self.0).insert(key, value); + Arc::make_mut(&mut self.0).insert(key, value); } /// Clear the dictionary. pub fn clear(&mut self) { - if Rc::strong_count(&self.0) == 1 { - Rc::make_mut(&mut self.0).clear(); + if Arc::strong_count(&self.0) == 1 { + Arc::make_mut(&mut self.0).clear(); } else { *self = Self::new(); } @@ -112,7 +112,7 @@ impl Add for Dict { impl AddAssign for Dict { fn add_assign(&mut self, rhs: Dict) { - match Rc::try_unwrap(rhs.0) { + match Arc::try_unwrap(rhs.0) { Ok(map) => self.extend(map), Err(rc) => self.extend(rc.iter().map(|(k, v)| (k.clone(), v.clone()))), } @@ -121,13 +121,13 @@ impl AddAssign for Dict { impl Extend<(EcoString, Value)> for Dict { fn extend>(&mut self, iter: T) { - Rc::make_mut(&mut self.0).extend(iter); + Arc::make_mut(&mut self.0).extend(iter); } } impl FromIterator<(EcoString, Value)> for Dict { fn from_iter>(iter: T) -> Self { - Self(Rc::new(iter.into_iter().collect())) + Self(Arc::new(iter.into_iter().collect())) } } @@ -136,7 +136,7 @@ impl IntoIterator for Dict { type IntoIter = std::collections::btree_map::IntoIter; fn into_iter(self) -> Self::IntoIter { - Rc::take(self.0).into_iter() + Arc::take(self.0).into_iter() } } diff --git a/src/eval/function.rs b/src/eval/function.rs index 931a90a00..0edc1e786 100644 --- a/src/eval/function.rs +++ b/src/eval/function.rs @@ -1,5 +1,5 @@ use std::fmt::{self, Debug, Formatter, Write}; -use std::rc::Rc; +use std::sync::Arc; use super::{Cast, EvalContext, Value}; use crate::diag::{At, TypResult}; @@ -8,9 +8,9 @@ use crate::util::EcoString; /// An evaluatable function. #[derive(Clone)] -pub struct Function(Rc>); +pub struct Function(Arc>); -/// The unsized structure behind the [`Rc`]. +/// The unsized structure behind the [`Arc`]. struct Inner { name: Option, func: T, @@ -24,7 +24,7 @@ impl Function { where F: Fn(&mut EvalContext, &mut Args) -> TypResult + 'static, { - Self(Rc::new(Inner { name, func })) + Self(Arc::new(Inner { name, func })) } /// The name of the function. @@ -53,8 +53,8 @@ impl PartialEq for Function { fn eq(&self, other: &Self) -> bool { // We cast to thin pointers for comparison. std::ptr::eq( - Rc::as_ptr(&self.0) as *const (), - Rc::as_ptr(&other.0) as *const (), + Arc::as_ptr(&self.0) as *const (), + Arc::as_ptr(&other.0) as *const (), ) } } diff --git a/src/eval/node.rs b/src/eval/node.rs index d909fc7d6..665550b07 100644 --- a/src/eval/node.rs +++ b/src/eval/node.rs @@ -71,7 +71,7 @@ impl Node { /// Create an inline-level node. pub fn inline(node: T) -> Self where - T: Layout + Debug + Hash + 'static, + T: Layout + Debug + Hash + Sync + Send + 'static, { Self::Inline(node.pack()) } @@ -79,7 +79,7 @@ impl Node { /// Create a block-level node. pub fn block(node: T) -> Self where - T: Layout + Debug + Hash + 'static, + T: Layout + Debug + Hash + Sync + Send + 'static, { Self::Block(node.pack()) } diff --git a/src/eval/scope.rs b/src/eval/scope.rs index 5178c8191..34da68d4a 100644 --- a/src/eval/scope.rs +++ b/src/eval/scope.rs @@ -2,14 +2,14 @@ use std::cell::RefCell; use std::collections::HashMap; use std::fmt::{self, Debug, Formatter}; use std::iter; -use std::rc::Rc; +use std::sync::Arc; use super::{Args, Class, Construct, EvalContext, Function, Set, Value}; use crate::diag::TypResult; use crate::util::EcoString; /// A slot where a variable is stored. -pub type Slot = Rc>; +pub type Slot = Arc>; /// A stack of scopes. #[derive(Debug, Default, Clone)] @@ -85,12 +85,12 @@ impl Scope { // FIXME: Use Ref::leak once stable. std::mem::forget(cell.borrow()); - self.values.insert(var.into(), Rc::new(cell)); + self.values.insert(var.into(), Arc::new(cell)); } /// Define a mutable variable with a value. pub fn def_mut(&mut self, var: impl Into, value: impl Into) { - self.values.insert(var.into(), Rc::new(RefCell::new(value.into()))); + self.values.insert(var.into(), Arc::new(RefCell::new(value.into()))); } /// Define a variable with a slot. diff --git a/src/eval/styles.rs b/src/eval/styles.rs index 508996a1c..5276353ad 100644 --- a/src/eval/styles.rs +++ b/src/eval/styles.rs @@ -1,7 +1,7 @@ use std::any::{Any, TypeId}; use std::fmt::{self, Debug, Formatter}; use std::hash::{Hash, Hasher}; -use std::rc::Rc; +use std::sync::Arc; // TODO(style): Possible optimizations: // - Ref-count map for cheaper cloning and smaller footprint @@ -334,13 +334,13 @@ impl Debug for Link<'_> { /// An entry for a single style property. #[derive(Clone)] struct Entry { - p: Rc, + p: Arc, scoped: bool, } impl Entry { fn new(key: P, value: P::Value) -> Self { - Self { p: Rc::new((key, value)), scoped: false } + Self { p: Arc::new((key, value)), scoped: false } } fn is(&self) -> bool { @@ -390,11 +390,11 @@ impl Hash for Entry { /// /// This trait is not intended to be implemented manually, but rather through /// the `#[properties]` proc-macro. -pub trait Property: Copy + 'static { +pub trait Property: Copy + Sync + Send + 'static { /// The type of value that is returned when getting this property from a /// style map. For example, this could be [`Length`](crate::geom::Length) /// for a `WIDTH` property. - type Value: Debug + Clone + PartialEq + Hash + 'static; + type Value: Debug + Clone + PartialEq + Hash + Sync + Send + 'static; /// The name of the property, used for debug printing. const NAME: &'static str; @@ -432,7 +432,7 @@ pub trait Nonfolding {} /// value types below. Although it is zero-sized, the property `P` must be part /// of the implementing type so that we can use it in the methods (it must be a /// constrained type parameter). -trait Bounds: 'static { +trait Bounds: Sync + Send + 'static { fn as_any(&self) -> &dyn Any; fn dyn_fmt(&self, f: &mut Formatter) -> fmt::Result; fn dyn_eq(&self, other: &Entry) -> bool; diff --git a/src/eval/value.rs b/src/eval/value.rs index e64f6cc6d..7d65d5af1 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -2,7 +2,7 @@ use std::any::Any; use std::cmp::Ordering; use std::fmt::{self, Debug, Formatter}; use std::hash::Hash; -use std::rc::Rc; +use std::sync::Arc; use super::{ops, Args, Array, Class, Dict, Function, Node}; use crate::diag::StrResult; @@ -58,7 +58,7 @@ impl Value { /// Create an inline-level node value. pub fn inline(node: T) -> Self where - T: Layout + Debug + Hash + 'static, + T: Layout + Debug + Hash + Sync + Send + 'static, { Self::Node(Node::inline(node)) } @@ -66,7 +66,7 @@ impl Value { /// Create a block-level node value. pub fn block(node: T) -> Self where - T: Layout + Debug + Hash + 'static, + T: Layout + Debug + Hash + Sync + Send + 'static, { Self::Node(Node::block(node)) } @@ -211,15 +211,15 @@ impl From for Value { /// A dynamic value. #[derive(Clone)] -pub struct Dynamic(Rc); +pub struct Dynamic(Arc); impl Dynamic { /// Create a new instance from any value that satisifies the required bounds. pub fn new(any: T) -> Self where - T: Type + Debug + PartialEq + 'static, + T: Type + Debug + PartialEq + Sync + Send + 'static, { - Self(Rc::new(any)) + Self(Arc::new(any)) } /// Whether the wrapped type is `T`. @@ -250,7 +250,7 @@ impl PartialEq for Dynamic { } } -trait Bounds: Debug + 'static { +trait Bounds: Debug + Sync + Send + 'static { fn as_any(&self) -> &dyn Any; fn dyn_eq(&self, other: &Dynamic) -> bool; fn dyn_type_name(&self) -> &'static str; @@ -258,7 +258,7 @@ trait Bounds: Debug + 'static { impl Bounds for T where - T: Type + Debug + PartialEq + 'static, + T: Type + Debug + PartialEq + Sync + Send + 'static, { fn as_any(&self) -> &dyn Any { self diff --git a/src/export/pdf.rs b/src/export/pdf.rs index 1477e2832..19134f992 100644 --- a/src/export/pdf.rs +++ b/src/export/pdf.rs @@ -3,7 +3,7 @@ use std::cmp::Eq; use std::collections::{BTreeMap, HashMap, HashSet}; use std::hash::Hash; -use std::rc::Rc; +use std::sync::Arc; use image::{DynamicImage, GenericImageView, ImageFormat, ImageResult, Rgba}; use pdf_writer::types::{ @@ -26,7 +26,7 @@ use crate::Context; /// included in the PDF. /// /// Returns the raw bytes making up the PDF file. -pub fn pdf(ctx: &Context, frames: &[Rc]) -> Vec { +pub fn pdf(ctx: &Context, frames: &[Arc]) -> Vec { PdfExporter::new(ctx).export(frames) } @@ -60,14 +60,14 @@ impl<'a> PdfExporter<'a> { } } - fn export(mut self, frames: &[Rc]) -> Vec { + fn export(mut self, frames: &[Arc]) -> Vec { self.build_pages(frames); self.write_fonts(); self.write_images(); self.write_structure() } - fn build_pages(&mut self, frames: &[Rc]) { + fn build_pages(&mut self, frames: &[Arc]) { for frame in frames { let page = PageExporter::new(self).export(frame); self.pages.push(page); diff --git a/src/font.rs b/src/font.rs index 674ffa63b..45cc6be25 100644 --- a/src/font.rs +++ b/src/font.rs @@ -3,7 +3,7 @@ use std::collections::{hash_map::Entry, BTreeMap, HashMap}; use std::fmt::{self, Debug, Formatter}; use std::path::{Path, PathBuf}; -use std::rc::Rc; +use std::sync::Arc; use serde::{Deserialize, Serialize}; use ttf_parser::{name_id, GlyphId, PlatformId}; @@ -33,15 +33,15 @@ impl FaceId { /// Storage for loaded and parsed font faces. pub struct FontStore { - loader: Rc, + loader: Arc, faces: Vec>, families: BTreeMap>, - buffers: HashMap>>, + buffers: HashMap>>, } impl FontStore { /// Create a new, empty font store. - pub fn new(loader: Rc) -> Self { + pub fn new(loader: Arc) -> Self { let mut faces = vec![]; let mut families = BTreeMap::>::new(); @@ -109,11 +109,11 @@ impl FontStore { Entry::Occupied(entry) => entry.into_mut(), Entry::Vacant(entry) => { let buffer = self.loader.load(path).ok()?; - entry.insert(Rc::new(buffer)) + entry.insert(Arc::new(buffer)) } }; - let face = Face::new(Rc::clone(buffer), index)?; + let face = Face::new(Arc::clone(buffer), index)?; *slot = Some(face); } @@ -147,7 +147,7 @@ pub struct Face { /// The raw face data, possibly shared with other faces from the same /// collection. Must stay alive put, because `ttf` points into it using /// unsafe code. - buffer: Rc>, + buffer: Arc>, /// The face's index in the collection (zero if not a collection). index: u32, /// The underlying ttf-parser/rustybuzz face. @@ -182,11 +182,11 @@ pub struct LineMetrics { impl Face { /// Parse a font face from a buffer and collection index. - pub fn new(buffer: Rc>, index: u32) -> Option { + pub fn new(buffer: Arc>, index: u32) -> Option { // Safety: // - The slices's location is stable in memory: // - We don't move the underlying vector - // - Nobody else can move it since we have a strong ref to the `Rc`. + // - Nobody else can move it since we have a strong ref to the `Arc`. // - The internal static lifetime is not leaked because its rewritten // to the self-lifetime in `ttf()`. let slice: &'static [u8] = @@ -238,7 +238,7 @@ impl Face { } /// The underlying buffer. - pub fn buffer(&self) -> &Rc> { + pub fn buffer(&self) -> &Arc> { &self.buffer } diff --git a/src/frame.rs b/src/frame.rs index 133ba256d..f714fbbe0 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -1,7 +1,7 @@ //! Finished layouts. use std::fmt::{self, Debug, Formatter}; -use std::rc::Rc; +use std::sync::Arc; use crate::font::FaceId; use crate::geom::{Align, Em, Length, Paint, Path, Point, Size, Spec, Transform}; @@ -43,7 +43,7 @@ impl Frame { } /// Add a group element. - pub fn push_frame(&mut self, pos: Point, frame: Rc) { + pub fn push_frame(&mut self, pos: Point, frame: Arc) { self.elements.push((pos, Element::Group(Group::new(frame)))); } @@ -100,7 +100,7 @@ impl Frame { F: FnOnce(&mut Group), { let mut wrapper = Frame { elements: vec![], ..*self }; - let mut group = Group::new(Rc::new(std::mem::take(self))); + let mut group = Group::new(Arc::new(std::mem::take(self))); f(&mut group); wrapper.push(Point::zero(), Element::Group(group)); *self = wrapper; @@ -149,7 +149,7 @@ pub enum Element { #[derive(Debug, Clone, Eq, PartialEq)] pub struct Group { /// The group's frame. - pub frame: Rc, + pub frame: Arc, /// A transformation to apply to the group. pub transform: Transform, /// Whether the frame should be a clipping boundary. @@ -158,7 +158,7 @@ pub struct Group { impl Group { /// Create a new group with default settings. - pub fn new(frame: Rc) -> Self { + pub fn new(frame: Arc) -> Self { Self { frame, transform: Transform::identity(), diff --git a/src/image.rs b/src/image.rs index bd70bf284..24a0deecc 100644 --- a/src/image.rs +++ b/src/image.rs @@ -5,7 +5,7 @@ use std::ffi::OsStr; use std::fmt::{self, Debug, Formatter}; use std::io; use std::path::Path; -use std::rc::Rc; +use std::sync::Arc; use image::io::Reader as ImageReader; use image::{DynamicImage, GenericImageView, ImageFormat}; @@ -33,14 +33,14 @@ impl ImageId { /// Storage for loaded and decoded images. pub struct ImageStore { - loader: Rc, + loader: Arc, files: HashMap, images: Vec, } impl ImageStore { /// Create a new, empty image store. - pub fn new(loader: Rc) -> Self { + pub fn new(loader: Arc) -> Self { Self { loader, files: HashMap::new(), diff --git a/src/layout/constraints.rs b/src/layout/constraints.rs index 0d772cead..3bdbc4bce 100644 --- a/src/layout/constraints.rs +++ b/src/layout/constraints.rs @@ -1,4 +1,4 @@ -use std::rc::Rc; +use std::sync::Arc; use super::Regions; use crate::frame::Frame; @@ -7,12 +7,12 @@ use crate::geom::{Length, Size, Spec}; /// Constrain a frame with constraints. pub trait Constrain { /// Reference-count the frame and wrap it with constraints. - fn constrain(self, cts: Constraints) -> Constrained>; + fn constrain(self, cts: Constraints) -> Constrained>; } impl Constrain for Frame { - fn constrain(self, cts: Constraints) -> Constrained> { - Constrained::new(Rc::new(self), cts) + fn constrain(self, cts: Constraints) -> Constrained> { + Constrained::new(Arc::new(self), cts) } } diff --git a/src/layout/incremental.rs b/src/layout/incremental.rs index 63915b530..2112fef1b 100644 --- a/src/layout/incremental.rs +++ b/src/layout/incremental.rs @@ -1,6 +1,6 @@ use std::cmp::Reverse; use std::collections::HashMap; -use std::rc::Rc; +use std::sync::Arc; use itertools::Itertools; @@ -65,7 +65,7 @@ impl LayoutCache { &mut self, hash: u64, regions: &Regions, - ) -> Option>>> { + ) -> Option>>> { self.frames .get_mut(&hash)? .iter_mut() @@ -193,7 +193,7 @@ impl LayoutCache { #[derive(Debug, Clone)] pub struct FramesEntry { /// The cached frames for a node. - frames: Vec>>, + frames: Vec>>, /// How nested the frame was in the context is was originally appearing in. level: usize, /// For how long the element already exists. @@ -209,7 +209,7 @@ pub struct FramesEntry { impl FramesEntry { /// Construct a new instance. - pub fn new(frames: Vec>>, level: usize) -> Self { + pub fn new(frames: Vec>>, level: usize) -> Self { Self { frames, level, @@ -222,7 +222,7 @@ impl FramesEntry { /// Checks if the cached frames are valid in the given regions and returns /// them if so. - pub fn lookup(&mut self, regions: &Regions) -> Option>>> { + pub fn lookup(&mut self, regions: &Regions) -> Option>>> { self.check(regions).then(|| { self.temperature[0] = self.temperature[0].saturating_add(1); self.frames.clone() @@ -396,9 +396,9 @@ mod tests { use crate::geom::{Size, Spec}; use crate::layout::Constraints; - fn empty_frames() -> Vec>> { + fn empty_frames() -> Vec>> { vec![Constrained { - item: Rc::new(Frame::default()), + item: Arc::new(Frame::default()), cts: Constraints::new(Spec::splat(false)), }] } diff --git a/src/layout/mod.rs b/src/layout/mod.rs index e4c29f9b3..147e8c9d4 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -13,7 +13,7 @@ pub use regions::*; use std::any::Any; use std::fmt::{self, Debug, Formatter}; use std::hash::{Hash, Hasher}; -use std::rc::Rc; +use std::sync::Arc; use crate::eval::{StyleChain, Styled}; use crate::font::FontStore; @@ -29,7 +29,7 @@ pub struct RootNode(pub Vec>); impl RootNode { /// Layout the document into a sequence of frames, one per page. - pub fn layout(&self, ctx: &mut Context) -> Vec> { + pub fn layout(&self, ctx: &mut Context) -> Vec> { let (mut ctx, styles) = LayoutContext::new(ctx); self.0 .iter() @@ -56,17 +56,17 @@ pub trait Layout { ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, - ) -> Vec>>; + ) -> Vec>>; /// Convert to a packed node. fn pack(self) -> PackedNode where - Self: Debug + Hash + Sized + 'static, + Self: Debug + Hash + Sized + Sync + Send + 'static, { PackedNode { #[cfg(feature = "layout-cache")] hash: self.hash64(), - node: Rc::new(self), + node: Arc::new(self), } } } @@ -112,7 +112,7 @@ impl Layout for EmptyNode { _: &mut LayoutContext, regions: &Regions, _: StyleChain, - ) -> Vec>> { + ) -> Vec>> { let size = regions.expand.select(regions.current, Size::zero()); let mut cts = Constraints::new(regions.expand); cts.exact = regions.current.filter(regions.expand); @@ -124,7 +124,7 @@ impl Layout for EmptyNode { #[derive(Clone)] pub struct PackedNode { /// The type-erased node. - node: Rc, + node: Arc, /// A precomputed hash for the node. #[cfg(feature = "layout-cache")] hash: u64, @@ -205,7 +205,7 @@ impl Layout for PackedNode { ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, - ) -> Vec>> { + ) -> Vec>> { let styles = styles.barred(self.node.as_any().type_id()); #[cfg(not(feature = "layout-cache"))] @@ -243,10 +243,7 @@ impl Layout for PackedNode { }) } - fn pack(self) -> PackedNode - where - Self: Sized + Hash + 'static, - { + fn pack(self) -> PackedNode { self } } @@ -266,8 +263,8 @@ impl Debug for PackedNode { impl PartialEq for PackedNode { fn eq(&self, other: &Self) -> bool { std::ptr::eq( - Rc::as_ptr(&self.node) as *const (), - Rc::as_ptr(&other.node) as *const (), + Arc::as_ptr(&self.node) as *const (), + Arc::as_ptr(&other.node) as *const (), ) } } @@ -282,14 +279,14 @@ impl Hash for PackedNode { } } -trait Bounds: Layout + Debug + 'static { +trait Bounds: Layout + Debug + Sync + Send + 'static { fn as_any(&self) -> &dyn Any; fn hash64(&self) -> u64; } impl Bounds for T where - T: Layout + Hash + Debug + 'static, + T: Layout + Hash + Debug + Sync + Send + 'static, { fn as_any(&self) -> &dyn Any { self @@ -320,7 +317,7 @@ impl Layout for SizedNode { ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, - ) -> Vec>> { + ) -> Vec>> { let is_auto = self.sizing.map_is_none(); let is_rel = self.sizing.map(|s| s.map_or(false, Linear::is_relative)); @@ -346,7 +343,7 @@ impl Layout for SizedNode { // Ensure frame size matches regions size if expansion is on. let target = regions.expand.select(regions.current, frame.size); - Rc::make_mut(frame).resize(target, Align::LEFT_TOP); + Arc::make_mut(frame).resize(target, Align::LEFT_TOP); // Set base & exact constraints if the child is automatically sized // since we don't know what the child might have done. Also set base if @@ -374,11 +371,11 @@ impl Layout for FillNode { ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, - ) -> Vec>> { + ) -> Vec>> { let mut frames = self.child.layout(ctx, regions, styles); for Constrained { item: frame, .. } in &mut frames { let shape = Shape::filled(Geometry::Rect(frame.size), self.fill); - Rc::make_mut(frame).prepend(Point::zero(), Element::Shape(shape)); + Arc::make_mut(frame).prepend(Point::zero(), Element::Shape(shape)); } frames } @@ -399,11 +396,11 @@ impl Layout for StrokeNode { ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, - ) -> Vec>> { + ) -> Vec>> { let mut frames = self.child.layout(ctx, regions, styles); for Constrained { item: frame, .. } in &mut frames { let shape = Shape::stroked(Geometry::Rect(frame.size), self.stroke); - Rc::make_mut(frame).prepend(Point::zero(), Element::Shape(shape)); + Arc::make_mut(frame).prepend(Point::zero(), Element::Shape(shape)); } frames } diff --git a/src/lib.rs b/src/lib.rs index a764468bf..6d52ceaa7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,7 +52,7 @@ pub mod parse; pub mod source; pub mod syntax; -use std::rc::Rc; +use std::sync::Arc; use crate::diag::TypResult; use crate::eval::{Eval, EvalContext, Module, Scope, StyleMap}; @@ -68,7 +68,7 @@ use crate::source::{SourceId, SourceStore}; /// The core context which holds the loader, configuration and cached artifacts. pub struct Context { /// The loader the context was created with. - pub loader: Rc, + pub loader: Arc, /// Stores loaded source files. pub sources: SourceStore, /// Stores parsed font faces. @@ -88,7 +88,7 @@ pub struct Context { impl Context { /// Create a new context with the default settings. - pub fn new(loader: Rc) -> Self { + pub fn new(loader: Arc) -> Self { Self::builder().build(loader) } @@ -124,7 +124,7 @@ impl Context { /// Returns either a vector of frames representing individual pages or /// diagnostics in the form of a vector of error message with file and span /// information. - pub fn typeset(&mut self, id: SourceId) -> TypResult>> { + pub fn typeset(&mut self, id: SourceId) -> TypResult>> { let module = self.evaluate(id)?; let tree = module.into_root(); let frames = tree.layout(self); @@ -183,11 +183,11 @@ impl ContextBuilder { /// Finish building the context by providing the `loader` used to load /// fonts, images, source files and other resources. - pub fn build(self, loader: Rc) -> Context { + pub fn build(self, loader: Arc) -> Context { Context { - sources: SourceStore::new(Rc::clone(&loader)), - fonts: FontStore::new(Rc::clone(&loader)), - images: ImageStore::new(Rc::clone(&loader)), + sources: SourceStore::new(Arc::clone(&loader)), + fonts: FontStore::new(Arc::clone(&loader)), + images: ImageStore::new(Arc::clone(&loader)), loader, #[cfg(feature = "layout-cache")] layout_cache: LayoutCache::new(self.policy, self.max_size), diff --git a/src/library/align.rs b/src/library/align.rs index 8eee116ec..ecf50cc4b 100644 --- a/src/library/align.rs +++ b/src/library/align.rs @@ -27,7 +27,7 @@ impl Layout for AlignNode { ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, - ) -> Vec>> { + ) -> Vec>> { // The child only needs to expand along an axis if there's no alignment. let mut pod = regions.clone(); pod.expand &= self.aligns.map_is_none(); @@ -49,7 +49,7 @@ impl Layout for AlignNode { let target = regions.expand.select(current, frame.size); let default = Spec::new(Align::Left, Align::Top); let aligns = self.aligns.unwrap_or(default); - Rc::make_mut(frame).resize(target, aligns); + Arc::make_mut(frame).resize(target, aligns); // Set constraints. cts.expand = regions.expand; diff --git a/src/library/columns.rs b/src/library/columns.rs index d2dc350f7..149da755b 100644 --- a/src/library/columns.rs +++ b/src/library/columns.rs @@ -37,7 +37,7 @@ impl Layout for ColumnsNode { ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, - ) -> Vec>> { + ) -> Vec>> { let columns = self.columns.get(); // Separating the infinite space into infinite columns does not make diff --git a/src/library/flow.rs b/src/library/flow.rs index 3405b04a0..954267318 100644 --- a/src/library/flow.rs +++ b/src/library/flow.rs @@ -18,7 +18,7 @@ impl Layout for FlowNode { ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, - ) -> Vec>> { + ) -> Vec>> { FlowLayouter::new(self, regions.clone()).layout(ctx, styles) } } @@ -72,7 +72,7 @@ struct FlowLayouter<'a> { /// Spacing and layouted nodes. items: Vec, /// Finished frames for previous regions. - finished: Vec>>, + finished: Vec>>, } /// A prepared item in a flow layout. @@ -82,9 +82,9 @@ enum FlowItem { /// Fractional spacing between other items. Fractional(Fractional), /// A frame for a layouted child node and how to align it. - Frame(Rc, Spec), + Frame(Arc, Spec), /// An absolutely placed frame. - Placed(Rc), + Placed(Arc), } impl<'a> FlowLayouter<'a> { @@ -113,7 +113,7 @@ impl<'a> FlowLayouter<'a> { mut self, ctx: &mut LayoutContext, styles: StyleChain, - ) -> Vec>> { + ) -> Vec>> { for styled in self.children { let styles = styled.map.chain(&styles); match styled.item { diff --git a/src/library/grid.rs b/src/library/grid.rs index 59f524273..c49ac84f5 100644 --- a/src/library/grid.rs +++ b/src/library/grid.rs @@ -38,7 +38,7 @@ impl Layout for GridNode { ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, - ) -> Vec>> { + ) -> Vec>> { // Prepare grid layout by unifying content and gutter tracks. let mut layouter = GridLayouter::new(self, regions.clone(), styles); @@ -114,7 +114,7 @@ struct GridLayouter<'a> { /// Constraints for the active region. cts: Constraints, /// Frames for finished regions. - finished: Vec>>, + finished: Vec>>, } /// Produced by initial row layout, auto and linear rows are already finished, @@ -355,7 +355,7 @@ impl<'a> GridLayouter<'a> { } /// Layout the grid row-by-row. - fn layout(mut self, ctx: &mut LayoutContext) -> Vec>> { + fn layout(mut self, ctx: &mut LayoutContext) -> Vec>> { for y in 0 .. self.rows.len() { // Skip to next region if current one is full, but only for content // rows, not for gutter rows. diff --git a/src/library/heading.rs b/src/library/heading.rs index 4c7bcc7d5..17efb5e4d 100644 --- a/src/library/heading.rs +++ b/src/library/heading.rs @@ -51,7 +51,7 @@ impl Layout for HeadingNode { ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, - ) -> Vec>> { + ) -> Vec>> { let upscale = (1.6 - 0.1 * self.level as f64).max(0.75); let mut passed = StyleMap::new(); @@ -82,7 +82,7 @@ impl Layout for HeadingNode { // FIXME: Constraints and region size. for Constrained { item: frame, .. } in &mut frames { - let frame = Rc::make_mut(frame); + let frame = Arc::make_mut(frame); frame.size.y += above + below; frame.translate(Point::with_y(above)); } diff --git a/src/library/hidden.rs b/src/library/hidden.rs index 7287bf3d9..5025fefbf 100644 --- a/src/library/hidden.rs +++ b/src/library/hidden.rs @@ -19,12 +19,12 @@ impl Layout for HideNode { ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, - ) -> Vec>> { + ) -> Vec>> { let mut frames = self.0.layout(ctx, regions, styles); // Clear the frames. for Constrained { item: frame, .. } in &mut frames { - *frame = Rc::new(Frame { elements: vec![], ..**frame }); + *frame = Arc::new(Frame { elements: vec![], ..**frame }); } frames diff --git a/src/library/image.rs b/src/library/image.rs index a5423ccb3..06b3fe31d 100644 --- a/src/library/image.rs +++ b/src/library/image.rs @@ -44,7 +44,7 @@ impl Layout for ImageNode { ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, - ) -> Vec>> { + ) -> Vec>> { let img = ctx.images.get(self.0); let pxw = img.width() as f64; let pxh = img.height() as f64; diff --git a/src/library/link.rs b/src/library/link.rs index dc523ffd6..0ecd317b8 100644 --- a/src/library/link.rs +++ b/src/library/link.rs @@ -10,13 +10,14 @@ pub struct LinkNode; #[class] impl LinkNode { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult { - let url: String = args.expect::("url")?.into(); + let url = args.expect::("url")?; let body = args.find().unwrap_or_else(|| { let mut text = url.as_str(); for prefix in ["mailto:", "tel:"] { text = text.trim_start_matches(prefix); } - Node::Text(text.into()) + let shorter = text.len() < url.len(); + Node::Text(if shorter { text.into() } else { url.clone() }) }); Ok(body.styled(TextNode::LINK, Some(url))) diff --git a/src/library/list.rs b/src/library/list.rs index 9f742a32b..94f7aa44c 100644 --- a/src/library/list.rs +++ b/src/library/list.rs @@ -39,7 +39,7 @@ impl Layout for ListNode { ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, - ) -> Vec>> { + ) -> Vec>> { let em = styles.get(TextNode::SIZE).abs; let label_indent = styles.get(Self::LABEL_INDENT).resolve(em); let body_indent = styles.get(Self::BODY_INDENT).resolve(em); @@ -65,7 +65,7 @@ impl Layout for ListNode { } /// How to label a list. -pub trait ListKind: Debug + Default + Hash + 'static { +pub trait ListKind: Debug + Default + Hash + Sync + Send + 'static { /// Return the item's label. fn label(&self) -> EcoString; } diff --git a/src/library/mod.rs b/src/library/mod.rs index 3115cc7ae..ae7fc3a16 100644 --- a/src/library/mod.rs +++ b/src/library/mod.rs @@ -61,7 +61,7 @@ macro_rules! prelude { prelude! { pub use std::fmt::{self, Debug, Formatter}; pub use std::num::NonZeroUsize; - pub use std::rc::Rc; + pub use std::sync::Arc; pub use std::hash::Hash; pub use typst_macros::class; diff --git a/src/library/pad.rs b/src/library/pad.rs index 394d3c179..8bfc6d170 100644 --- a/src/library/pad.rs +++ b/src/library/pad.rs @@ -37,7 +37,7 @@ impl Layout for PadNode { ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, - ) -> Vec>> { + ) -> Vec>> { // Layout child into padded regions. let pod = regions.map(|size| shrink(size, self.padding)); let mut frames = self.child.layout(ctx, &pod, styles); @@ -52,7 +52,7 @@ impl Layout for PadNode { let offset = Point::new(padding.left, padding.top); // Grow the frame and translate everything in the frame inwards. - let frame = Rc::make_mut(frame); + let frame = Arc::make_mut(frame); frame.size = padded; frame.translate(offset); diff --git a/src/library/page.rs b/src/library/page.rs index f3a287dc9..9949e1e77 100644 --- a/src/library/page.rs +++ b/src/library/page.rs @@ -70,7 +70,7 @@ impl PageNode { impl PageNode { /// Layout the page run into a sequence of frames, one per page. - pub fn layout(&self, ctx: &mut LayoutContext, styles: StyleChain) -> Vec> { + pub fn layout(&self, ctx: &mut LayoutContext, styles: StyleChain) -> Vec> { // When one of the lengths is infinite the page fits its content along // that axis. let width = styles.get(Self::WIDTH).unwrap_or(Length::inf()); diff --git a/src/library/par.rs b/src/library/par.rs index 4f711e76c..913d2253c 100644 --- a/src/library/par.rs +++ b/src/library/par.rs @@ -1,7 +1,7 @@ //! Paragraph layout. use std::fmt::{self, Debug, Formatter}; -use std::rc::Rc; +use std::sync::Arc; use itertools::Either; use unicode_bidi::{BidiInfo, Level}; @@ -9,7 +9,7 @@ use xi_unicode::LineBreakIterator; use super::prelude::*; use super::{shape, ShapedText, SpacingKind, TextNode}; -use crate::util::{EcoString, RangeExt, RcExt, SliceExt}; +use crate::util::{ArcExt, EcoString, RangeExt, SliceExt}; /// A node that arranges its children into a paragraph. #[derive(Hash)] @@ -75,7 +75,7 @@ impl Layout for ParNode { ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, - ) -> Vec>> { + ) -> Vec>> { // Collect all text into one string used for BiDi analysis. let text = self.collect_text(); @@ -253,7 +253,7 @@ impl<'a> ParLayouter<'a> { let size = Size::new(regions.current.x, regions.base.y); let pod = Regions::one(size, regions.base, Spec::splat(false)); let frame = node.layout(ctx, &pod, styles).remove(0); - items.push(ParItem::Frame(Rc::take(frame.item))); + items.push(ParItem::Frame(Arc::take(frame.item))); ranges.push(range); } } @@ -271,7 +271,7 @@ impl<'a> ParLayouter<'a> { self, ctx: &mut LayoutContext, regions: Regions, - ) -> Vec>> { + ) -> Vec>> { let mut stack = LineStack::new(self.leading, regions); // The current line attempt. @@ -582,7 +582,7 @@ struct LineStack<'a> { regions: Regions, size: Size, lines: Vec>, - finished: Vec>>, + finished: Vec>>, cts: Constraints, overflowing: bool, fractional: bool, @@ -650,7 +650,7 @@ impl<'a> LineStack<'a> { } /// Finish the last region and return the built frames. - fn finish(mut self, ctx: &LayoutContext) -> Vec>> { + fn finish(mut self, ctx: &LayoutContext) -> Vec>> { self.finish_region(ctx); self.finished } diff --git a/src/library/place.rs b/src/library/place.rs index cee687fa3..d5880995f 100644 --- a/src/library/place.rs +++ b/src/library/place.rs @@ -26,7 +26,7 @@ impl Layout for PlaceNode { ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, - ) -> Vec>> { + ) -> Vec>> { let out_of_flow = self.out_of_flow(); // The pod is the base area of the region because for absolute @@ -43,7 +43,7 @@ impl Layout for PlaceNode { // If expansion is off, zero all sizes so that we don't take up any // space in our parent. Otherwise, respect the expand settings. let target = regions.expand.select(regions.current, Size::zero()); - Rc::make_mut(frame).resize(target, Align::LEFT_TOP); + Arc::make_mut(frame).resize(target, Align::LEFT_TOP); // Set base constraint because our pod size is base and exact // constraints if we needed to expand or offset. diff --git a/src/library/shape.rs b/src/library/shape.rs index 12126ab45..5d31d570b 100644 --- a/src/library/shape.rs +++ b/src/library/shape.rs @@ -66,7 +66,7 @@ impl Layout for ShapeNode { ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, - ) -> Vec>> { + ) -> Vec>> { let mut frames; if let Some(child) = &self.child { let mut padding = styles.get(Self::PADDING); @@ -118,7 +118,7 @@ impl Layout for ShapeNode { frames = vec![Frame::new(size).constrain(Constraints::tight(regions))]; } - let frame = Rc::make_mut(&mut frames[0].item); + let frame = Arc::make_mut(&mut frames[0].item); // Add fill and/or stroke. let fill = styles.get(Self::FILL); @@ -149,7 +149,7 @@ impl Layout for ShapeNode { } /// Categorizes shapes. -pub trait ShapeKind: Debug + Default + Hash + 'static { +pub trait ShapeKind: Debug + Default + Hash + Sync + Send + 'static { const ROUND: bool; const QUADRATIC: bool; } diff --git a/src/library/stack.rs b/src/library/stack.rs index 8c8a9f603..14b268c2b 100644 --- a/src/library/stack.rs +++ b/src/library/stack.rs @@ -31,7 +31,7 @@ impl Layout for StackNode { ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, - ) -> Vec>> { + ) -> Vec>> { StackLayouter::new(self, regions.clone(), styles).layout(ctx) } } @@ -90,7 +90,7 @@ struct StackLayouter<'a> { /// Spacing and layouted nodes. items: Vec, /// Finished frames for previous regions. - finished: Vec>>, + finished: Vec>>, } /// A prepared item in a stack layout. @@ -100,7 +100,7 @@ enum StackItem { /// Fractional spacing between other items. Fractional(Fractional), /// A layouted child node. - Frame(Rc, Align), + Frame(Arc, Align), } impl<'a> StackLayouter<'a> { @@ -131,7 +131,7 @@ impl<'a> StackLayouter<'a> { } /// Layout all children. - fn layout(mut self, ctx: &mut LayoutContext) -> Vec>> { + fn layout(mut self, ctx: &mut LayoutContext) -> Vec>> { // Spacing to insert before the next node. let mut deferred = None; diff --git a/src/library/table.rs b/src/library/table.rs index 0e41ad782..d7aa61db0 100644 --- a/src/library/table.rs +++ b/src/library/table.rs @@ -60,7 +60,7 @@ impl Layout for TableNode { ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, - ) -> Vec>> { + ) -> Vec>> { let primary = styles.get(Self::PRIMARY); let secondary = styles.get(Self::SECONDARY); let thickness = styles.get(Self::THICKNESS); diff --git a/src/library/text.rs b/src/library/text.rs index 6d7be323f..c6c1ab801 100644 --- a/src/library/text.rs +++ b/src/library/text.rs @@ -55,7 +55,7 @@ impl TextNode { #[fold(|a, b| a.into_iter().chain(b).collect())] pub const LINES: Vec = vec![]; /// An URL the text should link to. - pub const LINK: Option = None; + pub const LINK: Option = None; /// The size of the glyphs. #[fold(Linear::compose)] @@ -211,12 +211,12 @@ castable! { /// A specific font family like "Arial". #[derive(Clone, Eq, PartialEq, Hash)] -pub struct NamedFamily(String); +pub struct NamedFamily(EcoString); impl NamedFamily { /// Create a named font family variant. pub fn new(string: &str) -> Self { - Self(string.to_lowercase()) + Self(string.to_lowercase().into()) } /// The lowercased family name. diff --git a/src/library/transform.rs b/src/library/transform.rs index aceb4197a..e9a41a98c 100644 --- a/src/library/transform.rs +++ b/src/library/transform.rs @@ -36,7 +36,7 @@ impl Layout for TransformNode { ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, - ) -> Vec>> { + ) -> Vec>> { let origin = styles.get(Self::ORIGIN).unwrap_or(Align::CENTER_HORIZON); let matrix = self.kind.matrix(); @@ -48,7 +48,7 @@ impl Layout for TransformNode { .pre_concat(matrix) .pre_concat(Transform::translation(-x, -y)); - Rc::make_mut(frame).transform(transform); + Arc::make_mut(frame).transform(transform); } frames @@ -56,7 +56,7 @@ impl Layout for TransformNode { } /// Kinds of transformations. -pub trait TransformKind: Debug + Hash + Sized + 'static { +pub trait TransformKind: Debug + Hash + Sized + Sync + Send + 'static { fn construct(args: &mut Args) -> TypResult; fn matrix(&self) -> Transform; } diff --git a/src/loading/fs.rs b/src/loading/fs.rs index 4c46c80c6..3f4a45e1f 100644 --- a/src/loading/fs.rs +++ b/src/loading/fs.rs @@ -1,7 +1,7 @@ use std::fs::{self, File}; use std::io; use std::path::Path; -use std::rc::Rc; +use std::sync::Arc; use memmap2::Mmap; use same_file::Handle; @@ -35,10 +35,10 @@ impl FsLoader { self } - /// Builder-style method to wrap the loader in an [`Rc`] to make it usable + /// Builder-style method to wrap the loader in an [`Arc`] to make it usable /// with the [`Context`](crate::Context). - pub fn wrap(self) -> Rc { - Rc::new(self) + pub fn wrap(self) -> Arc { + Arc::new(self) } /// Search for fonts in the operating system's font directories. diff --git a/src/loading/mem.rs b/src/loading/mem.rs index 9ff02d2d7..5e3e78d11 100644 --- a/src/loading/mem.rs +++ b/src/loading/mem.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use std::collections::HashMap; use std::io; use std::path::{Path, PathBuf}; -use std::rc::Rc; +use std::sync::Arc; use super::{FileHash, Loader}; use crate::font::FaceInfo; @@ -31,10 +31,10 @@ impl MemLoader { self } - /// Builder-style method to wrap the loader in an [`Rc`] to make it usable + /// Builder-style method to wrap the loader in an [`Arc`] to make it usable /// with the [`Context`](crate::Context). - pub fn wrap(self) -> Rc { - Rc::new(self) + pub fn wrap(self) -> Arc { + Arc::new(self) } /// Insert a path-file mapping. If the data forms a font, then that font diff --git a/src/parse/incremental.rs b/src/parse/incremental.rs index c1da96988..a347f6ca2 100644 --- a/src/parse/incremental.rs +++ b/src/parse/incremental.rs @@ -1,5 +1,5 @@ use std::ops::Range; -use std::rc::Rc; +use std::sync::Arc; use crate::syntax::{Green, GreenNode, NodeKind}; @@ -78,8 +78,8 @@ impl<'a> Reparser<'a> { impl Reparser<'_> { /// Find the innermost child that is incremental safe. - pub fn reparse(&self, green: &mut Rc) -> Range { - self.reparse_step(Rc::make_mut(green), 0, TokenMode::Markup, true) + pub fn reparse(&self, green: &mut Arc) -> Range { + self.reparse_step(Arc::make_mut(green), 0, TokenMode::Markup, true) .unwrap_or_else(|| { *green = parse(self.src); 0 .. self.src.len() @@ -167,7 +167,7 @@ impl Reparser<'_> { if last_kind.succession_rule() != SuccessionRule::Unsafe { if let Some(range) = match child { Green::Node(node) => self.reparse_step( - Rc::make_mut(node), + Arc::make_mut(node), first_start, child_mode, outermost, diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 38a08ab8c..fbace15b1 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -12,14 +12,14 @@ pub use resolve::*; pub use scanner::*; pub use tokens::*; -use std::rc::Rc; +use std::sync::Arc; use crate::syntax::ast::{Associativity, BinOp, UnOp}; use crate::syntax::{ErrorPos, Green, GreenNode, NodeKind}; use crate::util::EcoString; /// Parse a source file. -pub fn parse(src: &str) -> Rc { +pub fn parse(src: &str) -> Arc { let mut p = Parser::new(src, TokenMode::Markup); markup(&mut p, true); match p.finish().into_iter().next() { diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs index 27da3b80c..970c0dd68 100644 --- a/src/parse/tokens.rs +++ b/src/parse/tokens.rs @@ -1,4 +1,4 @@ -use std::rc::Rc; +use std::sync::Arc; use super::{ is_id_continue, is_id_start, is_newline, resolve_hex, resolve_raw, resolve_string, @@ -321,7 +321,7 @@ impl<'s> Tokens<'s> { // Special case for empty inline block. if backticks == 2 { - return NodeKind::Raw(Rc::new(RawNode { + return NodeKind::Raw(Arc::new(RawNode { text: EcoString::new(), lang: None, block: false, @@ -341,7 +341,7 @@ impl<'s> Tokens<'s> { if found == backticks { let end = self.s.index() - found as usize; - NodeKind::Raw(Rc::new(resolve_raw( + NodeKind::Raw(Arc::new(resolve_raw( column, backticks, self.s.get(start .. end), @@ -393,7 +393,7 @@ impl<'s> Tokens<'s> { }; if terminated { - NodeKind::Math(Rc::new(MathNode { + NodeKind::Math(Arc::new(MathNode { formula: self.s.get(start .. end).into(), display, })) @@ -581,7 +581,7 @@ mod tests { } fn Raw(text: &str, lang: Option<&str>, block: bool) -> NodeKind { - NodeKind::Raw(Rc::new(RawNode { + NodeKind::Raw(Arc::new(RawNode { text: text.into(), lang: lang.map(Into::into), block, @@ -589,7 +589,7 @@ mod tests { } fn Math(formula: &str, display: bool) -> NodeKind { - NodeKind::Math(Rc::new(MathNode { formula: formula.into(), display })) + NodeKind::Math(Arc::new(MathNode { formula: formula.into(), display })) } fn Str(string: &str) -> NodeKind { diff --git a/src/source.rs b/src/source.rs index fd42c3f7e..0e7b4c635 100644 --- a/src/source.rs +++ b/src/source.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use std::io; use std::ops::Range; use std::path::{Path, PathBuf}; -use std::rc::Rc; +use std::sync::Arc; use crate::diag::TypResult; use crate::loading::{FileHash, Loader}; @@ -37,14 +37,14 @@ impl SourceId { /// Storage for loaded source files. pub struct SourceStore { - loader: Rc, + loader: Arc, files: HashMap, sources: Vec, } impl SourceStore { /// Create a new, empty source store. - pub fn new(loader: Rc) -> Self { + pub fn new(loader: Arc) -> Self { Self { loader, files: HashMap::new(), @@ -125,7 +125,7 @@ pub struct SourceFile { path: PathBuf, src: String, lines: Vec, - root: Rc, + root: Arc, } impl SourceFile { @@ -148,7 +148,7 @@ impl SourceFile { } /// The root node of the file's untyped green tree. - pub fn root(&self) -> &Rc { + pub fn root(&self) -> &Arc { &self.root } diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index 03a496ddc..a26384e15 100644 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -7,7 +7,7 @@ mod span; use std::fmt::{self, Debug, Display, Formatter}; use std::ops::Range; -use std::rc::Rc; +use std::sync::Arc; pub use highlight::*; pub use pretty::*; @@ -24,7 +24,7 @@ use crate::util::EcoString; #[derive(Clone, PartialEq)] pub enum Green { /// A reference-counted inner node. - Node(Rc), + Node(Arc), /// A terminal, owned token. Token(GreenData), } @@ -76,7 +76,7 @@ impl Green { pub fn convert(&mut self, kind: NodeKind) { match self { Self::Node(node) => { - let node = Rc::make_mut(node); + let node = Arc::make_mut(node); node.erroneous |= kind.is_error(); node.data.kind = kind; } @@ -187,12 +187,12 @@ impl GreenNode { impl From for Green { fn from(node: GreenNode) -> Self { - Rc::new(node).into() + Arc::new(node).into() } } -impl From> for Green { - fn from(node: Rc) -> Self { +impl From> for Green { + fn from(node: Arc) -> Self { Self::Node(node) } } @@ -259,7 +259,7 @@ pub struct RedNode { impl RedNode { /// Create a new red node from a root [`GreenNode`]. - pub fn from_root(root: Rc, id: SourceId) -> Self { + pub fn from_root(root: Arc, id: SourceId) -> Self { Self { id, offset: 0, green: root.into() } } @@ -611,9 +611,9 @@ pub enum NodeKind { Emph, /// An arbitrary number of backticks followed by inner contents, terminated /// with the same number of backticks: `` `...` ``. - Raw(Rc), + Raw(Arc), /// Dollar signs surrounding inner contents. - Math(Rc), + Math(Arc), /// A section heading: `= Introduction`. Heading, /// An item in an unordered list: `- ...`. diff --git a/src/util/eco_string.rs b/src/util/eco_string.rs index 8cb833779..953508ce8 100644 --- a/src/util/eco_string.rs +++ b/src/util/eco_string.rs @@ -3,9 +3,9 @@ use std::cmp::Ordering; use std::fmt::{self, Debug, Display, Formatter, Write}; use std::hash::{Hash, Hasher}; use std::ops::{Add, AddAssign, Deref}; -use std::rc::Rc; +use std::sync::Arc; -use super::RcExt; +use super::ArcExt; /// Create a new [`EcoString`] from a format string. macro_rules! format_eco { @@ -27,13 +27,13 @@ pub struct EcoString(Repr); #[derive(Clone)] enum Repr { Small { buf: [u8; LIMIT], len: u8 }, - Large(Rc), + Large(Arc), } /// The maximum number of bytes that can be stored inline. /// /// The value is chosen such that an `EcoString` fits exactly into 16 bytes -/// (which are needed anyway due to the `Rc`s alignment, at least on 64-bit +/// (which are needed anyway due to the `Arc`s alignment, at least on 64-bit /// platforms). /// /// Must be at least 4 to hold any char. @@ -50,7 +50,7 @@ impl EcoString { if capacity <= LIMIT { Self::new() } else { - Self(Repr::Large(Rc::new(String::with_capacity(capacity)))) + Self(Repr::Large(Arc::new(String::with_capacity(capacity)))) } } @@ -66,7 +66,7 @@ impl EcoString { buf[.. len].copy_from_slice(slice.as_bytes()); Repr::Small { buf, len: len as u8 } } else { - Repr::Large(Rc::new(s.into())) + Repr::Large(Arc::new(s.into())) }) } @@ -100,7 +100,7 @@ impl EcoString { self.push_str(c.encode_utf8(&mut [0; 4])); } } - Repr::Large(rc) => Rc::make_mut(rc).push(c), + Repr::Large(rc) => Arc::make_mut(rc).push(c), } } @@ -117,10 +117,10 @@ impl EcoString { let mut spilled = String::with_capacity(new); spilled.push_str(self); spilled.push_str(string); - self.0 = Repr::Large(Rc::new(spilled)); + self.0 = Repr::Large(Arc::new(spilled)); } } - Repr::Large(rc) => Rc::make_mut(rc).push_str(string), + Repr::Large(rc) => Arc::make_mut(rc).push_str(string), } } @@ -132,7 +132,7 @@ impl EcoString { *len -= c.len_utf8() as u8; } Repr::Large(rc) => { - Rc::make_mut(rc).pop(); + Arc::make_mut(rc).pop(); } } Some(c) @@ -143,8 +143,8 @@ impl EcoString { match &mut self.0 { Repr::Small { len, .. } => *len = 0, Repr::Large(rc) => { - if Rc::strong_count(rc) == 1 { - Rc::make_mut(rc).clear(); + if Arc::strong_count(rc) == 1 { + Arc::make_mut(rc).clear(); } else { *self = Self::new(); } @@ -351,11 +351,17 @@ impl From for EcoString { } } +impl From<&EcoString> for String { + fn from(s: &EcoString) -> Self { + s.as_str().to_owned() + } +} + impl From for String { fn from(s: EcoString) -> Self { match s.0 { Repr::Small { .. } => s.as_str().to_owned(), - Repr::Large(rc) => Rc::take(rc), + Repr::Large(rc) => Arc::take(rc), } } } diff --git a/src/util/mod.rs b/src/util/mod.rs index 61e7131d1..de37354e7 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -11,7 +11,7 @@ use std::cell::RefMut; use std::cmp::Ordering; use std::ops::Range; use std::path::{Component, Path, PathBuf}; -use std::rc::Rc; +use std::sync::Arc; /// Additional methods for strings. pub trait StrExt { @@ -62,18 +62,18 @@ impl OptionExt for Option { } /// Additional methods for reference-counted pointers. -pub trait RcExt { +pub trait ArcExt { /// Takes the inner value if there is exactly one strong reference and /// clones it otherwise. fn take(self) -> T; } -impl RcExt for Rc +impl ArcExt for Arc where T: Clone, { fn take(self) -> T { - match Rc::try_unwrap(self) { + match Arc::try_unwrap(self) { Ok(v) => v, Err(rc) => (*rc).clone(), } diff --git a/tests/typeset.rs b/tests/typeset.rs index e65375bb1..f7f2eccfa 100644 --- a/tests/typeset.rs +++ b/tests/typeset.rs @@ -3,7 +3,7 @@ use std::ffi::OsStr; use std::fs; use std::ops::Range; use std::path::Path; -use std::rc::Rc; +use std::sync::Arc; use tiny_skia as sk; use walkdir::WalkDir; @@ -258,7 +258,7 @@ fn test_part( line: usize, debug: bool, rng: &mut LinearShift, -) -> (bool, bool, Vec>) { +) -> (bool, bool, Vec>) { let mut ok = true; let id = ctx.sources.provide(src_path, src); @@ -483,7 +483,7 @@ fn test_incremental( ctx: &mut Context, i: usize, tree: &RootNode, - frames: &[Rc], + frames: &[Arc], ) -> bool { let mut ok = true; @@ -527,7 +527,7 @@ fn test_incremental( } /// Draw all frames into one image with padding in between. -fn render(ctx: &mut Context, frames: &[Rc]) -> sk::Pixmap { +fn render(ctx: &mut Context, frames: &[Arc]) -> sk::Pixmap { let pixel_per_pt = 2.0; let pixmaps: Vec<_> = frames .iter()