diff --git a/src/color.rs b/src/color.rs index 5944b7c00..750d6da30 100644 --- a/src/color.rs +++ b/src/color.rs @@ -10,7 +10,7 @@ use std::str::FromStr; /// [page: background=#423abaff] /// ^^^^^^^^ /// ``` -#[derive(Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Copy, Clone, Eq, PartialEq)] pub struct RgbaColor { /// Red channel. pub r: u8, diff --git a/src/diag.rs b/src/diag.rs index f85583901..801dc6a3b 100644 --- a/src/diag.rs +++ b/src/diag.rs @@ -17,7 +17,7 @@ pub struct Diag { } /// How severe / important a diagnostic is. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "serialize", derive(serde::Serialize))] #[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))] pub enum Level { diff --git a/src/eval/state.rs b/src/eval/state.rs index 3a9f05a40..d90096140 100644 --- a/src/eval/state.rs +++ b/src/eval/state.rs @@ -3,8 +3,8 @@ use fontdock::{fallback, FallbackTree, FontStretch, FontStyle, FontVariant, FontWeight}; use super::Scope; -use crate::geom::{Insets, Linear, Sides, Size}; -use crate::layout::{Dir, GenAlign, LayoutAlign, LayoutSystem}; +use crate::geom::{Insets, Linear, Size}; +use crate::layout::{Dir, GenAlign, LayoutAlign, LayoutSystem, Sides}; use crate::length::Length; use crate::paper::{Paper, PaperClass, PAPER_A4}; diff --git a/src/geom.rs b/src/geom.rs index 0a65a0902..d38d6fe74 100644 --- a/src/geom.rs +++ b/src/geom.rs @@ -12,17 +12,11 @@ use crate::layout::primitive::{Dir, GenAlign, LayoutAlign, LayoutSystem, SpecAxi /// /// [sizes]: ../../kurbo/struct.Size.html pub trait SizeExt { - /// Return the primary component of this specialized size. - fn primary(self, sys: LayoutSystem) -> f64; + /// Return the component for the specified axis. + fn get(self, axis: SpecAxis) -> f64; - /// Borrow the primary component of this specialized size mutably. - fn primary_mut(&mut self, sys: LayoutSystem) -> &mut f64; - - /// Return the secondary component of this specialized size. - fn secondary(self, sys: LayoutSystem) -> f64; - - /// Borrow the secondary component of this specialized size mutably. - fn secondary_mut(&mut self, sys: LayoutSystem) -> &mut f64; + /// Borrow the component for the specified axis mutably. + fn get_mut(&mut self, axis: SpecAxis) -> &mut f64; /// Returns the generalized version of a `Size` based on the layouting /// system, that is: @@ -38,44 +32,26 @@ pub trait SizeExt { /// values are smaller or equal. fn fits(self, other: Self) -> bool; - /// The anchor position along the given axis for an item with the given - /// alignment in a container with this size. + /// The anchor position for an object to be aligned according to `align` in + /// a container with this size. /// - /// This assumes the size to be generalized such that `x` corresponds to the - /// primary axis. + /// This assumes the size to be generalized such that `width` corresponds to + /// the primary and `height` to the secondary axis. fn anchor(self, align: LayoutAlign, sys: LayoutSystem) -> Point; } impl SizeExt for Size { - fn primary(self, sys: LayoutSystem) -> f64 { - if sys.primary.axis() == SpecAxis::Horizontal { - self.width - } else { - self.height + fn get(self, axis: SpecAxis) -> f64 { + match axis { + SpecAxis::Horizontal => self.width, + SpecAxis::Vertical => self.height, } } - fn primary_mut(&mut self, sys: LayoutSystem) -> &mut f64 { - if sys.primary.axis() == SpecAxis::Horizontal { - &mut self.width - } else { - &mut self.height - } - } - - fn secondary(self, sys: LayoutSystem) -> f64 { - if sys.primary.axis() == SpecAxis::Horizontal { - self.height - } else { - self.width - } - } - - fn secondary_mut(&mut self, sys: LayoutSystem) -> &mut f64 { - if sys.primary.axis() == SpecAxis::Horizontal { - &mut self.height - } else { - &mut self.width + fn get_mut(&mut self, axis: SpecAxis) -> &mut f64 { + match axis { + SpecAxis::Horizontal => &mut self.width, + SpecAxis::Vertical => &mut self.height, } } @@ -87,8 +63,8 @@ impl SizeExt for Size { } fn specialized(self, sys: LayoutSystem) -> Self { - // In fact, generalized is its own inverse. For reasons of clarity - // at the call site, we still have this second function. + // Even though generalized is its own inverse, we still have this second + // function, for clarity at the call-site. self.generalized(sys) } @@ -97,7 +73,7 @@ impl SizeExt for Size { } fn anchor(self, align: LayoutAlign, sys: LayoutSystem) -> Point { - fn length_anchor(length: f64, align: GenAlign, dir: Dir) -> f64 { + fn anchor(length: f64, align: GenAlign, dir: Dir) -> f64 { match (dir.is_positive(), align) { (true, GenAlign::Start) | (false, GenAlign::End) => 0.0, (_, GenAlign::Center) => length / 2.0, @@ -106,8 +82,8 @@ impl SizeExt for Size { } Point::new( - length_anchor(self.width, align.primary, sys.primary), - length_anchor(self.height, align.secondary, sys.secondary), + anchor(self.width, align.primary, sys.primary), + anchor(self.height, align.secondary, sys.secondary), ) } } @@ -116,7 +92,12 @@ impl SizeExt for Size { /// /// [rectangles]: ../../kurbo/struct.Rect.html pub trait RectExt { - /// Get a mutable reference to the value for the specified direction at the + /// Return the side identified by direction and alignment. + /// + /// Center alignment is treated the same as origin alignment. + fn get(&mut self, dir: Dir, align: GenAlign) -> f64; + + /// Get a mutable reference to the side identified by direction and /// alignment. /// /// Center alignment is treated the same as origin alignment. @@ -124,6 +105,15 @@ pub trait RectExt { } impl RectExt for Rect { + fn get(&mut self, dir: Dir, align: GenAlign) -> f64 { + match if align == GenAlign::End { dir.inv() } else { dir } { + Dir::LTR => self.x0, + Dir::TTB => self.y0, + Dir::RTL => self.x1, + Dir::BTT => self.y1, + } + } + fn get_mut(&mut self, dir: Dir, align: GenAlign) -> &mut f64 { match if align == GenAlign::End { dir.inv() } else { dir } { Dir::LTR => &mut self.x0, @@ -134,52 +124,6 @@ impl RectExt for Rect { } } -/// A generic container for `[left, top, right, bottom]` values. -#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)] -pub struct Sides { - /// The value for the left side. - pub left: T, - /// The value for the top side. - pub top: T, - /// The value for the right side. - pub right: T, - /// The value for the bottom side. - pub bottom: T, -} - -impl Sides { - /// Create a new box from four sizes. - pub fn new(left: T, top: T, right: T, bottom: T) -> Self { - Self { left, top, right, bottom } - } - - /// Create an instance with all four components set to the same `value`. - pub fn uniform(value: T) -> Self - where - T: Clone, - { - Self { - left: value.clone(), - top: value.clone(), - right: value.clone(), - bottom: value, - } - } - - /// Get a mutable reference to the value for the specified direction at the - /// alignment. - /// - /// Center alignment is treated the same as origin alignment. - pub fn get_mut(&mut self, dir: Dir, align: GenAlign) -> &mut T { - match if align == GenAlign::End { dir.inv() } else { dir } { - Dir::LTR => &mut self.left, - Dir::RTL => &mut self.right, - Dir::TTB => &mut self.top, - Dir::BTT => &mut self.bottom, - } - } -} - /// A function that depends linearly on one value. /// /// This represents a function `f(x) = rel * x + abs`. diff --git a/src/layout/line.rs b/src/layout/line.rs index 19ec053df..745a0d144 100644 --- a/src/layout/line.rs +++ b/src/layout/line.rs @@ -67,7 +67,7 @@ impl LineLayouter { } else if align.primary > prev.primary { let mut rest_run = LineRun::new(); - let usable = self.stack.usable().primary(sys); + let usable = self.stack.usable().get(sys.primary.axis()); rest_run.usable = Some(match align.primary { GenAlign::Start => unreachable!("start > x"), GenAlign::Center => usable - 2.0 * self.run.size.width, @@ -181,7 +181,7 @@ impl LineLayouter { /// it will fit into this layouter's underlying stack. pub fn remaining(&self) -> Vec { let mut spaces = self.stack.remaining(); - *spaces[0].size.secondary_mut(self.ctx.sys) -= self.run.size.height; + *spaces[0].size.get_mut(self.ctx.sys.secondary.axis()) -= self.run.size.height; spaces } @@ -213,7 +213,11 @@ impl LineLayouter { for (offset, child) in layouts { let x = match self.ctx.sys.primary.is_positive() { true => offset, - false => self.run.size.width - offset - child.size.primary(self.ctx.sys), + false => { + self.run.size.width + - offset + - child.size.get(self.ctx.sys.primary.axis()) + } }; let pos = Point::new(x, 0.0); diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 5e4e020ef..2ba1b0de5 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -11,7 +11,7 @@ pub use primitive::*; pub use stack::*; pub use tree::*; -use crate::geom::{Insets, Point, Rect, RectExt, Sides, Size, SizeExt}; +use crate::geom::{Insets, Point, Rect, RectExt, Size, SizeExt}; use crate::diag::Diag; use crate::eval::{PageState, State, TextState}; diff --git a/src/layout/primitive.rs b/src/layout/primitive.rs index d13110e3e..64cd1dff5 100644 --- a/src/layout/primitive.rs +++ b/src/layout/primitive.rs @@ -27,7 +27,7 @@ impl Default for LayoutAlign { pub type LayoutExpansion = Spec2; /// The four directions into which content can be laid out. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum Dir { /// Left to right. LTR, @@ -40,26 +40,6 @@ pub enum Dir { } impl Dir { - /// The side this direction starts at. - pub fn start(self) -> Side { - match self { - Self::LTR => Side::Left, - Self::RTL => Side::Right, - Self::TTB => Side::Top, - Self::BTT => Side::Bottom, - } - } - - /// The side this direction ends at. - pub fn end(self) -> Side { - match self { - Self::LTR => Side::Right, - Self::RTL => Side::Left, - Self::TTB => Side::Bottom, - Self::BTT => Side::Top, - } - } - /// The specific axis this direction belongs to. pub fn axis(self) -> SpecAxis { match self { @@ -95,6 +75,18 @@ impl Dir { Self::BTT => Self::TTB, } } + + /// The side of this direction the alignment identifies. + /// + /// `Center` alignment is treated the same as `Start` alignment. + pub fn side(self, align: GenAlign) -> Side { + match if align == GenAlign::End { self.inv() } else { self } { + Self::LTR => Side::Left, + Self::RTL => Side::Right, + Self::TTB => Side::Top, + Self::BTT => Side::Bottom, + } + } } impl Display for Dir { @@ -109,7 +101,7 @@ impl Display for Dir { } /// The two generic layouting axes. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum GenAxis { /// The primary layouting direction into which text and lines flow. Primary, @@ -134,7 +126,7 @@ impl Display for GenAxis { } /// The two specific layouting axes. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum SpecAxis { /// The horizontal layouting axis. Horizontal, @@ -162,17 +154,8 @@ impl Display for SpecAxis { } } -/// A side of a container. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Side { - Left, - Top, - Right, - Bottom, -} - /// Where to align content along an axis in a generic context. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] pub enum GenAlign { Start, Center, @@ -201,7 +184,7 @@ impl Display for GenAlign { } /// Where to align content along an axis in a specific context. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] pub enum SpecAlign { Left, Right, @@ -256,8 +239,29 @@ impl Display for SpecAlign { } } +/// A side of a container. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum Side { + Left, + Top, + Right, + Bottom, +} + +impl Side { + /// The opposite side. + pub fn inv(self) -> Self { + match self { + Self::Left => Self::Right, + Self::Top => Self::Bottom, + Self::Right => Self::Left, + Self::Bottom => Self::Top, + } + } +} + /// A generic container with two components for the two generic axes. -#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)] pub struct Gen2 { /// The primary component. pub primary: T, @@ -279,14 +283,6 @@ impl Gen2 { } } - /// Borrow the component for the specified generic axis. - pub fn get_ref(&mut self, axis: GenAxis) -> &T { - match axis { - GenAxis::Primary => &mut self.primary, - GenAxis::Secondary => &mut self.secondary, - } - } - /// Borrow the component for the specified generic axis mutably. pub fn get_mut(&mut self, axis: GenAxis) -> &mut T { match axis { @@ -297,7 +293,7 @@ impl Gen2 { } /// A generic container with two components for the two specific axes. -#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)] pub struct Spec2 { /// The horizontal component. pub horizontal: T, @@ -319,14 +315,6 @@ impl Spec2 { } } - /// Borrow the component for the given specific axis. - pub fn get_ref(&mut self, axis: SpecAxis) -> &T { - match axis { - SpecAxis::Horizontal => &mut self.horizontal, - SpecAxis::Vertical => &mut self.vertical, - } - } - /// Borrow the component for the given specific axis mutably. pub fn get_mut(&mut self, axis: SpecAxis) -> &mut T { match axis { @@ -335,3 +323,56 @@ impl Spec2 { } } } + +/// A generic container with left, top, right and bottom components. +#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)] +pub struct Sides { + /// The value for the left side. + pub left: T, + /// The value for the top side. + pub top: T, + /// The value for the right side. + pub right: T, + /// The value for the bottom side. + pub bottom: T, +} + +impl Sides { + /// Create a new box from four sizes. + pub fn new(left: T, top: T, right: T, bottom: T) -> Self { + Self { left, top, right, bottom } + } + + /// Create an instance with all four components set to the same `value`. + pub fn uniform(value: T) -> Self + where + T: Clone, + { + Self { + left: value.clone(), + top: value.clone(), + right: value.clone(), + bottom: value, + } + } + + /// Return the component for the given side. + pub fn get(self, side: Side) -> T { + match side { + Side::Left => self.left, + Side::Right => self.right, + Side::Top => self.top, + Side::Bottom => self.bottom, + } + } + + /// Borrow the component for the given side mutably. + pub fn get_mut(&mut self, side: Side) -> &mut T { + match side { + Side::Left => &mut self.left, + Side::Right => &mut self.right, + Side::Top => &mut self.top, + Side::Bottom => &mut self.bottom, + } + } +} diff --git a/src/layout/stack.rs b/src/layout/stack.rs index 04c78da56..de933fbf2 100644 --- a/src/layout/stack.rs +++ b/src/layout/stack.rs @@ -90,9 +90,10 @@ impl StackLayouter { // A hard space is simply an empty box. SpacingKind::Hard => { // Reduce the spacing such that it definitely fits. - spacing = spacing.min(self.space.usable.secondary(self.ctx.sys)); - let size = Size::new(0.0, spacing); + let axis = self.ctx.sys.secondary.axis(); + spacing = spacing.min(self.space.usable.get(axis)); + let size = Size::new(0.0, spacing); self.update_metrics(size); self.space.layouts.push(( self.ctx.sys, @@ -133,29 +134,29 @@ impl StackLayouter { self.space.size = size.specialized(sys); self.space.extra = extra.specialized(sys); - *self.space.usable.secondary_mut(sys) -= added.height; + *self.space.usable.get_mut(sys.secondary.axis()) -= added.height; } /// Returns true if a space break is necessary. fn update_rulers(&mut self, align: LayoutAlign) -> bool { let allowed = self.is_fitting_alignment(align); if allowed { - *self.space.rulers.get_mut(self.ctx.sys.secondary, GenAlign::Start) = - align.secondary; + let side = self.ctx.sys.secondary.side(GenAlign::Start); + *self.space.rulers.get_mut(side) = align.secondary; } allowed } /// Whether a layout with the given alignment can still be layouted into the /// active space or a space break is necessary. - pub(crate) fn is_fitting_alignment(&mut self, align: LayoutAlign) -> bool { + pub(crate) fn is_fitting_alignment(&self, align: LayoutAlign) -> bool { self.is_fitting_axis(self.ctx.sys.primary, align.primary) && self.is_fitting_axis(self.ctx.sys.secondary, align.secondary) } - fn is_fitting_axis(&mut self, dir: Dir, align: GenAlign) -> bool { - align >= *self.space.rulers.get_mut(dir, GenAlign::Start) - && align <= self.space.rulers.get_mut(dir, GenAlign::End).inv() + fn is_fitting_axis(&self, dir: Dir, align: GenAlign) -> bool { + align >= self.space.rulers.get(dir.side(GenAlign::Start)) + && align <= self.space.rulers.get(dir.side(GenAlign::End)).inv() } /// Update the layouting system. @@ -284,7 +285,7 @@ impl StackLayouter { // the usable space for following layouts at its origin by its // extent along the secondary axis. *bound.get_mut(sys.secondary, GenAlign::Start) += - sys.secondary.factor() * layout.size.secondary(*sys); + sys.secondary.factor() * layout.size.get(sys.secondary.axis()); } // ------------------------------------------------------------------ // diff --git a/src/library/page.rs b/src/library/page.rs index 2bf9f0194..fd33039cf 100644 --- a/src/library/page.rs +++ b/src/library/page.rs @@ -1,7 +1,7 @@ use std::mem; use crate::eval::Absolute; -use crate::geom::{Linear, Sides}; +use crate::geom::Linear; use crate::paper::{Paper, PaperClass}; use crate::prelude::*; diff --git a/src/paper.rs b/src/paper.rs index aff4cdd7c..21762b17f 100644 --- a/src/paper.rs +++ b/src/paper.rs @@ -1,6 +1,7 @@ //! Predefined papers. -use crate::geom::{Linear, Sides, Size}; +use crate::geom::{Linear, Size}; +use crate::layout::Sides; use crate::length::Length; /// Specification of a paper. diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs index fbfb71e68..03dec6d7c 100644 --- a/src/parse/tokens.rs +++ b/src/parse/tokens.rs @@ -19,7 +19,7 @@ pub struct Tokens<'s> { /// Whether to tokenize in header mode which yields expression, comma and /// similar tokens or in body mode which yields text and star, underscore, /// backtick tokens. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum TokenMode { Header, Body, diff --git a/src/syntax/ident.rs b/src/syntax/ident.rs index 5ab7c73c4..f8c38cfb2 100644 --- a/src/syntax/ident.rs +++ b/src/syntax/ident.rs @@ -10,7 +10,7 @@ use unicode_xid::UnicodeXID; /// `-` and `_` as starting and continuing characters. /// /// [Unicode Standard]: http://www.unicode.org/reports/tr31/ -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] pub struct Ident(pub String); impl Ident { diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index a6ae92670..a85b06a98 100644 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -12,7 +12,7 @@ pub use span::*; pub use token::*; /// Decorations for semantic syntax highlighting. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "serialize", derive(serde::Serialize))] #[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))] pub enum Deco { diff --git a/src/syntax/span.rs b/src/syntax/span.rs index 6ba9c44a3..5f51d1579 100644 --- a/src/syntax/span.rs +++ b/src/syntax/span.rs @@ -40,7 +40,7 @@ impl Offset for SpanVec { } /// A value with the span it corresponds to in the source code. -#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "serialize", derive(serde::Serialize))] pub struct Spanned { /// The spanned value. @@ -108,7 +108,7 @@ impl Debug for Spanned { } /// Locates a slice of source code. -#[derive(Copy, Clone, Ord, PartialOrd, Hash)] +#[derive(Copy, Clone, Ord, PartialOrd)] #[cfg_attr(feature = "serialize", derive(serde::Serialize))] pub struct Span { /// The inclusive start position. @@ -209,7 +209,7 @@ impl Debug for Span { } /// A byte position in source code. -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "serialize", derive(serde::Serialize))] pub struct Pos(pub u32); @@ -254,7 +254,7 @@ impl Debug for Pos { } /// A one-indexed line-column position in source code. -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "serialize", derive(serde::Serialize))] pub struct Location { /// The one-indexed line.