Switch from Rc to Arc

This commit is contained in:
Laurenz 2022-01-31 16:06:44 +01:00
parent fa57d86ed9
commit 20b1a38414
45 changed files with 222 additions and 218 deletions

View File

@ -3,11 +3,11 @@ use std::convert::TryFrom;
use std::fmt::{self, Debug, Formatter, Write}; use std::fmt::{self, Debug, Formatter, Write};
use std::iter::FromIterator; use std::iter::FromIterator;
use std::ops::{Add, AddAssign}; use std::ops::{Add, AddAssign};
use std::rc::Rc; use std::sync::Arc;
use super::Value; use super::Value;
use crate::diag::StrResult; use crate::diag::StrResult;
use crate::util::RcExt; use crate::util::ArcExt;
/// Create a new [`Array`] from values. /// Create a new [`Array`] from values.
#[allow(unused_macros)] #[allow(unused_macros)]
@ -23,7 +23,7 @@ macro_rules! array {
/// An array of values with clone-on-write value semantics. /// An array of values with clone-on-write value semantics.
#[derive(Default, Clone, PartialEq)] #[derive(Default, Clone, PartialEq)]
pub struct Array(Rc<Vec<Value>>); pub struct Array(Arc<Vec<Value>>);
impl Array { impl Array {
/// Create a new, empty array. /// Create a new, empty array.
@ -33,7 +33,7 @@ impl Array {
/// Create a new array from a vector of values. /// Create a new array from a vector of values.
pub fn from_vec(vec: Vec<Value>) -> Self { pub fn from_vec(vec: Vec<Value>) -> Self {
Self(Rc::new(vec)) Self(Arc::new(vec))
} }
/// Whether the array is empty. /// Whether the array is empty.
@ -59,19 +59,19 @@ impl Array {
let len = self.len(); let len = self.len();
usize::try_from(index) usize::try_from(index)
.ok() .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)) .ok_or_else(|| out_of_bounds(index, len))
} }
/// Push a value to the end of the array. /// Push a value to the end of the array.
pub fn push(&mut self, value: Value) { 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. /// Clear the array.
pub fn clear(&mut self) { pub fn clear(&mut self) {
if Rc::strong_count(&self.0) == 1 { if Arc::strong_count(&self.0) == 1 {
Rc::make_mut(&mut self.0).clear(); Arc::make_mut(&mut self.0).clear();
} else { } else {
*self = Self::new(); *self = Self::new();
} }
@ -87,7 +87,7 @@ impl Array {
/// Returns an error if two values could not be compared. /// Returns an error if two values could not be compared.
pub fn sorted(mut self) -> StrResult<Self> { pub fn sorted(mut self) -> StrResult<Self> {
let mut result = Ok(()); 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(|| { a.partial_cmp(b).unwrap_or_else(|| {
if result.is_ok() { if result.is_ok() {
result = Err(format!( result = Err(format!(
@ -146,7 +146,7 @@ impl Add for Array {
impl AddAssign for Array { impl AddAssign for Array {
fn add_assign(&mut self, rhs: 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), Ok(vec) => self.extend(vec),
Err(rc) => self.extend(rc.iter().cloned()), Err(rc) => self.extend(rc.iter().cloned()),
} }
@ -155,13 +155,13 @@ impl AddAssign for Array {
impl Extend<Value> for Array { impl Extend<Value> for Array {
fn extend<T: IntoIterator<Item = Value>>(&mut self, iter: T) { fn extend<T: IntoIterator<Item = Value>>(&mut self, iter: T) {
Rc::make_mut(&mut self.0).extend(iter); Arc::make_mut(&mut self.0).extend(iter);
} }
} }
impl FromIterator<Value> for Array { impl FromIterator<Value> for Array {
fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self { fn from_iter<T: IntoIterator<Item = Value>>(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<Value>; type IntoIter = std::vec::IntoIter<Value>;
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
Rc::take(self.0).into_iter() Arc::take(self.0).into_iter()
} }
} }

View File

@ -1,4 +1,4 @@
use std::rc::Rc; use std::sync::Arc;
use super::{Scope, Scopes, Value}; use super::{Scope, Scopes, Value};
use crate::syntax::ast::{ClosureParam, Expr, Ident, Imports, TypedNode}; use crate::syntax::ast::{ClosureParam, Expr, Ident, Imports, TypedNode};
@ -35,7 +35,7 @@ impl<'a> CapturesVisitor<'a> {
pub fn capture(&mut self, ident: Ident) { pub fn capture(&mut self, ident: Ident) {
if self.internal.get(&ident).is_none() { if self.internal.get(&ident).is_none() {
if let Some(slot) = self.external.get(&ident) { 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));
} }
} }
} }

View File

@ -2,11 +2,11 @@ use std::collections::BTreeMap;
use std::fmt::{self, Debug, Formatter, Write}; use std::fmt::{self, Debug, Formatter, Write};
use std::iter::FromIterator; use std::iter::FromIterator;
use std::ops::{Add, AddAssign}; use std::ops::{Add, AddAssign};
use std::rc::Rc; use std::sync::Arc;
use super::Value; use super::Value;
use crate::diag::StrResult; use crate::diag::StrResult;
use crate::util::{EcoString, RcExt}; use crate::util::{ArcExt, EcoString};
/// Create a new [`Dict`] from key-value pairs. /// Create a new [`Dict`] from key-value pairs.
#[allow(unused_macros)] #[allow(unused_macros)]
@ -21,7 +21,7 @@ macro_rules! dict {
/// A dictionary from strings to values with clone-on-write value semantics. /// A dictionary from strings to values with clone-on-write value semantics.
#[derive(Default, Clone, PartialEq)] #[derive(Default, Clone, PartialEq)]
pub struct Dict(Rc<BTreeMap<EcoString, Value>>); pub struct Dict(Arc<BTreeMap<EcoString, Value>>);
impl Dict { impl Dict {
/// Create a new, empty dictionary. /// Create a new, empty dictionary.
@ -31,7 +31,7 @@ impl Dict {
/// Create a new dictionary from a mapping of strings to values. /// Create a new dictionary from a mapping of strings to values.
pub fn from_map(map: BTreeMap<EcoString, Value>) -> Self { pub fn from_map(map: BTreeMap<EcoString, Value>) -> Self {
Self(Rc::new(map)) Self(Arc::new(map))
} }
/// Whether the dictionary is empty. /// Whether the dictionary is empty.
@ -54,18 +54,18 @@ impl Dict {
/// This inserts the key with [`None`](Value::None) as the value if not /// This inserts the key with [`None`](Value::None) as the value if not
/// present so far. /// present so far.
pub fn get_mut(&mut self, key: EcoString) -> &mut Value { 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`. /// Insert a mapping from the given `key` to the given `value`.
pub fn insert(&mut self, key: EcoString, value: 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. /// Clear the dictionary.
pub fn clear(&mut self) { pub fn clear(&mut self) {
if Rc::strong_count(&self.0) == 1 { if Arc::strong_count(&self.0) == 1 {
Rc::make_mut(&mut self.0).clear(); Arc::make_mut(&mut self.0).clear();
} else { } else {
*self = Self::new(); *self = Self::new();
} }
@ -112,7 +112,7 @@ impl Add for Dict {
impl AddAssign for Dict { impl AddAssign for Dict {
fn add_assign(&mut self, rhs: 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), Ok(map) => self.extend(map),
Err(rc) => self.extend(rc.iter().map(|(k, v)| (k.clone(), v.clone()))), 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 { impl Extend<(EcoString, Value)> for Dict {
fn extend<T: IntoIterator<Item = (EcoString, Value)>>(&mut self, iter: T) { fn extend<T: IntoIterator<Item = (EcoString, Value)>>(&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 { impl FromIterator<(EcoString, Value)> for Dict {
fn from_iter<T: IntoIterator<Item = (EcoString, Value)>>(iter: T) -> Self { fn from_iter<T: IntoIterator<Item = (EcoString, Value)>>(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<EcoString, Value>; type IntoIter = std::collections::btree_map::IntoIter<EcoString, Value>;
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
Rc::take(self.0).into_iter() Arc::take(self.0).into_iter()
} }
} }

View File

@ -1,5 +1,5 @@
use std::fmt::{self, Debug, Formatter, Write}; use std::fmt::{self, Debug, Formatter, Write};
use std::rc::Rc; use std::sync::Arc;
use super::{Cast, EvalContext, Value}; use super::{Cast, EvalContext, Value};
use crate::diag::{At, TypResult}; use crate::diag::{At, TypResult};
@ -8,9 +8,9 @@ use crate::util::EcoString;
/// An evaluatable function. /// An evaluatable function.
#[derive(Clone)] #[derive(Clone)]
pub struct Function(Rc<Inner<Func>>); pub struct Function(Arc<Inner<Func>>);
/// The unsized structure behind the [`Rc`]. /// The unsized structure behind the [`Arc`].
struct Inner<T: ?Sized> { struct Inner<T: ?Sized> {
name: Option<EcoString>, name: Option<EcoString>,
func: T, func: T,
@ -24,7 +24,7 @@ impl Function {
where where
F: Fn(&mut EvalContext, &mut Args) -> TypResult<Value> + 'static, F: Fn(&mut EvalContext, &mut Args) -> TypResult<Value> + 'static,
{ {
Self(Rc::new(Inner { name, func })) Self(Arc::new(Inner { name, func }))
} }
/// The name of the function. /// The name of the function.
@ -53,8 +53,8 @@ impl PartialEq for Function {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
// We cast to thin pointers for comparison. // We cast to thin pointers for comparison.
std::ptr::eq( std::ptr::eq(
Rc::as_ptr(&self.0) as *const (), Arc::as_ptr(&self.0) as *const (),
Rc::as_ptr(&other.0) as *const (), Arc::as_ptr(&other.0) as *const (),
) )
} }
} }

View File

@ -71,7 +71,7 @@ impl Node {
/// Create an inline-level node. /// Create an inline-level node.
pub fn inline<T>(node: T) -> Self pub fn inline<T>(node: T) -> Self
where where
T: Layout + Debug + Hash + 'static, T: Layout + Debug + Hash + Sync + Send + 'static,
{ {
Self::Inline(node.pack()) Self::Inline(node.pack())
} }
@ -79,7 +79,7 @@ impl Node {
/// Create a block-level node. /// Create a block-level node.
pub fn block<T>(node: T) -> Self pub fn block<T>(node: T) -> Self
where where
T: Layout + Debug + Hash + 'static, T: Layout + Debug + Hash + Sync + Send + 'static,
{ {
Self::Block(node.pack()) Self::Block(node.pack())
} }

View File

@ -2,14 +2,14 @@ use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::iter; use std::iter;
use std::rc::Rc; use std::sync::Arc;
use super::{Args, Class, Construct, EvalContext, Function, Set, Value}; use super::{Args, Class, Construct, EvalContext, Function, Set, Value};
use crate::diag::TypResult; use crate::diag::TypResult;
use crate::util::EcoString; use crate::util::EcoString;
/// A slot where a variable is stored. /// A slot where a variable is stored.
pub type Slot = Rc<RefCell<Value>>; pub type Slot = Arc<RefCell<Value>>;
/// A stack of scopes. /// A stack of scopes.
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
@ -85,12 +85,12 @@ impl Scope {
// FIXME: Use Ref::leak once stable. // FIXME: Use Ref::leak once stable.
std::mem::forget(cell.borrow()); 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. /// Define a mutable variable with a value.
pub fn def_mut(&mut self, var: impl Into<EcoString>, value: impl Into<Value>) { pub fn def_mut(&mut self, var: impl Into<EcoString>, value: impl Into<Value>) {
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. /// Define a variable with a slot.

View File

@ -1,7 +1,7 @@
use std::any::{Any, TypeId}; use std::any::{Any, TypeId};
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::rc::Rc; use std::sync::Arc;
// TODO(style): Possible optimizations: // TODO(style): Possible optimizations:
// - Ref-count map for cheaper cloning and smaller footprint // - Ref-count map for cheaper cloning and smaller footprint
@ -334,13 +334,13 @@ impl Debug for Link<'_> {
/// An entry for a single style property. /// An entry for a single style property.
#[derive(Clone)] #[derive(Clone)]
struct Entry { struct Entry {
p: Rc<dyn Bounds>, p: Arc<dyn Bounds>,
scoped: bool, scoped: bool,
} }
impl Entry { impl Entry {
fn new<P: Property>(key: P, value: P::Value) -> Self { fn new<P: Property>(key: P, value: P::Value) -> Self {
Self { p: Rc::new((key, value)), scoped: false } Self { p: Arc::new((key, value)), scoped: false }
} }
fn is<P: Property>(&self) -> bool { fn is<P: Property>(&self) -> bool {
@ -390,11 +390,11 @@ impl Hash for Entry {
/// ///
/// This trait is not intended to be implemented manually, but rather through /// This trait is not intended to be implemented manually, but rather through
/// the `#[properties]` proc-macro. /// 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 /// The type of value that is returned when getting this property from a
/// style map. For example, this could be [`Length`](crate::geom::Length) /// style map. For example, this could be [`Length`](crate::geom::Length)
/// for a `WIDTH` property. /// 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. /// The name of the property, used for debug printing.
const NAME: &'static str; 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 /// 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 /// of the implementing type so that we can use it in the methods (it must be a
/// constrained type parameter). /// constrained type parameter).
trait Bounds: 'static { trait Bounds: Sync + Send + 'static {
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
fn dyn_fmt(&self, f: &mut Formatter) -> fmt::Result; fn dyn_fmt(&self, f: &mut Formatter) -> fmt::Result;
fn dyn_eq(&self, other: &Entry) -> bool; fn dyn_eq(&self, other: &Entry) -> bool;

View File

@ -2,7 +2,7 @@ use std::any::Any;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::hash::Hash; use std::hash::Hash;
use std::rc::Rc; use std::sync::Arc;
use super::{ops, Args, Array, Class, Dict, Function, Node}; use super::{ops, Args, Array, Class, Dict, Function, Node};
use crate::diag::StrResult; use crate::diag::StrResult;
@ -58,7 +58,7 @@ impl Value {
/// Create an inline-level node value. /// Create an inline-level node value.
pub fn inline<T>(node: T) -> Self pub fn inline<T>(node: T) -> Self
where where
T: Layout + Debug + Hash + 'static, T: Layout + Debug + Hash + Sync + Send + 'static,
{ {
Self::Node(Node::inline(node)) Self::Node(Node::inline(node))
} }
@ -66,7 +66,7 @@ impl Value {
/// Create a block-level node value. /// Create a block-level node value.
pub fn block<T>(node: T) -> Self pub fn block<T>(node: T) -> Self
where where
T: Layout + Debug + Hash + 'static, T: Layout + Debug + Hash + Sync + Send + 'static,
{ {
Self::Node(Node::block(node)) Self::Node(Node::block(node))
} }
@ -211,15 +211,15 @@ impl From<Dynamic> for Value {
/// A dynamic value. /// A dynamic value.
#[derive(Clone)] #[derive(Clone)]
pub struct Dynamic(Rc<dyn Bounds>); pub struct Dynamic(Arc<dyn Bounds>);
impl Dynamic { impl Dynamic {
/// Create a new instance from any value that satisifies the required bounds. /// Create a new instance from any value that satisifies the required bounds.
pub fn new<T>(any: T) -> Self pub fn new<T>(any: T) -> Self
where 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`. /// 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 as_any(&self) -> &dyn Any;
fn dyn_eq(&self, other: &Dynamic) -> bool; fn dyn_eq(&self, other: &Dynamic) -> bool;
fn dyn_type_name(&self) -> &'static str; fn dyn_type_name(&self) -> &'static str;
@ -258,7 +258,7 @@ trait Bounds: Debug + 'static {
impl<T> Bounds for T impl<T> Bounds for T
where where
T: Type + Debug + PartialEq + 'static, T: Type + Debug + PartialEq + Sync + Send + 'static,
{ {
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self self

View File

@ -3,7 +3,7 @@
use std::cmp::Eq; use std::cmp::Eq;
use std::collections::{BTreeMap, HashMap, HashSet}; use std::collections::{BTreeMap, HashMap, HashSet};
use std::hash::Hash; use std::hash::Hash;
use std::rc::Rc; use std::sync::Arc;
use image::{DynamicImage, GenericImageView, ImageFormat, ImageResult, Rgba}; use image::{DynamicImage, GenericImageView, ImageFormat, ImageResult, Rgba};
use pdf_writer::types::{ use pdf_writer::types::{
@ -26,7 +26,7 @@ use crate::Context;
/// included in the PDF. /// included in the PDF.
/// ///
/// Returns the raw bytes making up the PDF file. /// Returns the raw bytes making up the PDF file.
pub fn pdf(ctx: &Context, frames: &[Rc<Frame>]) -> Vec<u8> { pub fn pdf(ctx: &Context, frames: &[Arc<Frame>]) -> Vec<u8> {
PdfExporter::new(ctx).export(frames) PdfExporter::new(ctx).export(frames)
} }
@ -60,14 +60,14 @@ impl<'a> PdfExporter<'a> {
} }
} }
fn export(mut self, frames: &[Rc<Frame>]) -> Vec<u8> { fn export(mut self, frames: &[Arc<Frame>]) -> Vec<u8> {
self.build_pages(frames); self.build_pages(frames);
self.write_fonts(); self.write_fonts();
self.write_images(); self.write_images();
self.write_structure() self.write_structure()
} }
fn build_pages(&mut self, frames: &[Rc<Frame>]) { fn build_pages(&mut self, frames: &[Arc<Frame>]) {
for frame in frames { for frame in frames {
let page = PageExporter::new(self).export(frame); let page = PageExporter::new(self).export(frame);
self.pages.push(page); self.pages.push(page);

View File

@ -3,7 +3,7 @@
use std::collections::{hash_map::Entry, BTreeMap, HashMap}; use std::collections::{hash_map::Entry, BTreeMap, HashMap};
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::rc::Rc; use std::sync::Arc;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use ttf_parser::{name_id, GlyphId, PlatformId}; use ttf_parser::{name_id, GlyphId, PlatformId};
@ -33,15 +33,15 @@ impl FaceId {
/// Storage for loaded and parsed font faces. /// Storage for loaded and parsed font faces.
pub struct FontStore { pub struct FontStore {
loader: Rc<dyn Loader>, loader: Arc<dyn Loader>,
faces: Vec<Option<Face>>, faces: Vec<Option<Face>>,
families: BTreeMap<String, Vec<FaceId>>, families: BTreeMap<String, Vec<FaceId>>,
buffers: HashMap<FileHash, Rc<Vec<u8>>>, buffers: HashMap<FileHash, Arc<Vec<u8>>>,
} }
impl FontStore { impl FontStore {
/// Create a new, empty font store. /// Create a new, empty font store.
pub fn new(loader: Rc<dyn Loader>) -> Self { pub fn new(loader: Arc<dyn Loader>) -> Self {
let mut faces = vec![]; let mut faces = vec![];
let mut families = BTreeMap::<String, Vec<FaceId>>::new(); let mut families = BTreeMap::<String, Vec<FaceId>>::new();
@ -109,11 +109,11 @@ impl FontStore {
Entry::Occupied(entry) => entry.into_mut(), Entry::Occupied(entry) => entry.into_mut(),
Entry::Vacant(entry) => { Entry::Vacant(entry) => {
let buffer = self.loader.load(path).ok()?; 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); *slot = Some(face);
} }
@ -147,7 +147,7 @@ pub struct Face {
/// The raw face data, possibly shared with other faces from the same /// The raw face data, possibly shared with other faces from the same
/// collection. Must stay alive put, because `ttf` points into it using /// collection. Must stay alive put, because `ttf` points into it using
/// unsafe code. /// unsafe code.
buffer: Rc<Vec<u8>>, buffer: Arc<Vec<u8>>,
/// The face's index in the collection (zero if not a collection). /// The face's index in the collection (zero if not a collection).
index: u32, index: u32,
/// The underlying ttf-parser/rustybuzz face. /// The underlying ttf-parser/rustybuzz face.
@ -182,11 +182,11 @@ pub struct LineMetrics {
impl Face { impl Face {
/// Parse a font face from a buffer and collection index. /// Parse a font face from a buffer and collection index.
pub fn new(buffer: Rc<Vec<u8>>, index: u32) -> Option<Self> { pub fn new(buffer: Arc<Vec<u8>>, index: u32) -> Option<Self> {
// Safety: // Safety:
// - The slices's location is stable in memory: // - The slices's location is stable in memory:
// - We don't move the underlying vector // - 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 // - The internal static lifetime is not leaked because its rewritten
// to the self-lifetime in `ttf()`. // to the self-lifetime in `ttf()`.
let slice: &'static [u8] = let slice: &'static [u8] =
@ -238,7 +238,7 @@ impl Face {
} }
/// The underlying buffer. /// The underlying buffer.
pub fn buffer(&self) -> &Rc<Vec<u8>> { pub fn buffer(&self) -> &Arc<Vec<u8>> {
&self.buffer &self.buffer
} }

View File

@ -1,7 +1,7 @@
//! Finished layouts. //! Finished layouts.
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::rc::Rc; use std::sync::Arc;
use crate::font::FaceId; use crate::font::FaceId;
use crate::geom::{Align, Em, Length, Paint, Path, Point, Size, Spec, Transform}; use crate::geom::{Align, Em, Length, Paint, Path, Point, Size, Spec, Transform};
@ -43,7 +43,7 @@ impl Frame {
} }
/// Add a group element. /// Add a group element.
pub fn push_frame(&mut self, pos: Point, frame: Rc<Self>) { pub fn push_frame(&mut self, pos: Point, frame: Arc<Self>) {
self.elements.push((pos, Element::Group(Group::new(frame)))); self.elements.push((pos, Element::Group(Group::new(frame))));
} }
@ -100,7 +100,7 @@ impl Frame {
F: FnOnce(&mut Group), F: FnOnce(&mut Group),
{ {
let mut wrapper = Frame { elements: vec![], ..*self }; 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); f(&mut group);
wrapper.push(Point::zero(), Element::Group(group)); wrapper.push(Point::zero(), Element::Group(group));
*self = wrapper; *self = wrapper;
@ -149,7 +149,7 @@ pub enum Element {
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub struct Group { pub struct Group {
/// The group's frame. /// The group's frame.
pub frame: Rc<Frame>, pub frame: Arc<Frame>,
/// A transformation to apply to the group. /// A transformation to apply to the group.
pub transform: Transform, pub transform: Transform,
/// Whether the frame should be a clipping boundary. /// Whether the frame should be a clipping boundary.
@ -158,7 +158,7 @@ pub struct Group {
impl Group { impl Group {
/// Create a new group with default settings. /// Create a new group with default settings.
pub fn new(frame: Rc<Frame>) -> Self { pub fn new(frame: Arc<Frame>) -> Self {
Self { Self {
frame, frame,
transform: Transform::identity(), transform: Transform::identity(),

View File

@ -5,7 +5,7 @@ use std::ffi::OsStr;
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::io; use std::io;
use std::path::Path; use std::path::Path;
use std::rc::Rc; use std::sync::Arc;
use image::io::Reader as ImageReader; use image::io::Reader as ImageReader;
use image::{DynamicImage, GenericImageView, ImageFormat}; use image::{DynamicImage, GenericImageView, ImageFormat};
@ -33,14 +33,14 @@ impl ImageId {
/// Storage for loaded and decoded images. /// Storage for loaded and decoded images.
pub struct ImageStore { pub struct ImageStore {
loader: Rc<dyn Loader>, loader: Arc<dyn Loader>,
files: HashMap<FileHash, ImageId>, files: HashMap<FileHash, ImageId>,
images: Vec<Image>, images: Vec<Image>,
} }
impl ImageStore { impl ImageStore {
/// Create a new, empty image store. /// Create a new, empty image store.
pub fn new(loader: Rc<dyn Loader>) -> Self { pub fn new(loader: Arc<dyn Loader>) -> Self {
Self { Self {
loader, loader,
files: HashMap::new(), files: HashMap::new(),

View File

@ -1,4 +1,4 @@
use std::rc::Rc; use std::sync::Arc;
use super::Regions; use super::Regions;
use crate::frame::Frame; use crate::frame::Frame;
@ -7,12 +7,12 @@ use crate::geom::{Length, Size, Spec};
/// Constrain a frame with constraints. /// Constrain a frame with constraints.
pub trait Constrain { pub trait Constrain {
/// Reference-count the frame and wrap it with constraints. /// Reference-count the frame and wrap it with constraints.
fn constrain(self, cts: Constraints) -> Constrained<Rc<Frame>>; fn constrain(self, cts: Constraints) -> Constrained<Arc<Frame>>;
} }
impl Constrain for Frame { impl Constrain for Frame {
fn constrain(self, cts: Constraints) -> Constrained<Rc<Frame>> { fn constrain(self, cts: Constraints) -> Constrained<Arc<Frame>> {
Constrained::new(Rc::new(self), cts) Constrained::new(Arc::new(self), cts)
} }
} }

View File

@ -1,6 +1,6 @@
use std::cmp::Reverse; use std::cmp::Reverse;
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc; use std::sync::Arc;
use itertools::Itertools; use itertools::Itertools;
@ -65,7 +65,7 @@ impl LayoutCache {
&mut self, &mut self,
hash: u64, hash: u64,
regions: &Regions, regions: &Regions,
) -> Option<Vec<Constrained<Rc<Frame>>>> { ) -> Option<Vec<Constrained<Arc<Frame>>>> {
self.frames self.frames
.get_mut(&hash)? .get_mut(&hash)?
.iter_mut() .iter_mut()
@ -193,7 +193,7 @@ impl LayoutCache {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct FramesEntry { pub struct FramesEntry {
/// The cached frames for a node. /// The cached frames for a node.
frames: Vec<Constrained<Rc<Frame>>>, frames: Vec<Constrained<Arc<Frame>>>,
/// How nested the frame was in the context is was originally appearing in. /// How nested the frame was in the context is was originally appearing in.
level: usize, level: usize,
/// For how long the element already exists. /// For how long the element already exists.
@ -209,7 +209,7 @@ pub struct FramesEntry {
impl FramesEntry { impl FramesEntry {
/// Construct a new instance. /// Construct a new instance.
pub fn new(frames: Vec<Constrained<Rc<Frame>>>, level: usize) -> Self { pub fn new(frames: Vec<Constrained<Arc<Frame>>>, level: usize) -> Self {
Self { Self {
frames, frames,
level, level,
@ -222,7 +222,7 @@ impl FramesEntry {
/// Checks if the cached frames are valid in the given regions and returns /// Checks if the cached frames are valid in the given regions and returns
/// them if so. /// them if so.
pub fn lookup(&mut self, regions: &Regions) -> Option<Vec<Constrained<Rc<Frame>>>> { pub fn lookup(&mut self, regions: &Regions) -> Option<Vec<Constrained<Arc<Frame>>>> {
self.check(regions).then(|| { self.check(regions).then(|| {
self.temperature[0] = self.temperature[0].saturating_add(1); self.temperature[0] = self.temperature[0].saturating_add(1);
self.frames.clone() self.frames.clone()
@ -396,9 +396,9 @@ mod tests {
use crate::geom::{Size, Spec}; use crate::geom::{Size, Spec};
use crate::layout::Constraints; use crate::layout::Constraints;
fn empty_frames() -> Vec<Constrained<Rc<Frame>>> { fn empty_frames() -> Vec<Constrained<Arc<Frame>>> {
vec![Constrained { vec![Constrained {
item: Rc::new(Frame::default()), item: Arc::new(Frame::default()),
cts: Constraints::new(Spec::splat(false)), cts: Constraints::new(Spec::splat(false)),
}] }]
} }

View File

@ -13,7 +13,7 @@ pub use regions::*;
use std::any::Any; use std::any::Any;
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::rc::Rc; use std::sync::Arc;
use crate::eval::{StyleChain, Styled}; use crate::eval::{StyleChain, Styled};
use crate::font::FontStore; use crate::font::FontStore;
@ -29,7 +29,7 @@ pub struct RootNode(pub Vec<Styled<PageNode>>);
impl RootNode { impl RootNode {
/// Layout the document into a sequence of frames, one per page. /// Layout the document into a sequence of frames, one per page.
pub fn layout(&self, ctx: &mut Context) -> Vec<Rc<Frame>> { pub fn layout(&self, ctx: &mut Context) -> Vec<Arc<Frame>> {
let (mut ctx, styles) = LayoutContext::new(ctx); let (mut ctx, styles) = LayoutContext::new(ctx);
self.0 self.0
.iter() .iter()
@ -56,17 +56,17 @@ pub trait Layout {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>>; ) -> Vec<Constrained<Arc<Frame>>>;
/// Convert to a packed node. /// Convert to a packed node.
fn pack(self) -> PackedNode fn pack(self) -> PackedNode
where where
Self: Debug + Hash + Sized + 'static, Self: Debug + Hash + Sized + Sync + Send + 'static,
{ {
PackedNode { PackedNode {
#[cfg(feature = "layout-cache")] #[cfg(feature = "layout-cache")]
hash: self.hash64(), hash: self.hash64(),
node: Rc::new(self), node: Arc::new(self),
} }
} }
} }
@ -112,7 +112,7 @@ impl Layout for EmptyNode {
_: &mut LayoutContext, _: &mut LayoutContext,
regions: &Regions, regions: &Regions,
_: StyleChain, _: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
let size = regions.expand.select(regions.current, Size::zero()); let size = regions.expand.select(regions.current, Size::zero());
let mut cts = Constraints::new(regions.expand); let mut cts = Constraints::new(regions.expand);
cts.exact = regions.current.filter(regions.expand); cts.exact = regions.current.filter(regions.expand);
@ -124,7 +124,7 @@ impl Layout for EmptyNode {
#[derive(Clone)] #[derive(Clone)]
pub struct PackedNode { pub struct PackedNode {
/// The type-erased node. /// The type-erased node.
node: Rc<dyn Bounds>, node: Arc<dyn Bounds>,
/// A precomputed hash for the node. /// A precomputed hash for the node.
#[cfg(feature = "layout-cache")] #[cfg(feature = "layout-cache")]
hash: u64, hash: u64,
@ -205,7 +205,7 @@ impl Layout for PackedNode {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
let styles = styles.barred(self.node.as_any().type_id()); let styles = styles.barred(self.node.as_any().type_id());
#[cfg(not(feature = "layout-cache"))] #[cfg(not(feature = "layout-cache"))]
@ -243,10 +243,7 @@ impl Layout for PackedNode {
}) })
} }
fn pack(self) -> PackedNode fn pack(self) -> PackedNode {
where
Self: Sized + Hash + 'static,
{
self self
} }
} }
@ -266,8 +263,8 @@ impl Debug for PackedNode {
impl PartialEq for PackedNode { impl PartialEq for PackedNode {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
std::ptr::eq( std::ptr::eq(
Rc::as_ptr(&self.node) as *const (), Arc::as_ptr(&self.node) as *const (),
Rc::as_ptr(&other.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 as_any(&self) -> &dyn Any;
fn hash64(&self) -> u64; fn hash64(&self) -> u64;
} }
impl<T> Bounds for T impl<T> Bounds for T
where where
T: Layout + Hash + Debug + 'static, T: Layout + Hash + Debug + Sync + Send + 'static,
{ {
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self self
@ -320,7 +317,7 @@ impl Layout for SizedNode {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
let is_auto = self.sizing.map_is_none(); let is_auto = self.sizing.map_is_none();
let is_rel = self.sizing.map(|s| s.map_or(false, Linear::is_relative)); 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. // Ensure frame size matches regions size if expansion is on.
let target = regions.expand.select(regions.current, frame.size); 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 // 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 // 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, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
let mut frames = self.child.layout(ctx, regions, styles); let mut frames = self.child.layout(ctx, regions, styles);
for Constrained { item: frame, .. } in &mut frames { for Constrained { item: frame, .. } in &mut frames {
let shape = Shape::filled(Geometry::Rect(frame.size), self.fill); 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 frames
} }
@ -399,11 +396,11 @@ impl Layout for StrokeNode {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
let mut frames = self.child.layout(ctx, regions, styles); let mut frames = self.child.layout(ctx, regions, styles);
for Constrained { item: frame, .. } in &mut frames { for Constrained { item: frame, .. } in &mut frames {
let shape = Shape::stroked(Geometry::Rect(frame.size), self.stroke); 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 frames
} }

View File

@ -52,7 +52,7 @@ pub mod parse;
pub mod source; pub mod source;
pub mod syntax; pub mod syntax;
use std::rc::Rc; use std::sync::Arc;
use crate::diag::TypResult; use crate::diag::TypResult;
use crate::eval::{Eval, EvalContext, Module, Scope, StyleMap}; 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. /// The core context which holds the loader, configuration and cached artifacts.
pub struct Context { pub struct Context {
/// The loader the context was created with. /// The loader the context was created with.
pub loader: Rc<dyn Loader>, pub loader: Arc<dyn Loader>,
/// Stores loaded source files. /// Stores loaded source files.
pub sources: SourceStore, pub sources: SourceStore,
/// Stores parsed font faces. /// Stores parsed font faces.
@ -88,7 +88,7 @@ pub struct Context {
impl Context { impl Context {
/// Create a new context with the default settings. /// Create a new context with the default settings.
pub fn new(loader: Rc<dyn Loader>) -> Self { pub fn new(loader: Arc<dyn Loader>) -> Self {
Self::builder().build(loader) Self::builder().build(loader)
} }
@ -124,7 +124,7 @@ impl Context {
/// Returns either a vector of frames representing individual pages or /// Returns either a vector of frames representing individual pages or
/// diagnostics in the form of a vector of error message with file and span /// diagnostics in the form of a vector of error message with file and span
/// information. /// information.
pub fn typeset(&mut self, id: SourceId) -> TypResult<Vec<Rc<Frame>>> { pub fn typeset(&mut self, id: SourceId) -> TypResult<Vec<Arc<Frame>>> {
let module = self.evaluate(id)?; let module = self.evaluate(id)?;
let tree = module.into_root(); let tree = module.into_root();
let frames = tree.layout(self); let frames = tree.layout(self);
@ -183,11 +183,11 @@ impl ContextBuilder {
/// Finish building the context by providing the `loader` used to load /// Finish building the context by providing the `loader` used to load
/// fonts, images, source files and other resources. /// fonts, images, source files and other resources.
pub fn build(self, loader: Rc<dyn Loader>) -> Context { pub fn build(self, loader: Arc<dyn Loader>) -> Context {
Context { Context {
sources: SourceStore::new(Rc::clone(&loader)), sources: SourceStore::new(Arc::clone(&loader)),
fonts: FontStore::new(Rc::clone(&loader)), fonts: FontStore::new(Arc::clone(&loader)),
images: ImageStore::new(Rc::clone(&loader)), images: ImageStore::new(Arc::clone(&loader)),
loader, loader,
#[cfg(feature = "layout-cache")] #[cfg(feature = "layout-cache")]
layout_cache: LayoutCache::new(self.policy, self.max_size), layout_cache: LayoutCache::new(self.policy, self.max_size),

View File

@ -27,7 +27,7 @@ impl Layout for AlignNode {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
// The child only needs to expand along an axis if there's no alignment. // The child only needs to expand along an axis if there's no alignment.
let mut pod = regions.clone(); let mut pod = regions.clone();
pod.expand &= self.aligns.map_is_none(); pod.expand &= self.aligns.map_is_none();
@ -49,7 +49,7 @@ impl Layout for AlignNode {
let target = regions.expand.select(current, frame.size); let target = regions.expand.select(current, frame.size);
let default = Spec::new(Align::Left, Align::Top); let default = Spec::new(Align::Left, Align::Top);
let aligns = self.aligns.unwrap_or(default); let aligns = self.aligns.unwrap_or(default);
Rc::make_mut(frame).resize(target, aligns); Arc::make_mut(frame).resize(target, aligns);
// Set constraints. // Set constraints.
cts.expand = regions.expand; cts.expand = regions.expand;

View File

@ -37,7 +37,7 @@ impl Layout for ColumnsNode {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
let columns = self.columns.get(); let columns = self.columns.get();
// Separating the infinite space into infinite columns does not make // Separating the infinite space into infinite columns does not make

View File

@ -18,7 +18,7 @@ impl Layout for FlowNode {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
FlowLayouter::new(self, regions.clone()).layout(ctx, styles) FlowLayouter::new(self, regions.clone()).layout(ctx, styles)
} }
} }
@ -72,7 +72,7 @@ struct FlowLayouter<'a> {
/// Spacing and layouted nodes. /// Spacing and layouted nodes.
items: Vec<FlowItem>, items: Vec<FlowItem>,
/// Finished frames for previous regions. /// Finished frames for previous regions.
finished: Vec<Constrained<Rc<Frame>>>, finished: Vec<Constrained<Arc<Frame>>>,
} }
/// A prepared item in a flow layout. /// A prepared item in a flow layout.
@ -82,9 +82,9 @@ enum FlowItem {
/// Fractional spacing between other items. /// Fractional spacing between other items.
Fractional(Fractional), Fractional(Fractional),
/// A frame for a layouted child node and how to align it. /// A frame for a layouted child node and how to align it.
Frame(Rc<Frame>, Spec<Align>), Frame(Arc<Frame>, Spec<Align>),
/// An absolutely placed frame. /// An absolutely placed frame.
Placed(Rc<Frame>), Placed(Arc<Frame>),
} }
impl<'a> FlowLayouter<'a> { impl<'a> FlowLayouter<'a> {
@ -113,7 +113,7 @@ impl<'a> FlowLayouter<'a> {
mut self, mut self,
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
styles: StyleChain, styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
for styled in self.children { for styled in self.children {
let styles = styled.map.chain(&styles); let styles = styled.map.chain(&styles);
match styled.item { match styled.item {

View File

@ -38,7 +38,7 @@ impl Layout for GridNode {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
// Prepare grid layout by unifying content and gutter tracks. // Prepare grid layout by unifying content and gutter tracks.
let mut layouter = GridLayouter::new(self, regions.clone(), styles); let mut layouter = GridLayouter::new(self, regions.clone(), styles);
@ -114,7 +114,7 @@ struct GridLayouter<'a> {
/// Constraints for the active region. /// Constraints for the active region.
cts: Constraints, cts: Constraints,
/// Frames for finished regions. /// Frames for finished regions.
finished: Vec<Constrained<Rc<Frame>>>, finished: Vec<Constrained<Arc<Frame>>>,
} }
/// Produced by initial row layout, auto and linear rows are already finished, /// 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. /// Layout the grid row-by-row.
fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Rc<Frame>>> { fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Arc<Frame>>> {
for y in 0 .. self.rows.len() { for y in 0 .. self.rows.len() {
// Skip to next region if current one is full, but only for content // Skip to next region if current one is full, but only for content
// rows, not for gutter rows. // rows, not for gutter rows.

View File

@ -51,7 +51,7 @@ impl Layout for HeadingNode {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
let upscale = (1.6 - 0.1 * self.level as f64).max(0.75); let upscale = (1.6 - 0.1 * self.level as f64).max(0.75);
let mut passed = StyleMap::new(); let mut passed = StyleMap::new();
@ -82,7 +82,7 @@ impl Layout for HeadingNode {
// FIXME: Constraints and region size. // FIXME: Constraints and region size.
for Constrained { item: frame, .. } in &mut frames { 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.size.y += above + below;
frame.translate(Point::with_y(above)); frame.translate(Point::with_y(above));
} }

View File

@ -19,12 +19,12 @@ impl Layout for HideNode {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
let mut frames = self.0.layout(ctx, regions, styles); let mut frames = self.0.layout(ctx, regions, styles);
// Clear the frames. // Clear the frames.
for Constrained { item: frame, .. } in &mut frames { for Constrained { item: frame, .. } in &mut frames {
*frame = Rc::new(Frame { elements: vec![], ..**frame }); *frame = Arc::new(Frame { elements: vec![], ..**frame });
} }
frames frames

View File

@ -44,7 +44,7 @@ impl Layout for ImageNode {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
let img = ctx.images.get(self.0); let img = ctx.images.get(self.0);
let pxw = img.width() as f64; let pxw = img.width() as f64;
let pxh = img.height() as f64; let pxh = img.height() as f64;

View File

@ -10,13 +10,14 @@ pub struct LinkNode;
#[class] #[class]
impl LinkNode { impl LinkNode {
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> {
let url: String = args.expect::<EcoString>("url")?.into(); let url = args.expect::<EcoString>("url")?;
let body = args.find().unwrap_or_else(|| { let body = args.find().unwrap_or_else(|| {
let mut text = url.as_str(); let mut text = url.as_str();
for prefix in ["mailto:", "tel:"] { for prefix in ["mailto:", "tel:"] {
text = text.trim_start_matches(prefix); 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))) Ok(body.styled(TextNode::LINK, Some(url)))

View File

@ -39,7 +39,7 @@ impl<L: ListKind> Layout for ListNode<L> {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
let em = styles.get(TextNode::SIZE).abs; let em = styles.get(TextNode::SIZE).abs;
let label_indent = styles.get(Self::LABEL_INDENT).resolve(em); let label_indent = styles.get(Self::LABEL_INDENT).resolve(em);
let body_indent = styles.get(Self::BODY_INDENT).resolve(em); let body_indent = styles.get(Self::BODY_INDENT).resolve(em);
@ -65,7 +65,7 @@ impl<L: ListKind> Layout for ListNode<L> {
} }
/// How to label a list. /// 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. /// Return the item's label.
fn label(&self) -> EcoString; fn label(&self) -> EcoString;
} }

View File

@ -61,7 +61,7 @@ macro_rules! prelude {
prelude! { prelude! {
pub use std::fmt::{self, Debug, Formatter}; pub use std::fmt::{self, Debug, Formatter};
pub use std::num::NonZeroUsize; pub use std::num::NonZeroUsize;
pub use std::rc::Rc; pub use std::sync::Arc;
pub use std::hash::Hash; pub use std::hash::Hash;
pub use typst_macros::class; pub use typst_macros::class;

View File

@ -37,7 +37,7 @@ impl Layout for PadNode {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
// Layout child into padded regions. // Layout child into padded regions.
let pod = regions.map(|size| shrink(size, self.padding)); let pod = regions.map(|size| shrink(size, self.padding));
let mut frames = self.child.layout(ctx, &pod, styles); 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); let offset = Point::new(padding.left, padding.top);
// Grow the frame and translate everything in the frame inwards. // 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.size = padded;
frame.translate(offset); frame.translate(offset);

View File

@ -70,7 +70,7 @@ impl PageNode {
impl PageNode { impl PageNode {
/// Layout the page run into a sequence of frames, one per page. /// Layout the page run into a sequence of frames, one per page.
pub fn layout(&self, ctx: &mut LayoutContext, styles: StyleChain) -> Vec<Rc<Frame>> { pub fn layout(&self, ctx: &mut LayoutContext, styles: StyleChain) -> Vec<Arc<Frame>> {
// When one of the lengths is infinite the page fits its content along // When one of the lengths is infinite the page fits its content along
// that axis. // that axis.
let width = styles.get(Self::WIDTH).unwrap_or(Length::inf()); let width = styles.get(Self::WIDTH).unwrap_or(Length::inf());

View File

@ -1,7 +1,7 @@
//! Paragraph layout. //! Paragraph layout.
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::rc::Rc; use std::sync::Arc;
use itertools::Either; use itertools::Either;
use unicode_bidi::{BidiInfo, Level}; use unicode_bidi::{BidiInfo, Level};
@ -9,7 +9,7 @@ use xi_unicode::LineBreakIterator;
use super::prelude::*; use super::prelude::*;
use super::{shape, ShapedText, SpacingKind, TextNode}; 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. /// A node that arranges its children into a paragraph.
#[derive(Hash)] #[derive(Hash)]
@ -75,7 +75,7 @@ impl Layout for ParNode {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
// Collect all text into one string used for BiDi analysis. // Collect all text into one string used for BiDi analysis.
let text = self.collect_text(); let text = self.collect_text();
@ -253,7 +253,7 @@ impl<'a> ParLayouter<'a> {
let size = Size::new(regions.current.x, regions.base.y); let size = Size::new(regions.current.x, regions.base.y);
let pod = Regions::one(size, regions.base, Spec::splat(false)); let pod = Regions::one(size, regions.base, Spec::splat(false));
let frame = node.layout(ctx, &pod, styles).remove(0); 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); ranges.push(range);
} }
} }
@ -271,7 +271,7 @@ impl<'a> ParLayouter<'a> {
self, self,
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: Regions, regions: Regions,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
let mut stack = LineStack::new(self.leading, regions); let mut stack = LineStack::new(self.leading, regions);
// The current line attempt. // The current line attempt.
@ -582,7 +582,7 @@ struct LineStack<'a> {
regions: Regions, regions: Regions,
size: Size, size: Size,
lines: Vec<LineLayout<'a>>, lines: Vec<LineLayout<'a>>,
finished: Vec<Constrained<Rc<Frame>>>, finished: Vec<Constrained<Arc<Frame>>>,
cts: Constraints, cts: Constraints,
overflowing: bool, overflowing: bool,
fractional: bool, fractional: bool,
@ -650,7 +650,7 @@ impl<'a> LineStack<'a> {
} }
/// Finish the last region and return the built frames. /// Finish the last region and return the built frames.
fn finish(mut self, ctx: &LayoutContext) -> Vec<Constrained<Rc<Frame>>> { fn finish(mut self, ctx: &LayoutContext) -> Vec<Constrained<Arc<Frame>>> {
self.finish_region(ctx); self.finish_region(ctx);
self.finished self.finished
} }

View File

@ -26,7 +26,7 @@ impl Layout for PlaceNode {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
let out_of_flow = self.out_of_flow(); let out_of_flow = self.out_of_flow();
// The pod is the base area of the region because for absolute // 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 // If expansion is off, zero all sizes so that we don't take up any
// space in our parent. Otherwise, respect the expand settings. // space in our parent. Otherwise, respect the expand settings.
let target = regions.expand.select(regions.current, Size::zero()); 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 // Set base constraint because our pod size is base and exact
// constraints if we needed to expand or offset. // constraints if we needed to expand or offset.

View File

@ -66,7 +66,7 @@ impl<S: ShapeKind> Layout for ShapeNode<S> {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
let mut frames; let mut frames;
if let Some(child) = &self.child { if let Some(child) = &self.child {
let mut padding = styles.get(Self::PADDING); let mut padding = styles.get(Self::PADDING);
@ -118,7 +118,7 @@ impl<S: ShapeKind> Layout for ShapeNode<S> {
frames = vec![Frame::new(size).constrain(Constraints::tight(regions))]; 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. // Add fill and/or stroke.
let fill = styles.get(Self::FILL); let fill = styles.get(Self::FILL);
@ -149,7 +149,7 @@ impl<S: ShapeKind> Layout for ShapeNode<S> {
} }
/// Categorizes shapes. /// Categorizes shapes.
pub trait ShapeKind: Debug + Default + Hash + 'static { pub trait ShapeKind: Debug + Default + Hash + Sync + Send + 'static {
const ROUND: bool; const ROUND: bool;
const QUADRATIC: bool; const QUADRATIC: bool;
} }

View File

@ -31,7 +31,7 @@ impl Layout for StackNode {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
StackLayouter::new(self, regions.clone(), styles).layout(ctx) StackLayouter::new(self, regions.clone(), styles).layout(ctx)
} }
} }
@ -90,7 +90,7 @@ struct StackLayouter<'a> {
/// Spacing and layouted nodes. /// Spacing and layouted nodes.
items: Vec<StackItem>, items: Vec<StackItem>,
/// Finished frames for previous regions. /// Finished frames for previous regions.
finished: Vec<Constrained<Rc<Frame>>>, finished: Vec<Constrained<Arc<Frame>>>,
} }
/// A prepared item in a stack layout. /// A prepared item in a stack layout.
@ -100,7 +100,7 @@ enum StackItem {
/// Fractional spacing between other items. /// Fractional spacing between other items.
Fractional(Fractional), Fractional(Fractional),
/// A layouted child node. /// A layouted child node.
Frame(Rc<Frame>, Align), Frame(Arc<Frame>, Align),
} }
impl<'a> StackLayouter<'a> { impl<'a> StackLayouter<'a> {
@ -131,7 +131,7 @@ impl<'a> StackLayouter<'a> {
} }
/// Layout all children. /// Layout all children.
fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Rc<Frame>>> { fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Arc<Frame>>> {
// Spacing to insert before the next node. // Spacing to insert before the next node.
let mut deferred = None; let mut deferred = None;

View File

@ -60,7 +60,7 @@ impl Layout for TableNode {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
let primary = styles.get(Self::PRIMARY); let primary = styles.get(Self::PRIMARY);
let secondary = styles.get(Self::SECONDARY); let secondary = styles.get(Self::SECONDARY);
let thickness = styles.get(Self::THICKNESS); let thickness = styles.get(Self::THICKNESS);

View File

@ -55,7 +55,7 @@ impl TextNode {
#[fold(|a, b| a.into_iter().chain(b).collect())] #[fold(|a, b| a.into_iter().chain(b).collect())]
pub const LINES: Vec<Decoration> = vec![]; pub const LINES: Vec<Decoration> = vec![];
/// An URL the text should link to. /// An URL the text should link to.
pub const LINK: Option<String> = None; pub const LINK: Option<EcoString> = None;
/// The size of the glyphs. /// The size of the glyphs.
#[fold(Linear::compose)] #[fold(Linear::compose)]
@ -211,12 +211,12 @@ castable! {
/// A specific font family like "Arial". /// A specific font family like "Arial".
#[derive(Clone, Eq, PartialEq, Hash)] #[derive(Clone, Eq, PartialEq, Hash)]
pub struct NamedFamily(String); pub struct NamedFamily(EcoString);
impl NamedFamily { impl NamedFamily {
/// Create a named font family variant. /// Create a named font family variant.
pub fn new(string: &str) -> Self { pub fn new(string: &str) -> Self {
Self(string.to_lowercase()) Self(string.to_lowercase().into())
} }
/// The lowercased family name. /// The lowercased family name.

View File

@ -36,7 +36,7 @@ impl<T: TransformKind> Layout for TransformNode<T> {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Arc<Frame>>> {
let origin = styles.get(Self::ORIGIN).unwrap_or(Align::CENTER_HORIZON); let origin = styles.get(Self::ORIGIN).unwrap_or(Align::CENTER_HORIZON);
let matrix = self.kind.matrix(); let matrix = self.kind.matrix();
@ -48,7 +48,7 @@ impl<T: TransformKind> Layout for TransformNode<T> {
.pre_concat(matrix) .pre_concat(matrix)
.pre_concat(Transform::translation(-x, -y)); .pre_concat(Transform::translation(-x, -y));
Rc::make_mut(frame).transform(transform); Arc::make_mut(frame).transform(transform);
} }
frames frames
@ -56,7 +56,7 @@ impl<T: TransformKind> Layout for TransformNode<T> {
} }
/// Kinds of transformations. /// 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<Self>; fn construct(args: &mut Args) -> TypResult<Self>;
fn matrix(&self) -> Transform; fn matrix(&self) -> Transform;
} }

View File

@ -1,7 +1,7 @@
use std::fs::{self, File}; use std::fs::{self, File};
use std::io; use std::io;
use std::path::Path; use std::path::Path;
use std::rc::Rc; use std::sync::Arc;
use memmap2::Mmap; use memmap2::Mmap;
use same_file::Handle; use same_file::Handle;
@ -35,10 +35,10 @@ impl FsLoader {
self 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). /// with the [`Context`](crate::Context).
pub fn wrap(self) -> Rc<Self> { pub fn wrap(self) -> Arc<Self> {
Rc::new(self) Arc::new(self)
} }
/// Search for fonts in the operating system's font directories. /// Search for fonts in the operating system's font directories.

View File

@ -2,7 +2,7 @@ use std::borrow::Cow;
use std::collections::HashMap; use std::collections::HashMap;
use std::io; use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::rc::Rc; use std::sync::Arc;
use super::{FileHash, Loader}; use super::{FileHash, Loader};
use crate::font::FaceInfo; use crate::font::FaceInfo;
@ -31,10 +31,10 @@ impl MemLoader {
self 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). /// with the [`Context`](crate::Context).
pub fn wrap(self) -> Rc<Self> { pub fn wrap(self) -> Arc<Self> {
Rc::new(self) Arc::new(self)
} }
/// Insert a path-file mapping. If the data forms a font, then that font /// Insert a path-file mapping. If the data forms a font, then that font

View File

@ -1,5 +1,5 @@
use std::ops::Range; use std::ops::Range;
use std::rc::Rc; use std::sync::Arc;
use crate::syntax::{Green, GreenNode, NodeKind}; use crate::syntax::{Green, GreenNode, NodeKind};
@ -78,8 +78,8 @@ impl<'a> Reparser<'a> {
impl Reparser<'_> { impl Reparser<'_> {
/// Find the innermost child that is incremental safe. /// Find the innermost child that is incremental safe.
pub fn reparse(&self, green: &mut Rc<GreenNode>) -> Range<usize> { pub fn reparse(&self, green: &mut Arc<GreenNode>) -> Range<usize> {
self.reparse_step(Rc::make_mut(green), 0, TokenMode::Markup, true) self.reparse_step(Arc::make_mut(green), 0, TokenMode::Markup, true)
.unwrap_or_else(|| { .unwrap_or_else(|| {
*green = parse(self.src); *green = parse(self.src);
0 .. self.src.len() 0 .. self.src.len()
@ -167,7 +167,7 @@ impl Reparser<'_> {
if last_kind.succession_rule() != SuccessionRule::Unsafe { if last_kind.succession_rule() != SuccessionRule::Unsafe {
if let Some(range) = match child { if let Some(range) = match child {
Green::Node(node) => self.reparse_step( Green::Node(node) => self.reparse_step(
Rc::make_mut(node), Arc::make_mut(node),
first_start, first_start,
child_mode, child_mode,
outermost, outermost,

View File

@ -12,14 +12,14 @@ pub use resolve::*;
pub use scanner::*; pub use scanner::*;
pub use tokens::*; pub use tokens::*;
use std::rc::Rc; use std::sync::Arc;
use crate::syntax::ast::{Associativity, BinOp, UnOp}; use crate::syntax::ast::{Associativity, BinOp, UnOp};
use crate::syntax::{ErrorPos, Green, GreenNode, NodeKind}; use crate::syntax::{ErrorPos, Green, GreenNode, NodeKind};
use crate::util::EcoString; use crate::util::EcoString;
/// Parse a source file. /// Parse a source file.
pub fn parse(src: &str) -> Rc<GreenNode> { pub fn parse(src: &str) -> Arc<GreenNode> {
let mut p = Parser::new(src, TokenMode::Markup); let mut p = Parser::new(src, TokenMode::Markup);
markup(&mut p, true); markup(&mut p, true);
match p.finish().into_iter().next() { match p.finish().into_iter().next() {

View File

@ -1,4 +1,4 @@
use std::rc::Rc; use std::sync::Arc;
use super::{ use super::{
is_id_continue, is_id_start, is_newline, resolve_hex, resolve_raw, resolve_string, 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. // Special case for empty inline block.
if backticks == 2 { if backticks == 2 {
return NodeKind::Raw(Rc::new(RawNode { return NodeKind::Raw(Arc::new(RawNode {
text: EcoString::new(), text: EcoString::new(),
lang: None, lang: None,
block: false, block: false,
@ -341,7 +341,7 @@ impl<'s> Tokens<'s> {
if found == backticks { if found == backticks {
let end = self.s.index() - found as usize; let end = self.s.index() - found as usize;
NodeKind::Raw(Rc::new(resolve_raw( NodeKind::Raw(Arc::new(resolve_raw(
column, column,
backticks, backticks,
self.s.get(start .. end), self.s.get(start .. end),
@ -393,7 +393,7 @@ impl<'s> Tokens<'s> {
}; };
if terminated { if terminated {
NodeKind::Math(Rc::new(MathNode { NodeKind::Math(Arc::new(MathNode {
formula: self.s.get(start .. end).into(), formula: self.s.get(start .. end).into(),
display, display,
})) }))
@ -581,7 +581,7 @@ mod tests {
} }
fn Raw(text: &str, lang: Option<&str>, block: bool) -> NodeKind { fn Raw(text: &str, lang: Option<&str>, block: bool) -> NodeKind {
NodeKind::Raw(Rc::new(RawNode { NodeKind::Raw(Arc::new(RawNode {
text: text.into(), text: text.into(),
lang: lang.map(Into::into), lang: lang.map(Into::into),
block, block,
@ -589,7 +589,7 @@ mod tests {
} }
fn Math(formula: &str, display: bool) -> NodeKind { 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 { fn Str(string: &str) -> NodeKind {

View File

@ -4,7 +4,7 @@ use std::collections::HashMap;
use std::io; use std::io;
use std::ops::Range; use std::ops::Range;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::rc::Rc; use std::sync::Arc;
use crate::diag::TypResult; use crate::diag::TypResult;
use crate::loading::{FileHash, Loader}; use crate::loading::{FileHash, Loader};
@ -37,14 +37,14 @@ impl SourceId {
/// Storage for loaded source files. /// Storage for loaded source files.
pub struct SourceStore { pub struct SourceStore {
loader: Rc<dyn Loader>, loader: Arc<dyn Loader>,
files: HashMap<FileHash, SourceId>, files: HashMap<FileHash, SourceId>,
sources: Vec<SourceFile>, sources: Vec<SourceFile>,
} }
impl SourceStore { impl SourceStore {
/// Create a new, empty source store. /// Create a new, empty source store.
pub fn new(loader: Rc<dyn Loader>) -> Self { pub fn new(loader: Arc<dyn Loader>) -> Self {
Self { Self {
loader, loader,
files: HashMap::new(), files: HashMap::new(),
@ -125,7 +125,7 @@ pub struct SourceFile {
path: PathBuf, path: PathBuf,
src: String, src: String,
lines: Vec<Line>, lines: Vec<Line>,
root: Rc<GreenNode>, root: Arc<GreenNode>,
} }
impl SourceFile { impl SourceFile {
@ -148,7 +148,7 @@ impl SourceFile {
} }
/// The root node of the file's untyped green tree. /// The root node of the file's untyped green tree.
pub fn root(&self) -> &Rc<GreenNode> { pub fn root(&self) -> &Arc<GreenNode> {
&self.root &self.root
} }

View File

@ -7,7 +7,7 @@ mod span;
use std::fmt::{self, Debug, Display, Formatter}; use std::fmt::{self, Debug, Display, Formatter};
use std::ops::Range; use std::ops::Range;
use std::rc::Rc; use std::sync::Arc;
pub use highlight::*; pub use highlight::*;
pub use pretty::*; pub use pretty::*;
@ -24,7 +24,7 @@ use crate::util::EcoString;
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub enum Green { pub enum Green {
/// A reference-counted inner node. /// A reference-counted inner node.
Node(Rc<GreenNode>), Node(Arc<GreenNode>),
/// A terminal, owned token. /// A terminal, owned token.
Token(GreenData), Token(GreenData),
} }
@ -76,7 +76,7 @@ impl Green {
pub fn convert(&mut self, kind: NodeKind) { pub fn convert(&mut self, kind: NodeKind) {
match self { match self {
Self::Node(node) => { Self::Node(node) => {
let node = Rc::make_mut(node); let node = Arc::make_mut(node);
node.erroneous |= kind.is_error(); node.erroneous |= kind.is_error();
node.data.kind = kind; node.data.kind = kind;
} }
@ -187,12 +187,12 @@ impl GreenNode {
impl From<GreenNode> for Green { impl From<GreenNode> for Green {
fn from(node: GreenNode) -> Self { fn from(node: GreenNode) -> Self {
Rc::new(node).into() Arc::new(node).into()
} }
} }
impl From<Rc<GreenNode>> for Green { impl From<Arc<GreenNode>> for Green {
fn from(node: Rc<GreenNode>) -> Self { fn from(node: Arc<GreenNode>) -> Self {
Self::Node(node) Self::Node(node)
} }
} }
@ -259,7 +259,7 @@ pub struct RedNode {
impl RedNode { impl RedNode {
/// Create a new red node from a root [`GreenNode`]. /// Create a new red node from a root [`GreenNode`].
pub fn from_root(root: Rc<GreenNode>, id: SourceId) -> Self { pub fn from_root(root: Arc<GreenNode>, id: SourceId) -> Self {
Self { id, offset: 0, green: root.into() } Self { id, offset: 0, green: root.into() }
} }
@ -611,9 +611,9 @@ pub enum NodeKind {
Emph, Emph,
/// An arbitrary number of backticks followed by inner contents, terminated /// An arbitrary number of backticks followed by inner contents, terminated
/// with the same number of backticks: `` `...` ``. /// with the same number of backticks: `` `...` ``.
Raw(Rc<RawNode>), Raw(Arc<RawNode>),
/// Dollar signs surrounding inner contents. /// Dollar signs surrounding inner contents.
Math(Rc<MathNode>), Math(Arc<MathNode>),
/// A section heading: `= Introduction`. /// A section heading: `= Introduction`.
Heading, Heading,
/// An item in an unordered list: `- ...`. /// An item in an unordered list: `- ...`.

View File

@ -3,9 +3,9 @@ use std::cmp::Ordering;
use std::fmt::{self, Debug, Display, Formatter, Write}; use std::fmt::{self, Debug, Display, Formatter, Write};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::ops::{Add, AddAssign, Deref}; 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. /// Create a new [`EcoString`] from a format string.
macro_rules! format_eco { macro_rules! format_eco {
@ -27,13 +27,13 @@ pub struct EcoString(Repr);
#[derive(Clone)] #[derive(Clone)]
enum Repr { enum Repr {
Small { buf: [u8; LIMIT], len: u8 }, Small { buf: [u8; LIMIT], len: u8 },
Large(Rc<String>), Large(Arc<String>),
} }
/// The maximum number of bytes that can be stored inline. /// The maximum number of bytes that can be stored inline.
/// ///
/// The value is chosen such that an `EcoString` fits exactly into 16 bytes /// 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). /// platforms).
/// ///
/// Must be at least 4 to hold any char. /// Must be at least 4 to hold any char.
@ -50,7 +50,7 @@ impl EcoString {
if capacity <= LIMIT { if capacity <= LIMIT {
Self::new() Self::new()
} else { } 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()); buf[.. len].copy_from_slice(slice.as_bytes());
Repr::Small { buf, len: len as u8 } Repr::Small { buf, len: len as u8 }
} else { } 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])); 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); let mut spilled = String::with_capacity(new);
spilled.push_str(self); spilled.push_str(self);
spilled.push_str(string); 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; *len -= c.len_utf8() as u8;
} }
Repr::Large(rc) => { Repr::Large(rc) => {
Rc::make_mut(rc).pop(); Arc::make_mut(rc).pop();
} }
} }
Some(c) Some(c)
@ -143,8 +143,8 @@ impl EcoString {
match &mut self.0 { match &mut self.0 {
Repr::Small { len, .. } => *len = 0, Repr::Small { len, .. } => *len = 0,
Repr::Large(rc) => { Repr::Large(rc) => {
if Rc::strong_count(rc) == 1 { if Arc::strong_count(rc) == 1 {
Rc::make_mut(rc).clear(); Arc::make_mut(rc).clear();
} else { } else {
*self = Self::new(); *self = Self::new();
} }
@ -351,11 +351,17 @@ impl From<String> for EcoString {
} }
} }
impl From<&EcoString> for String {
fn from(s: &EcoString) -> Self {
s.as_str().to_owned()
}
}
impl From<EcoString> for String { impl From<EcoString> for String {
fn from(s: EcoString) -> Self { fn from(s: EcoString) -> Self {
match s.0 { match s.0 {
Repr::Small { .. } => s.as_str().to_owned(), Repr::Small { .. } => s.as_str().to_owned(),
Repr::Large(rc) => Rc::take(rc), Repr::Large(rc) => Arc::take(rc),
} }
} }
} }

View File

@ -11,7 +11,7 @@ use std::cell::RefMut;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::ops::Range; use std::ops::Range;
use std::path::{Component, Path, PathBuf}; use std::path::{Component, Path, PathBuf};
use std::rc::Rc; use std::sync::Arc;
/// Additional methods for strings. /// Additional methods for strings.
pub trait StrExt { pub trait StrExt {
@ -62,18 +62,18 @@ impl<T> OptionExt<T> for Option<T> {
} }
/// Additional methods for reference-counted pointers. /// Additional methods for reference-counted pointers.
pub trait RcExt<T> { pub trait ArcExt<T> {
/// Takes the inner value if there is exactly one strong reference and /// Takes the inner value if there is exactly one strong reference and
/// clones it otherwise. /// clones it otherwise.
fn take(self) -> T; fn take(self) -> T;
} }
impl<T> RcExt<T> for Rc<T> impl<T> ArcExt<T> for Arc<T>
where where
T: Clone, T: Clone,
{ {
fn take(self) -> T { fn take(self) -> T {
match Rc::try_unwrap(self) { match Arc::try_unwrap(self) {
Ok(v) => v, Ok(v) => v,
Err(rc) => (*rc).clone(), Err(rc) => (*rc).clone(),
} }

View File

@ -3,7 +3,7 @@ use std::ffi::OsStr;
use std::fs; use std::fs;
use std::ops::Range; use std::ops::Range;
use std::path::Path; use std::path::Path;
use std::rc::Rc; use std::sync::Arc;
use tiny_skia as sk; use tiny_skia as sk;
use walkdir::WalkDir; use walkdir::WalkDir;
@ -258,7 +258,7 @@ fn test_part(
line: usize, line: usize,
debug: bool, debug: bool,
rng: &mut LinearShift, rng: &mut LinearShift,
) -> (bool, bool, Vec<Rc<Frame>>) { ) -> (bool, bool, Vec<Arc<Frame>>) {
let mut ok = true; let mut ok = true;
let id = ctx.sources.provide(src_path, src); let id = ctx.sources.provide(src_path, src);
@ -483,7 +483,7 @@ fn test_incremental(
ctx: &mut Context, ctx: &mut Context,
i: usize, i: usize,
tree: &RootNode, tree: &RootNode,
frames: &[Rc<Frame>], frames: &[Arc<Frame>],
) -> bool { ) -> bool {
let mut ok = true; let mut ok = true;
@ -527,7 +527,7 @@ fn test_incremental(
} }
/// Draw all frames into one image with padding in between. /// Draw all frames into one image with padding in between.
fn render(ctx: &mut Context, frames: &[Rc<Frame>]) -> sk::Pixmap { fn render(ctx: &mut Context, frames: &[Arc<Frame>]) -> sk::Pixmap {
let pixel_per_pt = 2.0; let pixel_per_pt = 2.0;
let pixmaps: Vec<_> = frames let pixmaps: Vec<_> = frames
.iter() .iter()