Simplify node construction

This commit is contained in:
Laurenz 2021-10-26 17:11:08 +02:00
parent fb0cd3df6e
commit 5c534fb428
12 changed files with 79 additions and 129 deletions

View File

@ -1,5 +1,6 @@
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::hash::Hash;
use std::mem; use std::mem;
use std::ops::{Add, AddAssign}; use std::ops::{Add, AddAssign};
use std::rc::Rc; use std::rc::Rc;
@ -8,8 +9,8 @@ use super::Str;
use crate::diag::StrResult; use crate::diag::StrResult;
use crate::geom::{Align, Dir, GenAxis, Length, Linear, Sides, Size}; use crate::geom::{Align, Dir, GenAxis, Length, Linear, Sides, Size};
use crate::layout::{ use crate::layout::{
BlockNode, Decoration, InlineNode, PadNode, PageNode, ParChild, ParNode, Spacing, BlockLevel, BlockNode, Decoration, InlineLevel, InlineNode, PadNode, PageNode,
StackChild, StackNode, ParChild, ParNode, Spacing, StackChild, StackNode,
}; };
use crate::style::Style; use crate::style::Style;
use crate::util::EcoString; use crate::util::EcoString;
@ -57,9 +58,9 @@ impl Template {
pub fn from_inline<F, T>(f: F) -> Self pub fn from_inline<F, T>(f: F) -> Self
where where
F: Fn(&Style) -> T + 'static, F: Fn(&Style) -> T + 'static,
T: Into<InlineNode>, 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])) Self(Rc::new(vec![node]))
} }
@ -67,9 +68,9 @@ impl Template {
pub fn from_block<F, T>(f: F) -> Self pub fn from_block<F, T>(f: F) -> Self
where where
F: Fn(&Style) -> T + 'static, F: Fn(&Style) -> T + 'static,
T: Into<BlockNode>, 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])) Self(Rc::new(vec![node]))
} }
@ -396,7 +397,7 @@ impl PageBuilder {
let Self { size, padding, hard } = self; let Self { size, padding, hard } = self;
(!child.children.is_empty() || (keep && hard)).then(|| PageNode { (!child.children.is_empty() || (keep && hard)).then(|| PageNode {
size, 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<StackChild> { fn build(self) -> Option<StackChild> {
let Self { align, dir, leading, children, .. } = self; let Self { align, dir, leading, children, .. } = self;
(!children.is_empty()) (!children.is_empty())
.then(|| StackChild::Node(ParNode { dir, leading, children }.into(), align)) .then(|| StackChild::Node(ParNode { dir, leading, children }.pack(), align))
} }
} }

View File

@ -3,7 +3,7 @@ use std::rc::Rc;
use super::{Eval, EvalContext, Str, Template, Value}; use super::{Eval, EvalContext, Str, Template, Value};
use crate::diag::TypResult; use crate::diag::TypResult;
use crate::geom::Align; 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::syntax::*;
use crate::util::BoolExt; use crate::util::BoolExt;
@ -118,9 +118,9 @@ fn walk_item(ctx: &mut EvalContext, label: Str, body: Template) {
StackNode { StackNode {
dir: style.dir, dir: style.dir,
children: vec![ 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::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),
], ],
} }
}); });

View File

@ -1,8 +1,7 @@
use super::*; use super::*;
/// A node that arranges its children in a grid. /// A node that arranges its children in a grid.
#[derive(Debug)] #[derive(Debug, Hash)]
#[cfg_attr(feature = "layout-cache", derive(Hash))]
pub struct GridNode { pub struct GridNode {
/// Defines sizing for content rows and columns. /// Defines sizing for content rows and columns.
pub tracks: Spec<Vec<TrackSizing>>, pub tracks: Spec<Vec<TrackSizing>>,
@ -40,12 +39,6 @@ impl BlockLevel for GridNode {
} }
} }
impl From<GridNode> for BlockNode {
fn from(node: GridNode) -> Self {
Self::new(node)
}
}
/// Performs grid layout. /// Performs grid layout.
struct GridLayouter<'a> { struct GridLayouter<'a> {
/// The original expand state of the target region. /// The original expand state of the target region.

View File

@ -2,8 +2,7 @@ use super::*;
use crate::image::ImageId; use crate::image::ImageId;
/// An image node. /// An image node.
#[derive(Debug)] #[derive(Debug, Hash)]
#[cfg_attr(feature = "layout-cache", derive(Hash))]
pub struct ImageNode { pub struct ImageNode {
/// The id of the image file. /// The id of the image file.
pub id: ImageId, pub id: ImageId,
@ -43,9 +42,3 @@ impl InlineLevel for ImageNode {
frame frame
} }
} }
impl From<ImageNode> for InlineNode {
fn from(node: ImageNode) -> Self {
Self::new(node)
}
}

