From e27f6c10146240a6c8b92930b27948083f08c9b5 Mon Sep 17 00:00:00 2001 From: Martin Haug Date: Wed, 26 May 2021 22:52:02 +0200 Subject: [PATCH] Add hash impls for all nodes This prepares the incremental PR. Co-Authored-By: Laurenz --- Cargo.toml | 2 ++ src/color.rs | 4 +-- src/exec/state.rs | 8 +++--- src/font.rs | 58 +++++++++++++++++++++------------------- src/geom/align.rs | 2 +- src/geom/dir.rs | 2 +- src/geom/gen.rs | 9 +++++-- src/geom/length.rs | 39 +++++++++++++-------------- src/geom/linear.rs | 20 ++++++++++---- src/geom/path.rs | 2 +- src/geom/point.rs | 4 ++- src/geom/relative.rs | 24 ++++++++++------- src/geom/sides.rs | 2 +- src/geom/size.rs | 15 +++++------ src/geom/spec.rs | 10 ++++--- src/layout/background.rs | 6 ++--- src/layout/fixed.rs | 2 +- src/layout/frame.rs | 2 +- src/layout/mod.rs | 54 ++++++++++++++++++++++++++----------- src/layout/pad.rs | 2 +- src/layout/par.rs | 24 ++++++++--------- src/layout/shaping.rs | 8 +++--- src/layout/stack.rs | 24 +++++++++-------- src/library/font.rs | 2 +- src/library/image.rs | 4 +-- src/library/shapes.rs | 10 ++++--- src/pdf/mod.rs | 2 +- src/pretty.rs | 2 +- 28 files changed, 198 insertions(+), 145 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6c77b29ac..ed46ccd92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,8 @@ debug = 0 opt-level = 2 [dependencies] +decorum = { version = "0.3.1", default-features = false, features = ["serialize-serde"] } +fxhash = "0.2.1" image = { version = "0.23", default-features = false, features = ["jpeg", "png"] } miniz_oxide = "0.3" pdf-writer = { path = "../pdf-writer" } diff --git a/src/color.rs b/src/color.rs index 5a93e0e91..c3ab5aa90 100644 --- a/src/color.rs +++ b/src/color.rs @@ -6,7 +6,7 @@ use std::str::FromStr; use serde::{Deserialize, Serialize}; /// A color in a dynamic format. -#[derive(Copy, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] pub enum Color { /// An 8-bit RGBA color: `#423abaff`. Rgba(RgbaColor), @@ -29,7 +29,7 @@ impl Debug for Color { } /// An 8-bit RGBA color: `#423abaff`. -#[derive(Copy, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] pub struct RgbaColor { /// Red channel. pub r: u8, diff --git a/src/exec/state.rs b/src/exec/state.rs index 99c162c64..9a8971cc0 100644 --- a/src/exec/state.rs +++ b/src/exec/state.rs @@ -184,7 +184,7 @@ impl Default for FontState { size: Length::pt(11.0), top_edge: VerticalFontMetric::CapHeight, bottom_edge: VerticalFontMetric::Baseline, - scale: Linear::ONE, + scale: Linear::one(), color: Fill::Color(Color::Rgba(RgbaColor::BLACK)), strong: false, emph: false, @@ -193,7 +193,7 @@ impl Default for FontState { } /// Properties used for font selection and layout. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Hash)] pub struct FontProps { /// The list of font families to use for shaping. pub families: Rc, @@ -210,7 +210,7 @@ pub struct FontProps { } /// Font family definitions. -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct FamilyList { /// The user-defined list of font families. pub list: Vec, @@ -255,7 +255,7 @@ impl Default for FamilyList { } /// A generic or named font family. -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum FontFamily { Serif, SansSerif, diff --git a/src/font.rs b/src/font.rs index 01434d0af..dd81fa88e 100644 --- a/src/font.rs +++ b/src/font.rs @@ -92,7 +92,7 @@ impl Face { } /// Identifies a vertical metric of a font. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum VerticalFontMetric { /// The distance from the baseline to the typographic ascender. /// @@ -169,7 +169,7 @@ pub struct FaceInfo { } /// Properties that distinguish a face from other faces in the same family. -#[derive(Default, Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Default, Debug, Copy, Clone, PartialEq, Hash, Serialize, Deserialize)] pub struct FontVariant { /// The style of the face (normal / italic / oblique). pub style: FontStyle, @@ -187,7 +187,7 @@ impl FontVariant { } /// The style of a font face. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[derive(Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub enum FontStyle { @@ -233,7 +233,8 @@ impl Display for FontStyle { } /// The weight of a font face. -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Serialize, Deserialize)] #[serde(transparent)] pub struct FontWeight(u16); @@ -353,42 +354,43 @@ impl Debug for FontWeight { } /// The width of a font face. -#[derive(Copy, Clone, PartialEq, PartialOrd, Serialize, Deserialize)] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Serialize, Deserialize)] #[serde(transparent)] -pub struct FontStretch(f32); +pub struct FontStretch(u16); impl FontStretch { /// Ultra-condensed stretch (50%). - pub const ULTRA_CONDENSED: Self = Self(0.5); + pub const ULTRA_CONDENSED: Self = Self(500); /// Extra-condensed stretch weight (62.5%). - pub const EXTRA_CONDENSED: Self = Self(0.625); + pub const EXTRA_CONDENSED: Self = Self(625); /// Condensed stretch (75%). - pub const CONDENSED: Self = Self(0.75); + pub const CONDENSED: Self = Self(750); /// Semi-condensed stretch (87.5%). - pub const SEMI_CONDENSED: Self = Self(0.875); + pub const SEMI_CONDENSED: Self = Self(875); /// Normal stretch (100%). - pub const NORMAL: Self = Self(1.0); + pub const NORMAL: Self = Self(1000); /// Semi-expanded stretch (112.5%). - pub const SEMI_EXPANDED: Self = Self(1.125); + pub const SEMI_EXPANDED: Self = Self(1125); /// Expanded stretch (125%). - pub const EXPANDED: Self = Self(1.25); + pub const EXPANDED: Self = Self(1250); /// Extra-expanded stretch (150%). - pub const EXTRA_EXPANDED: Self = Self(1.5); + pub const EXTRA_EXPANDED: Self = Self(1500); /// Ultra-expanded stretch (200%). - pub const ULTRA_EXPANDED: Self = Self(2.0); + pub const ULTRA_EXPANDED: Self = Self(2000); /// Create a font stretch from a ratio between 0.5 and 2.0, clamping it if /// necessary. pub fn from_ratio(ratio: f32) -> Self { - Self(ratio.max(0.5).min(2.0)) + Self((ratio.max(0.5).min(2.0) * 1000.0) as u16) } /// Create a font stretch from an OpenType-style number between 1 and 9, @@ -425,29 +427,29 @@ impl FontStretch { /// The ratio between 0.5 and 2.0 corresponding to this stretch. pub fn to_ratio(self) -> f32 { - self.0 + self.0 as f32 / 1000.0 } /// The lowercase string representation of this stretch is one of the named /// ones. pub fn to_str(self) -> Option<&'static str> { Some(match self { - s if s == Self::ULTRA_CONDENSED => "ultra-condensed", - s if s == Self::EXTRA_CONDENSED => "extra-condensed", - s if s == Self::CONDENSED => "condensed", - s if s == Self::SEMI_CONDENSED => "semi-condensed", - s if s == Self::NORMAL => "normal", - s if s == Self::SEMI_EXPANDED => "semi-expanded", - s if s == Self::EXPANDED => "expanded", - s if s == Self::EXTRA_EXPANDED => "extra-expanded", - s if s == Self::ULTRA_EXPANDED => "ultra-expanded", + Self::ULTRA_CONDENSED => "ultra-condensed", + Self::EXTRA_CONDENSED => "extra-condensed", + Self::CONDENSED => "condensed", + Self::SEMI_CONDENSED => "semi-condensed", + Self::NORMAL => "normal", + Self::SEMI_EXPANDED => "semi-expanded", + Self::EXPANDED => "expanded", + Self::EXTRA_EXPANDED => "extra-expanded", + Self::ULTRA_EXPANDED => "ultra-expanded", _ => return None, }) } /// The absolute ratio distance between this and another font stretch. pub fn distance(self, other: Self) -> f32 { - (self.0 - other.0).abs() + (self.to_ratio() - other.to_ratio()).abs() } } @@ -461,7 +463,7 @@ impl Display for FontStretch { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self.to_str() { Some(name) => f.pad(name), - None => write!(f, "{}", self.0), + None => write!(f, "{}", self.to_ratio()), } } } diff --git a/src/geom/align.rs b/src/geom/align.rs index 515efdf22..f6e5bb2af 100644 --- a/src/geom/align.rs +++ b/src/geom/align.rs @@ -1,7 +1,7 @@ use super::*; /// Where to align something along a directed axis. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum Align { /// Align at the start of the axis. Start, diff --git a/src/geom/dir.rs b/src/geom/dir.rs index cfcb4c09a..7b224b550 100644 --- a/src/geom/dir.rs +++ b/src/geom/dir.rs @@ -1,7 +1,7 @@ use super::*; /// The four directions into which content can be laid out. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Dir { /// Left to right. LTR, diff --git a/src/geom/gen.rs b/src/geom/gen.rs index 91f7499c2..c530ff2b1 100644 --- a/src/geom/gen.rs +++ b/src/geom/gen.rs @@ -1,7 +1,7 @@ use super::*; /// A container with a main and cross component. -#[derive(Default, Copy, Clone, Eq, PartialEq)] +#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)] pub struct Gen { /// The cross component. pub cross: T, @@ -26,7 +26,12 @@ impl Gen { impl Gen { /// The zero value. - pub const ZERO: Self = Self { main: Length::ZERO, cross: Length::ZERO }; + pub fn zero() -> Self { + Self { + main: Length::zero(), + cross: Length::zero(), + } + } } impl Get for Gen { diff --git a/src/geom/length.rs b/src/geom/length.rs index 8bc50e979..2439000cf 100644 --- a/src/geom/length.rs +++ b/src/geom/length.rs @@ -1,18 +1,22 @@ -use super::*; - +use decorum::NotNan; use serde::{Deserialize, Serialize}; +use super::*; + /// An absolute length. -#[derive(Default, Copy, Clone, PartialEq, PartialOrd, Serialize, Deserialize)] +#[derive(Default, Copy, Clone, PartialEq, PartialOrd, Hash)] +#[derive(Serialize, Deserialize)] #[serde(transparent)] pub struct Length { /// The length in raw units. - raw: f64, + raw: NotNan, } impl Length { /// The zero length. - pub const ZERO: Self = Self { raw: 0.0 }; + pub fn zero() -> Self { + Self { raw: 0.0.into() } + } /// Create a length from a number of points. pub fn pt(pt: f64) -> Self { @@ -35,8 +39,8 @@ impl Length { } /// Create a length from a number of raw units. - pub const fn raw(raw: f64) -> Self { - Self { raw } + pub fn raw(raw: f64) -> Self { + Self { raw: raw.into() } } /// Convert this to a number of points. @@ -60,18 +64,18 @@ impl Length { } /// Get the value of this length in raw units. - pub const fn to_raw(self) -> f64 { - self.raw + pub fn to_raw(self) -> f64 { + self.raw.into() } /// Create a length from a value in a unit. pub fn with_unit(val: f64, unit: LengthUnit) -> Self { - Self { raw: val * unit.raw_scale() } + Self { raw: (val * unit.raw_scale()).into() } } /// Get the value of this length in unit. pub fn to_unit(self, unit: LengthUnit) -> f64 { - self.raw / unit.raw_scale() + self.to_raw() / unit.raw_scale() } /// The minimum of this and another length. @@ -106,17 +110,12 @@ impl Length { /// Whether the length is finite. pub fn is_finite(self) -> bool { - self.raw.is_finite() + self.raw.into_inner().is_finite() } /// Whether the length is infinite. pub fn is_infinite(self) -> bool { - self.raw.is_infinite() - } - - /// Whether the length is `NaN`. - pub fn is_nan(self) -> bool { - self.raw.is_nan() + self.raw.into_inner().is_infinite() } } @@ -189,7 +188,7 @@ impl Div for Length { type Output = f64; fn div(self, other: Self) -> f64 { - self.raw / other.raw + self.to_raw() / other.to_raw() } } @@ -200,7 +199,7 @@ assign_impl!(Length /= f64); impl Sum for Length { fn sum>(iter: I) -> Self { - iter.fold(Length::ZERO, Add::add) + iter.fold(Length::zero(), Add::add) } } diff --git a/src/geom/linear.rs b/src/geom/linear.rs index 54ff71e66..204738219 100644 --- a/src/geom/linear.rs +++ b/src/geom/linear.rs @@ -1,7 +1,7 @@ use super::*; /// A combined relative and absolute length. -#[derive(Default, Copy, Clone, PartialEq)] +#[derive(Default, Copy, Clone, PartialEq, Hash)] pub struct Linear { /// The relative part. pub rel: Relative, @@ -11,10 +11,20 @@ pub struct Linear { impl Linear { /// The zero linear. - pub const ZERO: Self = Self { rel: Relative::ZERO, abs: Length::ZERO }; + pub fn zero() -> Self { + Self { + rel: Relative::zero(), + abs: Length::zero(), + } + } /// The linear with a relative part of `100%` and no absolute part. - pub const ONE: Self = Self { rel: Relative::ONE, abs: Length::ZERO }; + pub fn one() -> Self { + Self { + rel: Relative::one(), + abs: Length::zero(), + } + } /// Create a new linear. pub fn new(rel: Relative, abs: Length) -> Self { @@ -46,13 +56,13 @@ impl Debug for Linear { impl From for Linear { fn from(abs: Length) -> Self { - Self { rel: Relative::ZERO, abs } + Self { rel: Relative::zero(), abs } } } impl From for Linear { fn from(rel: Relative) -> Self { - Self { rel, abs: Length::ZERO } + Self { rel, abs: Length::zero() } } } diff --git a/src/geom/path.rs b/src/geom/path.rs index 8878b6f1a..f6be27549 100644 --- a/src/geom/path.rs +++ b/src/geom/path.rs @@ -30,7 +30,7 @@ impl Path { let m = 0.551784; let mx = m * rx; let my = m * ry; - let z = Length::ZERO; + let z = Length::zero(); let point = Point::new; let mut path = Self::new(); path.move_to(point(-rx, z)); diff --git a/src/geom/point.rs b/src/geom/point.rs index 479bb1374..babbdfef4 100644 --- a/src/geom/point.rs +++ b/src/geom/point.rs @@ -13,7 +13,9 @@ pub struct Point { impl Point { /// The origin point. - pub const ZERO: Self = Self { x: Length::ZERO, y: Length::ZERO }; + pub fn zero() -> Self { + Self { x: Length::zero(), y: Length::zero() } + } /// Create a new point from x and y coordinate. pub fn new(x: Length, y: Length) -> Self { diff --git a/src/geom/relative.rs b/src/geom/relative.rs index bbae5aba6..86759bbe6 100644 --- a/src/geom/relative.rs +++ b/src/geom/relative.rs @@ -1,34 +1,40 @@ +use decorum::NotNan; + use super::*; /// A relative length. /// /// _Note_: `50%` is represented as `0.5` here, but stored as `50.0` in the /// corresponding [literal](crate::syntax::Expr::Percent). -#[derive(Default, Copy, Clone, PartialEq, PartialOrd)] -pub struct Relative(f64); +#[derive(Default, Copy, Clone, PartialEq, PartialOrd, Hash)] +pub struct Relative(NotNan); impl Relative { /// A ratio of `0%` represented as `0.0`. - pub const ZERO: Self = Self(0.0); + pub fn zero() -> Self { + Self(0.0.into()) + } /// A ratio of `100%` represented as `1.0`. - pub const ONE: Self = Self(1.0); + pub fn one() -> Self { + Self(1.0.into()) + } /// Create a new relative value. pub fn new(ratio: f64) -> Self { - Self(ratio) + Self(ratio.into()) } /// Get the underlying ratio. pub fn get(self) -> f64 { - self.0 + self.0.into() } /// Resolve this relative to the given `length`. pub fn resolve(self, length: Length) -> Length { // We don't want NaNs. if length.is_infinite() { - Length::ZERO + Length::zero() } else { self.get() * length } @@ -42,7 +48,7 @@ impl Relative { impl Display for Relative { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}%", 100.0 * self.0) + write!(f, "{}%", 100.0 * self.get()) } } @@ -98,7 +104,7 @@ impl Div for Relative { type Output = f64; fn div(self, other: Self) -> f64 { - self.0 / other.0 + self.get() / other.get() } } diff --git a/src/geom/sides.rs b/src/geom/sides.rs index af728ed46..f9fdc01f2 100644 --- a/src/geom/sides.rs +++ b/src/geom/sides.rs @@ -1,7 +1,7 @@ use super::*; /// A container with left, top, right and bottom components. -#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)] pub struct Sides { /// The value for the left side. pub left: T, diff --git a/src/geom/size.rs b/src/geom/size.rs index d81525e6d..e20c24afb 100644 --- a/src/geom/size.rs +++ b/src/geom/size.rs @@ -13,10 +13,12 @@ pub struct Size { impl Size { /// The zero size. - pub const ZERO: Self = Self { - width: Length::ZERO, - height: Length::ZERO, - }; + pub fn zero() -> Self { + Self { + width: Length::zero(), + height: Length::zero(), + } + } /// Create a new size from width and height. pub fn new(width: Length, height: Length) -> Self { @@ -43,11 +45,6 @@ impl Size { self.width.is_infinite() || self.height.is_infinite() } - /// Whether any of the two components is `NaN`. - pub fn is_nan(self) -> bool { - self.width.is_nan() || self.height.is_nan() - } - /// Convert to a point. pub fn to_point(self) -> Point { Point::new(self.width, self.height) diff --git a/src/geom/spec.rs b/src/geom/spec.rs index e5479ba45..713f0a16b 100644 --- a/src/geom/spec.rs +++ b/src/geom/spec.rs @@ -29,10 +29,12 @@ impl Spec { impl Spec { /// The zero value. - pub const ZERO: Self = Self { - horizontal: Length::ZERO, - vertical: Length::ZERO, - }; + pub fn zero() -> Self { + Self { + horizontal: Length::zero(), + vertical: Length::zero(), + } + } /// Convert to a point. pub fn to_point(self) -> Point { diff --git a/src/layout/background.rs b/src/layout/background.rs index a5afbc4a2..3a76a2644 100644 --- a/src/layout/background.rs +++ b/src/layout/background.rs @@ -1,7 +1,7 @@ use super::*; /// A node that places a rectangular filled background behind its child. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Hash)] pub struct BackgroundNode { /// The kind of shape to use as a background. pub shape: BackgroundShape, @@ -12,7 +12,7 @@ pub struct BackgroundNode { } /// The kind of shape to use as a background. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum BackgroundShape { Rect, Ellipse, @@ -24,7 +24,7 @@ impl Layout for BackgroundNode { for frame in &mut frames { let (point, shape) = match self.shape { - BackgroundShape::Rect => (Point::ZERO, Shape::Rect(frame.size)), + BackgroundShape::Rect => (Point::zero(), Shape::Rect(frame.size)), BackgroundShape::Ellipse => { (frame.size.to_point() / 2.0, Shape::Ellipse(frame.size)) } diff --git a/src/layout/fixed.rs b/src/layout/fixed.rs index a0e5e9734..7c28e8e5c 100644 --- a/src/layout/fixed.rs +++ b/src/layout/fixed.rs @@ -1,7 +1,7 @@ use super::*; /// A node that can fix its child's width and height. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Hash)] pub struct FixedNode { /// The fixed width, if any. pub width: Option, diff --git a/src/layout/frame.rs b/src/layout/frame.rs index cf8ddb09f..61a84d6d6 100644 --- a/src/layout/frame.rs +++ b/src/layout/frame.rs @@ -96,7 +96,7 @@ pub enum Shape { } /// How text and shapes are filled. -#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Copy, Clone, PartialEq, Hash, Serialize, Deserialize)] pub enum Fill { /// A solid color. Color(Color), diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 7997f584a..207d5bed8 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -18,6 +18,10 @@ pub use stack::*; use std::any::Any; use std::fmt::{self, Debug, Formatter}; +use std::hash::{Hash, Hasher}; + +use decorum::NotNan; +use fxhash::FxHasher64; use crate::env::Env; use crate::geom::*; @@ -64,39 +68,62 @@ impl PageRun { } /// A wrapper around a dynamic layouting node. -pub struct AnyNode(Box); +pub struct AnyNode { + node: Box, + hash: u64, +} impl AnyNode { /// Create a new instance from any node that satisifies the required bounds. - pub fn new(any: T) -> Self + pub fn new(node: T) -> Self where - T: Layout + Debug + Clone + PartialEq + 'static, + T: Layout + Debug + Clone + PartialEq + Hash + 'static, { - Self(Box::new(any)) + let hash = { + let mut state = FxHasher64::default(); + node.hash(&mut state); + state.finish() + }; + + Self { node: Box::new(node), hash } + } + + /// The cached hash for the boxed node. + pub fn hash(&self) -> u64 { + self.hash } } impl Layout for AnyNode { fn layout(&self, ctx: &mut LayoutContext, regions: &Regions) -> Vec { - self.0.layout(ctx, regions) + self.node.layout(ctx, regions) } } impl Clone for AnyNode { fn clone(&self) -> Self { - Self(self.0.dyn_clone()) + Self { + node: self.node.dyn_clone(), + hash: self.hash, + } } } impl PartialEq for AnyNode { fn eq(&self, other: &Self) -> bool { - self.0.dyn_eq(other.0.as_ref()) + self.node.dyn_eq(other.node.as_ref()) + } +} + +impl Hash for AnyNode { + fn hash(&self, state: &mut H) { + state.write_u64(self.hash); } } impl Debug for AnyNode { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - self.0.fmt(f) + self.node.fmt(f) } } @@ -202,10 +229,7 @@ impl Regions { /// /// If this is true, calling `next()` will have no effect. pub fn in_full_last(&self) -> bool { - self.backlog.is_empty() - && self.last.map_or(true, |size| { - self.current.is_nan() || size.is_nan() || self.current == size - }) + self.backlog.is_empty() && self.last.map_or(true, |size| self.current == size) } /// Advance to the next region if there is any. @@ -217,9 +241,9 @@ impl Regions { } /// Shrink `current` to ensure that the aspect ratio can be satisfied. - pub fn apply_aspect_ratio(&mut self, aspect: f64) { - let width = self.current.width.min(aspect * self.current.height); - let height = width / aspect; + pub fn apply_aspect_ratio(&mut self, aspect: NotNan) { + let width = self.current.width.min(aspect.into_inner() * self.current.height); + let height = width / aspect.into_inner(); self.current = Size::new(width, height); } } diff --git a/src/layout/pad.rs b/src/layout/pad.rs index ad24d62cc..ccf0d5e13 100644 --- a/src/layout/pad.rs +++ b/src/layout/pad.rs @@ -1,7 +1,7 @@ use super::*; /// A node that adds padding to its child. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Hash)] pub struct PadNode { /// The amount of padding. pub padding: Sides, diff --git a/src/layout/par.rs b/src/layout/par.rs index 22400dd34..f21778dee 100644 --- a/src/layout/par.rs +++ b/src/layout/par.rs @@ -10,7 +10,7 @@ use crate::util::{RangeExt, SliceExt}; type Range = std::ops::Range; /// A node that arranges its children into a paragraph. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Hash)] pub struct ParNode { /// The inline direction of this paragraph. pub dir: Dir, @@ -21,7 +21,7 @@ pub struct ParNode { } /// A child of a paragraph node. -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Hash)] pub enum ParChild { /// Spacing between other nodes. Spacing(Length), @@ -255,7 +255,7 @@ impl ParItem<'_> { /// The size of the item. pub fn size(&self) -> Size { match self { - Self::Spacing(amount) => Size::new(*amount, Length::ZERO), + Self::Spacing(amount) => Size::new(*amount, Length::zero()), Self::Text(shaped, _) => shaped.size, Self::Frame(frame, _) => frame.size, } @@ -264,7 +264,7 @@ impl ParItem<'_> { /// The baseline of the item. pub fn baseline(&self) -> Length { match self { - Self::Spacing(_) => Length::ZERO, + Self::Spacing(_) => Length::zero(), Self::Text(shaped, _) => shaped.baseline, Self::Frame(frame, _) => frame.baseline, } @@ -287,7 +287,7 @@ impl<'a> LineStack<'a> { regions, finished: vec![], lines: vec![], - size: Size::ZERO, + size: Size::zero(), } } @@ -308,13 +308,13 @@ impl<'a> LineStack<'a> { } let mut output = Frame::new(self.size, self.size.height); - let mut offset = Length::ZERO; + let mut offset = Length::zero(); let mut first = true; for line in std::mem::take(&mut self.lines) { let frame = line.build(self.size.width); - let pos = Point::new(Length::ZERO, offset); + let pos = Point::new(Length::zero(), offset); if first { output.baseline = pos.y + frame.baseline; first = false; @@ -326,7 +326,7 @@ impl<'a> LineStack<'a> { self.finished.push(output); self.regions.next(); - self.size = Size::ZERO; + self.size = Size::zero(); } fn finish(mut self) -> Vec { @@ -421,9 +421,9 @@ impl<'a> LineLayout<'a> { } } - let mut width = Length::ZERO; - let mut top = Length::ZERO; - let mut bottom = Length::ZERO; + let mut width = Length::zero(); + let mut top = Length::zero(); + let mut bottom = Length::zero(); // Measure the size of the line. for item in first.iter().chain(items).chain(&last) { @@ -452,7 +452,7 @@ impl<'a> LineLayout<'a> { let free = size.width - self.size.width; let mut output = Frame::new(size, self.baseline); - let mut offset = Length::ZERO; + let mut offset = Length::zero(); let mut ruler = Align::Start; self.reordered(|item| { diff --git a/src/layout/shaping.rs b/src/layout/shaping.rs index da25b7a65..f8ab70379 100644 --- a/src/layout/shaping.rs +++ b/src/layout/shaping.rs @@ -62,7 +62,7 @@ impl<'a> ShapedText<'a> { /// Build the shaped text's frame. pub fn build(&self) -> Frame { let mut frame = Frame::new(self.size, self.baseline); - let mut offset = Length::ZERO; + let mut offset = Length::zero(); for (face_id, group) in self.glyphs.as_ref().group_by_key(|g| g.face_id) { let pos = Point::new(offset, self.baseline); @@ -331,9 +331,9 @@ fn measure( glyphs: &[ShapedGlyph], props: &FontProps, ) -> (Size, Length) { - let mut width = Length::ZERO; - let mut top = Length::ZERO; - let mut bottom = Length::ZERO; + let mut width = Length::zero(); + let mut top = Length::zero(); + let mut bottom = Length::zero(); let mut expand_vertical = |face: &Face| { top.set_max(face.vertical_metric(props.top_edge).to_length(props.size)); bottom.set_max(-face.vertical_metric(props.bottom_edge).to_length(props.size)); diff --git a/src/layout/stack.rs b/src/layout/stack.rs index 11f9c3d75..bb7673785 100644 --- a/src/layout/stack.rs +++ b/src/layout/stack.rs @@ -1,7 +1,9 @@ +use decorum::NotNan; + use super::*; /// A node that stacks its children. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Hash)] pub struct StackNode { /// The `main` and `cross` directions of this stack. /// @@ -11,13 +13,13 @@ pub struct StackNode { /// The fixed aspect ratio between width and height, if any. /// /// The resulting frames will satisfy `width = aspect * height`. - pub aspect: Option, + pub aspect: Option>, /// The nodes to be stacked. pub children: Vec, } /// A child of a stack node. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Hash)] pub enum StackChild { /// Spacing between other nodes. Spacing(Length), @@ -56,7 +58,7 @@ impl From for AnyNode { struct StackLayouter { dirs: Gen, - aspect: Option, + aspect: Option>, main: SpecAxis, regions: Regions, finished: Vec, @@ -67,7 +69,7 @@ struct StackLayouter { } impl StackLayouter { - fn new(dirs: Gen, aspect: Option, mut regions: Regions) -> Self { + fn new(dirs: Gen, aspect: Option>, mut regions: Regions) -> Self { if let Some(aspect) = aspect { regions.apply_aspect_ratio(aspect); } @@ -79,7 +81,7 @@ impl StackLayouter { finished: vec![], frames: vec![], full: regions.current, - size: Gen::ZERO, + size: Gen::zero(), ruler: Align::Start, regions, } @@ -122,11 +124,11 @@ impl StackLayouter { if let Some(aspect) = self.aspect { let width = size .width - .max(aspect * size.height) + .max(aspect.into_inner() * size.height) .min(self.full.width) - .min(aspect * self.full.height); + .min(aspect.into_inner() * self.full.height); - size = Size::new(width, width / aspect); + size = Size::new(width, width / aspect.into_inner()); } let mut output = Frame::new(size, size.height); @@ -141,7 +143,7 @@ impl StackLayouter { // Align along the cross axis. let cross = aligns .cross - .resolve(self.dirs.cross, Length::ZERO .. size.cross - child.cross); + .resolve(self.dirs.cross, Length::zero() .. size.cross - child.cross); // Align along the main axis. let main = aligns.main.resolve( @@ -163,7 +165,7 @@ impl StackLayouter { output.push_frame(pos, frame); } - self.size = Gen::ZERO; + self.size = Gen::zero(); self.ruler = Align::Start; self.regions.next(); if let Some(aspect) = self.aspect { diff --git a/src/library/font.rs b/src/library/font.rs index 33a521f53..b3b037cd8 100644 --- a/src/library/font.rs +++ b/src/library/font.rs @@ -68,7 +68,7 @@ pub fn font(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { if let Some(linear) = size { if linear.rel.is_zero() { ctx.state.font.size = linear.abs; - ctx.state.font.scale = Relative::ONE.into(); + ctx.state.font.scale = Linear::one(); } else { ctx.state.font.scale = linear; } diff --git a/src/library/image.rs b/src/library/image.rs index 9b880d040..b73c26a9b 100644 --- a/src/library/image.rs +++ b/src/library/image.rs @@ -32,7 +32,7 @@ pub fn image(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { } /// An image node. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Hash)] struct ImageNode { /// The id of the image file. id: ImageId, @@ -73,7 +73,7 @@ impl Layout for ImageNode { }; let mut frame = Frame::new(size, size.height); - frame.push(Point::ZERO, Element::Image(self.id, size)); + frame.push(Point::zero(), Element::Image(self.id, size)); vec![frame] } } diff --git a/src/library/shapes.rs b/src/library/shapes.rs index ce8f634b5..05cc2e2d3 100644 --- a/src/library/shapes.rs +++ b/src/library/shapes.rs @@ -1,5 +1,7 @@ use std::f64::consts::SQRT_2; +use decorum::NotNan; + use super::*; use crate::color::Color; use crate::layout::{BackgroundNode, BackgroundShape, Fill, FixedNode, PadNode}; @@ -47,14 +49,14 @@ pub fn square(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { let height = width.is_none().then(|| args.eat_named(ctx, "height")).flatten(); let fill = args.eat_named(ctx, "fill"); let body = args.eat::(ctx).unwrap_or_default(); - rect_impl("square", width, height, Some(1.0), fill, body) + rect_impl("square", width, height, Some(1.0.into()), fill, body) } fn rect_impl( name: &str, width: Option, height: Option, - aspect: Option, + aspect: Option>, fill: Option, body: TemplateValue, ) -> Value { @@ -119,14 +121,14 @@ pub fn circle(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { let height = width.is_none().then(|| args.eat_named(ctx, "height")).flatten(); let fill = args.eat_named(ctx, "fill"); let body = args.eat::(ctx).unwrap_or_default(); - ellipse_impl("circle", width, height, Some(1.0), fill, body) + ellipse_impl("circle", width, height, Some(1.0.into()), fill, body) } fn ellipse_impl( name: &str, width: Option, height: Option, - aspect: Option, + aspect: Option>, fill: Option, body: TemplateValue, ) -> Value { diff --git a/src/pdf/mod.rs b/src/pdf/mod.rs index 763dc7699..1769e2ae2 100644 --- a/src/pdf/mod.rs +++ b/src/pdf/mod.rs @@ -132,7 +132,7 @@ impl<'a> PdfExporter<'a> { // We only write font switching actions when the used face changes. To // do that, we need to remember the active face. let mut face = FaceId::MAX; - let mut size = Length::ZERO; + let mut size = Length::zero(); let mut fill: Option = None; for (pos, element) in &page.elements { diff --git a/src/pretty.rs b/src/pretty.rs index 4e03ed849..acdb46a0d 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -742,7 +742,7 @@ mod tests { test_value(3.14, "3.14"); test_value(Length::pt(5.5), "5.5pt"); test_value(Angle::deg(90.0), "90deg"); - test_value(Relative::ONE / 2.0, "50%"); + test_value(Relative::one() / 2.0, "50%"); test_value(Relative::new(0.3) + Length::cm(2.0), "30% + 2cm"); test_value(Color::Rgba(RgbaColor::new(1, 1, 1, 0xff)), "#010101"); test_value("hello", r#""hello""#);