diff --git a/src/eval/template.rs b/src/eval/template.rs index b1559b8fa..42c93b56d 100644 --- a/src/eval/template.rs +++ b/src/eval/template.rs @@ -1,5 +1,6 @@ use std::convert::TryFrom; use std::fmt::{self, Debug, Formatter}; +use std::hash::Hash; use std::mem; use std::ops::{Add, AddAssign}; use std::rc::Rc; @@ -8,8 +9,8 @@ use super::Str; use crate::diag::StrResult; use crate::geom::{Align, Dir, GenAxis, Length, Linear, Sides, Size}; use crate::layout::{ - BlockNode, Decoration, InlineNode, PadNode, PageNode, ParChild, ParNode, Spacing, - StackChild, StackNode, + BlockLevel, BlockNode, Decoration, InlineLevel, InlineNode, PadNode, PageNode, + ParChild, ParNode, Spacing, StackChild, StackNode, }; use crate::style::Style; use crate::util::EcoString; @@ -57,9 +58,9 @@ impl Template { pub fn from_inline(f: F) -> Self where F: Fn(&Style) -> T + 'static, - T: Into, + T: InlineLevel + Hash + 'static, { - let node = TemplateNode::Inline(Rc::new(move |s| f(s).into())); + let node = TemplateNode::Inline(Rc::new(move |s| f(s).pack())); Self(Rc::new(vec![node])) } @@ -67,9 +68,9 @@ impl Template { pub fn from_block(f: F) -> Self where F: Fn(&Style) -> T + 'static, - T: Into, + T: BlockLevel + Hash + 'static, { - let node = TemplateNode::Block(Rc::new(move |s| f(s).into())); + let node = TemplateNode::Block(Rc::new(move |s| f(s).pack())); Self(Rc::new(vec![node])) } @@ -396,7 +397,7 @@ impl PageBuilder { let Self { size, padding, hard } = self; (!child.children.is_empty() || (keep && hard)).then(|| PageNode { size, - child: PadNode { padding, child: child.into() }.into(), + child: PadNode { padding, child: child.pack() }.pack(), }) } } @@ -502,7 +503,7 @@ impl ParBuilder { fn build(self) -> Option { let Self { align, dir, leading, children, .. } = self; (!children.is_empty()) - .then(|| StackChild::Node(ParNode { dir, leading, children }.into(), align)) + .then(|| StackChild::Node(ParNode { dir, leading, children }.pack(), align)) } } diff --git a/src/eval/walk.rs b/src/eval/walk.rs index 9dd7cd2e9..cd9809a29 100644 --- a/src/eval/walk.rs +++ b/src/eval/walk.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use super::{Eval, EvalContext, Str, Template, Value}; use crate::diag::TypResult; use crate::geom::Align; -use crate::layout::{ParChild, ParNode, Spacing, StackChild, StackNode}; +use crate::layout::{BlockLevel, ParChild, ParNode, Spacing, StackChild, StackNode}; use crate::syntax::*; use crate::util::BoolExt; @@ -118,9 +118,9 @@ fn walk_item(ctx: &mut EvalContext, label: Str, body: Template) { StackNode { dir: style.dir, children: vec![ - StackChild::Node(label.into(), Align::Start), + StackChild::Node(label.pack(), Align::Start), StackChild::Spacing(Spacing::Linear((style.text.size / 2.0).into())), - StackChild::Node(body.to_stack(&style).into(), Align::Start), + StackChild::Node(body.to_stack(&style).pack(), Align::Start), ], } }); diff --git a/src/layout/grid.rs b/src/layout/grid.rs index 7220d7c2c..57986b48a 100644 --- a/src/layout/grid.rs +++ b/src/layout/grid.rs @@ -1,8 +1,7 @@ use super::*; /// A node that arranges its children in a grid. -#[derive(Debug)] -#[cfg_attr(feature = "layout-cache", derive(Hash))] +#[derive(Debug, Hash)] pub struct GridNode { /// Defines sizing for content rows and columns. pub tracks: Spec>, @@ -40,12 +39,6 @@ impl BlockLevel for GridNode { } } -impl From for BlockNode { - fn from(node: GridNode) -> Self { - Self::new(node) - } -} - /// Performs grid layout. struct GridLayouter<'a> { /// The original expand state of the target region. diff --git a/src/layout/image.rs b/src/layout/image.rs index 59b4c6efd..b410895b5 100644 --- a/src/layout/image.rs +++ b/src/layout/image.rs @@ -2,8 +2,7 @@ use super::*; use crate::image::ImageId; /// An image node. -#[derive(Debug)] -#[cfg_attr(feature = "layout-cache", derive(Hash))] +#[derive(Debug, Hash)] pub struct ImageNode { /// The id of the image file. pub id: ImageId, @@ -43,9 +42,3 @@ impl InlineLevel for ImageNode { frame } } - -impl From for InlineNode { - fn from(node: ImageNode) -> Self { - Self::new(node) - } -} diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 651daa21a..ffbf26685 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -29,6 +29,7 @@ pub use stack::*; pub use text::*; use std::fmt::{self, Debug, Formatter}; +use std::hash::{Hash, Hasher}; use std::rc::Rc; use crate::font::FontStore; @@ -37,13 +38,6 @@ use crate::image::ImageStore; use crate::util::OptionExt; use crate::Context; -#[cfg(feature = "layout-cache")] -use { - fxhash::FxHasher64, - std::any::Any, - std::hash::{Hash, Hasher}, -}; - /// Layout a page-level node into a collection of frames. pub fn layout(ctx: &mut Context, node: &T) -> Vec> where @@ -129,9 +123,21 @@ pub trait BlockLevel: Debug { ctx: &mut LayoutContext, regions: &Regions, ) -> Vec>>; + + /// Convert to a packed block-level node. + fn pack(self) -> BlockNode + where + Self: Sized + Hash + 'static, + { + BlockNode { + #[cfg(feature = "layout-cache")] + hash: hash_node(&self), + node: Rc::new(self), + } + } } -/// A dynamic [block-level](BlockLevel) layouting node. +/// A packed [block-level](BlockLevel) layouting node with precomputed hash. #[derive(Clone)] pub struct BlockNode { node: Rc, @@ -139,29 +145,6 @@ pub struct BlockNode { hash: u64, } -impl BlockNode { - /// Create a new dynamic node from any block-level node. - #[cfg(not(feature = "layout-cache"))] - pub fn new(node: T) -> Self - where - T: BlockLevel + 'static, - { - Self { node: Rc::new(node) } - } - - /// Create a new dynamic node from any block-level node. - #[cfg(feature = "layout-cache")] - pub fn new(node: T) -> Self - where - T: BlockLevel + Hash + 'static, - { - Self { - hash: hash_node(&node), - node: Rc::new(node), - } - } -} - impl BlockLevel for BlockNode { fn layout( &self, @@ -194,12 +177,21 @@ impl BlockLevel for BlockNode { frames }) } + + fn pack(self) -> BlockNode + where + Self: Sized + Hash + 'static, + { + self + } } -#[cfg(feature = "layout-cache")] impl Hash for BlockNode { - fn hash(&self, state: &mut H) { - state.write_u64(self.hash); + fn hash(&self, _state: &mut H) { + #[cfg(feature = "layout-cache")] + _state.write_u64(self.hash); + #[cfg(not(feature = "layout-cache"))] + unimplemented!() } } @@ -216,9 +208,21 @@ impl Debug for BlockNode { pub trait InlineLevel: Debug { /// Layout the node into a frame. fn layout(&self, ctx: &mut LayoutContext, space: Length, base: Size) -> Frame; + + /// Convert to a packed inline-level node. + fn pack(self) -> InlineNode + where + Self: Sized + Hash + 'static, + { + InlineNode { + #[cfg(feature = "layout-cache")] + hash: hash_node(&self), + node: Rc::new(self), + } + } } -/// A dynamic [inline-level](InlineLevel) layouting node. +/// A packed [inline-level](InlineLevel) layouting node with precomputed hash. #[derive(Clone)] pub struct InlineNode { node: Rc, @@ -226,39 +230,25 @@ pub struct InlineNode { hash: u64, } -impl InlineNode { - /// Create a new dynamic node from any inline-level node. - #[cfg(not(feature = "layout-cache"))] - pub fn new(node: T) -> Self - where - T: InlineLevel + 'static, - { - Self { node: Rc::new(node) } - } - - /// Create a new dynamic node from any inline-level node. - #[cfg(feature = "layout-cache")] - pub fn new(node: T) -> Self - where - T: InlineLevel + Hash + 'static, - { - Self { - hash: hash_node(&node), - node: Rc::new(node), - } - } -} - impl InlineLevel for InlineNode { fn layout(&self, ctx: &mut LayoutContext, space: Length, base: Size) -> Frame { self.node.layout(ctx, space, base) } + + fn pack(self) -> InlineNode + where + Self: Sized + Hash + 'static, + { + self + } } -#[cfg(feature = "layout-cache")] impl Hash for InlineNode { - fn hash(&self, state: &mut H) { - state.write_u64(self.hash); + fn hash(&self, _state: &mut H) { + #[cfg(feature = "layout-cache")] + _state.write_u64(self.hash); + #[cfg(not(feature = "layout-cache"))] + unimplemented!() } } @@ -271,7 +261,8 @@ impl Debug for InlineNode { /// Hash a node alongside its type id. #[cfg(feature = "layout-cache")] fn hash_node(node: &(impl Hash + 'static)) -> u64 { - let mut state = FxHasher64::default(); + use std::any::Any; + let mut state = fxhash::FxHasher64::default(); node.type_id().hash(&mut state); node.hash(&mut state); state.finish() diff --git a/src/layout/pad.rs b/src/layout/pad.rs index 20fcc1610..55c11e451 100644 --- a/src/layout/pad.rs +++ b/src/layout/pad.rs @@ -1,8 +1,7 @@ use super::*; /// A node that adds padding to its child. -#[derive(Debug)] -#[cfg_attr(feature = "layout-cache", derive(Hash))] +#[derive(Debug, Hash)] pub struct PadNode { /// The amount of padding. pub padding: Sides, @@ -74,9 +73,3 @@ impl BlockLevel for PadNode { frames } } - -impl From for BlockNode { - fn from(node: PadNode) -> Self { - Self::new(node) - } -} diff --git a/src/layout/par.rs b/src/layout/par.rs index 64265b63e..a645eb073 100644 --- a/src/layout/par.rs +++ b/src/layout/par.rs @@ -12,8 +12,7 @@ use crate::util::{EcoString, RangeExt, SliceExt}; type Range = std::ops::Range; /// A node that arranges its children into a paragraph. -#[derive(Debug)] -#[cfg_attr(feature = "layout-cache", derive(Hash))] +#[derive(Debug, Hash)] pub struct ParNode { /// The inline direction of this paragraph. pub dir: Dir, @@ -24,7 +23,7 @@ pub struct ParNode { } /// A child of a paragraph node. -#[cfg_attr(feature = "layout-cache", derive(Hash))] +#[derive(Hash)] pub enum ParChild { /// Spacing between other nodes. Spacing(Spacing), @@ -93,12 +92,6 @@ impl ParNode { } } -impl From for BlockNode { - fn from(node: ParNode) -> Self { - Self::new(node) - } -} - impl Debug for ParChild { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { diff --git a/src/layout/shape.rs b/src/layout/shape.rs index 2e66a0ddf..ed70dd95f 100644 --- a/src/layout/shape.rs +++ b/src/layout/shape.rs @@ -4,8 +4,7 @@ use super::*; use crate::util::RcExt; /// Places its child into a sizable and fillable shape. -#[derive(Debug)] -#[cfg_attr(feature = "layout-cache", derive(Hash))] +#[derive(Debug, Hash)] pub struct ShapeNode { /// Which shape to place the child into. pub shape: ShapeKind, @@ -105,9 +104,3 @@ impl InlineLevel for ShapeNode { frame } } - -impl From for InlineNode { - fn from(node: ShapeNode) -> Self { - Self::new(node) - } -} diff --git a/src/layout/stack.rs b/src/layout/stack.rs index dbd9ddb08..0fb3e3eba 100644 --- a/src/layout/stack.rs +++ b/src/layout/stack.rs @@ -3,8 +3,7 @@ use std::fmt::{self, Debug, Formatter}; use super::*; /// A node that stacks its children. -#[derive(Debug)] -#[cfg_attr(feature = "layout-cache", derive(Hash))] +#[derive(Debug, Hash)] pub struct StackNode { /// The stacking direction. pub dir: Dir, @@ -13,7 +12,7 @@ pub struct StackNode { } /// A child of a stack node. -#[cfg_attr(feature = "layout-cache", derive(Hash))] +#[derive(Hash)] pub enum StackChild { /// Spacing between other nodes. Spacing(Spacing), @@ -31,12 +30,6 @@ impl BlockLevel for StackNode { } } -impl From for BlockNode { - fn from(node: StackNode) -> Self { - Self::new(node) - } -} - impl Debug for StackChild { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { diff --git a/src/library/elements.rs b/src/library/elements.rs index cd8a6f88a..01efb4057 100644 --- a/src/library/elements.rs +++ b/src/library/elements.rs @@ -99,6 +99,6 @@ fn shape_impl( fill: Some(Paint::Color( fill.unwrap_or(Color::Rgba(RgbaColor::new(175, 175, 175, 255))), )), - child: body.as_ref().map(|template| template.to_stack(style).into()), + child: body.as_ref().map(|template| template.to_stack(style).pack()), })) } diff --git a/src/library/layout.rs b/src/library/layout.rs index 4ef0926fd..f7fb2882c 100644 --- a/src/library/layout.rs +++ b/src/library/layout.rs @@ -154,7 +154,7 @@ pub fn boxed(_: &mut EvalContext, args: &mut Args) -> TypResult { width, height, fill: fill.map(Paint::Color), - child: Some(body.to_stack(style).into()), + child: Some(body.to_stack(style).pack()), } }))) } @@ -186,7 +186,7 @@ pub fn pad(_: &mut EvalContext, args: &mut Args) -> TypResult { Ok(Value::Template(Template::from_block(move |style| { PadNode { padding, - child: body.to_stack(&style).into(), + child: body.to_stack(&style).pack(), } }))) } @@ -227,7 +227,7 @@ pub fn stack(_: &mut EvalContext, args: &mut Args) -> TypResult { children.push(StackChild::Spacing(v)); } - let node = template.to_stack(style).into(); + let node = template.to_stack(style).pack(); children.push(StackChild::Node(node, style.aligns.block)); delayed = spacing; } @@ -283,7 +283,7 @@ pub fn grid(_: &mut EvalContext, args: &mut Args) -> TypResult { gutter: gutter.clone(), children: children .iter() - .map(|child| child.to_stack(&style).into()) + .map(|child| child.to_stack(&style).pack()) .collect(), } }))) diff --git a/src/library/mod.rs b/src/library/mod.rs index 6f8881c3c..ac2085eb9 100644 --- a/src/library/mod.rs +++ b/src/library/mod.rs @@ -20,7 +20,7 @@ use crate::diag::{At, TypResult}; use crate::eval::{Args, Array, EvalContext, Scope, Str, Template, Value}; use crate::font::{FontFamily, FontStretch, FontStyle, FontWeight, VerticalFontMetric}; use crate::geom::*; -use crate::layout::Spacing; +use crate::layout::{BlockLevel, Spacing}; use crate::style::Style; use crate::syntax::{Span, Spanned};