View File

@ -29,6 +29,7 @@ pub use stack::*;
pub use text::*; pub use text::*;
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
use std::rc::Rc; use std::rc::Rc;
use crate::font::FontStore; use crate::font::FontStore;
@ -37,13 +38,6 @@ use crate::image::ImageStore;
use crate::util::OptionExt; use crate::util::OptionExt;
use crate::Context; 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. /// Layout a page-level node into a collection of frames.
pub fn layout<T>(ctx: &mut Context, node: &T) -> Vec<Rc<Frame>> pub fn layout<T>(ctx: &mut Context, node: &T) -> Vec<Rc<Frame>>
where where
@ -129,9 +123,21 @@ pub trait BlockLevel: Debug {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
) -> Vec<Constrained<Rc<Frame>>>; ) -> Vec<Constrained<Rc<Frame>>>;
/// 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)] #[derive(Clone)]
pub struct BlockNode { pub struct BlockNode {
node: Rc<dyn BlockLevel>, node: Rc<dyn BlockLevel>,
@ -139,29 +145,6 @@ pub struct BlockNode {
hash: u64, hash: u64,
} }
impl BlockNode {
/// Create a new dynamic node from any block-level node.
#[cfg(not(feature = "layout-cache"))]
pub fn new<T>(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<T>(node: T) -> Self
where
T: BlockLevel + Hash + 'static,
{
Self {
hash: hash_node(&node),
node: Rc::new(node),
}
}
}
impl BlockLevel for BlockNode { impl BlockLevel for BlockNode {
fn layout( fn layout(
&self, &self,
@ -194,12 +177,21 @@ impl BlockLevel for BlockNode {
frames frames
}) })
} }
fn pack(self) -> BlockNode
where
Self: Sized + Hash + 'static,
{
self
}
} }
#[cfg(feature = "layout-cache")]
impl Hash for BlockNode { impl Hash for BlockNode {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, _state: &mut H) {
state.write_u64(self.hash); #[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 { pub trait InlineLevel: Debug {
/// Layout the node into a frame. /// Layout the node into a frame.
fn layout(&self, ctx: &mut LayoutContext, space: Length, base: Size) -> 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)] #[derive(Clone)]
pub struct InlineNode { pub struct InlineNode {
node: Rc<dyn InlineLevel>, node: Rc<dyn InlineLevel>,
@ -226,39 +230,25 @@ pub struct InlineNode {
hash: u64, hash: u64,
} }
impl InlineNode {
/// Create a new dynamic node from any inline-level node.
#[cfg(not(feature = "layout-cache"))]
pub fn new<T>(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<T>(node: T) -> Self
where
T: InlineLevel + Hash + 'static,
{
Self {
hash: hash_node(&node),
node: Rc::new(node),
}
}
}
impl InlineLevel for InlineNode { impl InlineLevel for InlineNode {
fn layout(&self, ctx: &mut LayoutContext, space: Length, base: Size) -> Frame { fn layout(&self, ctx: &mut LayoutContext, space: Length, base: Size) -> Frame {
self.node.layout(ctx, space, base) self.node.layout(ctx, space, base)
} }
fn pack(self) -> InlineNode
where
Self: Sized + Hash + 'static,
{
self
}
} }
#[cfg(feature = "layout-cache")]
impl Hash for InlineNode { impl Hash for InlineNode {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, _state: &mut H) {
state.write_u64(self.hash); #[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. /// Hash a node alongside its type id.
#[cfg(feature = "layout-cache")] #[cfg(feature = "layout-cache")]
fn hash_node(node: &(impl Hash + 'static)) -> u64 { 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.type_id().hash(&mut state);
node.hash(&mut state); node.hash(&mut state);
state.finish() state.finish()

View File

@ -1,8 +1,7 @@
use super::*; use super::*;
/// A node that adds padding to its child. /// A node that adds padding to its child.
#[derive(Debug)] #[derive(Debug, Hash)]
#[cfg_attr(feature = "layout-cache", derive(Hash))]
pub struct PadNode { pub struct PadNode {
/// The amount of padding. /// The amount of padding.
pub padding: Sides<Linear>, pub padding: Sides<Linear>,
@ -74,9 +73,3 @@ impl BlockLevel for PadNode {
frames frames
} }
} }
impl From<PadNode> for BlockNode {
fn from(node: PadNode) -> Self {
Self::new(node)
}
}

View File

@ -12,8 +12,7 @@ use crate::util::{EcoString, RangeExt, SliceExt};
type Range = std::ops::Range<usize>; type Range = std::ops::Range<usize>;
/// A node that arranges its children into a paragraph. /// A node that arranges its children into a paragraph.
#[derive(Debug)] #[derive(Debug, Hash)]
#[cfg_attr(feature = "layout-cache", derive(Hash))]
pub struct ParNode { pub struct ParNode {
/// The inline direction of this paragraph. /// The inline direction of this paragraph.
pub dir: Dir, pub dir: Dir,
@ -24,7 +23,7 @@ pub struct ParNode {
} }
/// A child of a paragraph node. /// A child of a paragraph node.
#[cfg_attr(feature = "layout-cache", derive(Hash))] #[derive(Hash)]
pub enum ParChild { pub enum ParChild {
/// Spacing between other nodes. /// Spacing between other nodes.
Spacing(Spacing), Spacing(Spacing),
@ -93,12 +92,6 @@ impl ParNode {
} }
} }
impl From<ParNode> for BlockNode {
fn from(node: ParNode) -> Self {
Self::new(node)
}
}
impl Debug for ParChild { impl Debug for ParChild {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {

View File

@ -4,8 +4,7 @@ use super::*;
use crate::util::RcExt; use crate::util::RcExt;
/// Places its child into a sizable and fillable shape. /// Places its child into a sizable and fillable shape.
#[derive(Debug)] #[derive(Debug, Hash)]
#[cfg_attr(feature = "layout-cache", derive(Hash))]
pub struct ShapeNode { pub struct ShapeNode {
/// Which shape to place the child into. /// Which shape to place the child into.
pub shape: ShapeKind, pub shape: ShapeKind,
@ -105,9 +104,3 @@ impl InlineLevel for ShapeNode {
frame frame
} }
} }
impl From<ShapeNode> for InlineNode {
fn from(node: ShapeNode) -> Self {
Self::new(node)
}
}

View File

@ -3,8 +3,7 @@ use std::fmt::{self, Debug, Formatter};
use super::*; use super::*;
/// A node that stacks its children. /// A node that stacks its children.
#[derive(Debug)] #[derive(Debug, Hash)]
#[cfg_attr(feature = "layout-cache", derive(Hash))]
pub struct StackNode { pub struct StackNode {
/// The stacking direction. /// The stacking direction.
pub dir: Dir, pub dir: Dir,
@ -13,7 +12,7 @@ pub struct StackNode {
} }
/// A child of a stack node. /// A child of a stack node.
#[cfg_attr(feature = "layout-cache", derive(Hash))] #[derive(Hash)]
pub enum StackChild { pub enum StackChild {
/// Spacing between other nodes. /// Spacing between other nodes.
Spacing(Spacing), Spacing(Spacing),
@ -31,12 +30,6 @@ impl BlockLevel for StackNode {
} }
} }
impl From<StackNode> for BlockNode {
fn from(node: StackNode) -> Self {
Self::new(node)
}
}
impl Debug for StackChild { impl Debug for StackChild {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {

View File

@ -99,6 +99,6 @@ fn shape_impl(
fill: Some(Paint::Color( fill: Some(Paint::Color(
fill.unwrap_or(Color::Rgba(RgbaColor::new(175, 175, 175, 255))), 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()),
})) }))
} }

View File

@ -154,7 +154,7 @@ pub fn boxed(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
width, width,
height, height,
fill: fill.map(Paint::Color), 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<Value> {
Ok(Value::Template(Template::from_block(move |style| { Ok(Value::Template(Template::from_block(move |style| {
PadNode { PadNode {
padding, 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<Value> {
children.push(StackChild::Spacing(v)); 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)); children.push(StackChild::Node(node, style.aligns.block));
delayed = spacing; delayed = spacing;
} }
@ -283,7 +283,7 @@ pub fn grid(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
gutter: gutter.clone(), gutter: gutter.clone(),
children: children children: children
.iter() .iter()
.map(|child| child.to_stack(&style).into()) .map(|child| child.to_stack(&style).pack())
.collect(), .collect(),
} }
}))) })))

View File

@ -20,7 +20,7 @@ use crate::diag::{At, TypResult};
use crate::eval::{Args, Array, EvalContext, Scope, Str, Template, Value}; use crate::eval::{Args, Array, EvalContext, Scope, Str, Template, Value};
use crate::font::{FontFamily, FontStretch, FontStyle, FontWeight, VerticalFontMetric}; use crate::font::{FontFamily, FontStretch, FontStyle, FontWeight, VerticalFontMetric};
use crate::geom::*; use crate::geom::*;
use crate::layout::Spacing; use crate::layout::{BlockLevel, Spacing};
use crate::style::Style; use crate::style::Style;
use crate::syntax::{Span, Spanned}; use crate::syntax::{Span, Spanned};