1use std::fmt::Write;
6
7pub trait FontFormat: Sized {
9 const DEFAULT_FILE_EXTENSION: &'static str;
10 type Error: std::error::Error + 'static;
11
12 fn parse(b: &[u8]) -> Result<Self, Self::Error>;
14}
15
16#[derive(PartialEq, Eq, Debug, Copy, Clone, PartialOrd, Ord, Hash)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
21pub struct FontId(pub u32);
22
23impl FontId {
24 pub const NULL: FontId = FontId(0);
26
27 pub const ONE: FontId = FontId(1);
29}
30
31impl Default for FontId {
32 fn default() -> Self {
36 FontId::NULL
37 }
38}
39
40impl std::fmt::Display for FontId {
41 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42 write!(f, "{}", self.0)
43 }
44}
45
46#[derive(Default, PartialEq, Eq, Debug, Copy, Clone, PartialOrd, Ord, Hash)]
56#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
57pub struct Scaled(pub i32);
58
59impl Scaled {
60 pub const ZERO: Scaled = Scaled(0);
62
63 pub const ONE: Scaled = Scaled(1 << 16);
65
66 pub const TWO: Scaled = Scaled(1 << 17);
68
69 pub fn is_zero(&self) -> bool {
70 *self == Scaled::ZERO
71 }
72
73 pub const MAX_DIMEN: Scaled = Scaled((1 << 30) - 1);
79
80 pub fn from_integer(i: i32) -> Result<Scaled, OverflowError> {
85 if i >= (1 << 14) || i <= -(1 << 14) {
86 Err(OverflowError {})
87 } else {
88 Ok(Scaled(Scaled::ONE.0 * i))
89 }
90 }
91
92 pub fn from_decimal_digits(digits: &[u8]) -> Scaled {
96 let mut a = 0;
97 for d in digits.iter().rev() {
98 a = (a + (*d as i32) * Scaled::TWO.0) / 10
99 }
100 Scaled((a + 1) / 2)
101 }
102
103 pub fn new(
107 integer_part: i32,
108 fractional_part: Scaled,
109 scaled_unit: ScaledUnit,
110 ) -> Result<Scaled, OverflowError> {
111 if scaled_unit == ScaledUnit::ScaledPoint {
112 return if integer_part > Scaled::MAX_DIMEN.0 {
113 Err(OverflowError)
114 } else {
115 Ok(Scaled(integer_part))
117 };
118 }
119 let (n, d) = scaled_unit.conversion_fraction();
120 let (Scaled(i), Scaled(remainder)) = Scaled(integer_part).xn_over_d(n, d)?;
122 let f =
123 fractional_part.nx_plus_y(n, Scaled::from_integer(remainder).expect("remainder<d<=7200<2^13, so a valid scaled number"))
124 .expect("fractional_part<2^16, remainder<2^16*d, so nx_plus_y<2^16(n+d). Each (n,d) makes this <2^30")
125 / d;
126 let integer_part = Scaled::from_integer(i + f.integer_part())?;
127 Ok(integer_part + f.fractional_part())
128 }
129
130 pub fn xn_over_d(&self, n: i32, d: i32) -> Result<(Scaled, Scaled), OverflowError> {
141 debug_assert!(n <= 0o200000);
142 debug_assert!(d <= 0o200000);
143 let mut b: i64 = self.0.into();
144 b *= n as i64; let remainder: i32 = (b % (d as i64)).try_into().expect("d<=2^16 so b%d<2^16");
146 b /= d as i64;
147 if b < -(Scaled::MAX_DIMEN.0 as i64) || b > Scaled::MAX_DIMEN.0 as i64 {
148 return Err(OverflowError {});
149 }
150 let b: i32 = b.try_into().expect("b in (-2^30, +2^30)");
151 Ok((Scaled(b), Scaled(remainder)))
152 }
153
154 pub fn nx_plus_y(self, mut n: i32, y: Scaled) -> Result<Scaled, OverflowError> {
156 let max_answer = Scaled::MAX_DIMEN;
157 if n == 0 {
158 return Ok(y);
159 }
160 let mut x = self;
161 if n < 0 {
162 n = -n;
163 x = -x;
164 }
165 if x <= (max_answer - y) / n && -x <= (max_answer + y) / n {
166 Ok(x * n + y)
167 } else {
168 Err(OverflowError {})
169 }
170 }
171
172 pub fn parse_from_string(s: &str) -> Result<Scaled, String> {
177 if s.len() < 3 {
178 return Err(format!(
179 "invalid dimension \"{s}\": expected <number><unit> (e.g. 100pt)"
180 ));
181 }
182 let (value_str, unit_str) = s.split_at(s.len() - 2);
183 let unit = ScaledUnit::parse(unit_str)
184 .ok_or_else(|| format!("invalid unit \"{unit_str}\" in dimension \"{s}\""))?;
185 Self::parse_from_string_with_unit(value_str, unit)
186 }
187
188 fn parse_from_string_with_unit(s: &str, unit: ScaledUnit) -> Result<Scaled, String> {
189 let (int_str, frac_str) = match s.find('.') {
190 Some(pos) => (&s[..pos], &s[pos + 1..]),
191 None => (s, ""),
192 };
193 let integer_part: i32 = int_str
194 .parse()
195 .map_err(|_| format!("invalid number \"{int_str}\" in dimension \"{s}{unit}\""))?;
196 let frac_digits: Vec<u8> = frac_str.chars().map(|c| c as u8 - b'0').collect();
197 if frac_digits.iter().any(|&d| d > 9) {
198 return Err(format!(
199 "invalid fractional part \"{frac_str}\" in dimension \"{s}{unit}\""
200 ));
201 }
202 let fractional_part = Scaled::from_decimal_digits(&frac_digits);
203 Scaled::new(integer_part, fractional_part, unit)
204 .map_err(|_| format!("dimension \"{s}{unit}\" is out of range"))
205 }
206
207 pub fn parse_no_units(s: &str) -> Result<Scaled, OverflowError> {
226 let (neg, s) = match s.strip_prefix('-') {
227 Some(s) => (true, s),
228 None => (false, s),
229 };
230 let mut parts = s.split('.');
231 let i: i32 = parts
232 .next()
233 .expect("scaled has an integer part")
234 .parse()
235 .expect("integer part is an integer");
236 let mut f = [0_u8; 17];
237 for (k, c) in parts
238 .next()
239 .expect("scaled has a fractional part")
240 .chars()
241 .enumerate()
242 {
243 f[k] = c
244 .to_digit(10)
245 .expect("fractional part are digits")
246 .try_into()
247 .expect("digits are in the range [0,10) and always fit in u8");
248 }
249 let f = Scaled::from_decimal_digits(&f);
250 let sc = Scaled::new(i, f, ScaledUnit::Point)?;
251 Ok(if neg { -sc } else { sc })
252 }
253
254 pub fn integer_part(self) -> i32 {
255 self.0 / Scaled::ONE.0
256 }
257
258 pub fn fractional_part(self) -> Scaled {
259 self % Scaled::ONE.0
260 }
261
262 pub fn abs(self) -> Scaled {
263 Scaled(self.0.abs())
264 }
265
266 pub fn wrapping_add(self, rhs: Scaled) -> Self {
267 Scaled(self.0.wrapping_add(rhs.0))
268 }
269 pub fn checked_add(self, rhs: Scaled) -> Option<Self> {
270 Some(Scaled(self.0.checked_add(rhs.0)?))
271 }
272 pub fn wrapping_mul(self, rhs: i32) -> Self {
273 Scaled(self.0.wrapping_mul(rhs))
274 }
275 pub fn checked_mul(self, rhs: i32) -> Option<Self> {
276 self.nx_plus_y(rhs, Scaled::ZERO).ok()
279 }
280 pub fn checked_div(self, rhs: i32) -> Option<Self> {
281 Some(Scaled(self.0.checked_div(rhs)?))
282 }
283 pub fn display_no_units(self) -> impl std::fmt::Display {
285 struct D {
286 s: Scaled,
287 }
288 impl std::fmt::Display for D {
289 fn fmt(&self, fm: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
290 if self.s.0 < 0 {
291 write!(fm, "-")?;
292 }
293 write!(fm, "{}.", self.s.integer_part().abs())?;
294 let mut f = self.s.fractional_part().abs() * 10 + Scaled(5);
296 let mut delta = Scaled(10);
297 loop {
298 if delta > Scaled::ONE {
299 f += Scaled(0o100000 - 50000);
301 }
302 fm.write_char(
303 char::from_digit(f.integer_part().try_into().unwrap(), 10).unwrap(),
304 )?;
305 f = f.fractional_part() * 10;
306 delta = delta * 10;
307 if f <= delta {
308 break;
309 }
310 }
311 Ok(())
312 }
313 }
314 D { s: self }
315 }
316}
317
318#[derive(Debug, PartialEq, Eq)]
319pub struct OverflowError;
320
321impl std::fmt::Display for Scaled {
322 fn fmt(&self, fm: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
323 write!(fm, "{}", self.display_no_units())?;
325 write!(fm, "pt")?;
327 Ok(())
328 }
329}
330
331impl std::iter::Sum for Scaled {
332 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
333 Self(iter.map(|s| s.0).sum())
334 }
335}
336
337impl std::ops::Add<Scaled> for Scaled {
338 type Output = Scaled;
339 fn add(self, rhs: Scaled) -> Self::Output {
340 Scaled(self.0 + rhs.0)
341 }
342}
343
344impl std::ops::AddAssign<Scaled> for Scaled {
345 fn add_assign(&mut self, rhs: Scaled) {
346 self.0 += rhs.0;
347 }
348}
349
350impl std::ops::Sub<Scaled> for Scaled {
351 type Output = Scaled;
352 fn sub(self, rhs: Scaled) -> Self::Output {
353 Scaled(self.0 - rhs.0)
354 }
355}
356
357impl std::ops::SubAssign<Scaled> for Scaled {
358 fn sub_assign(&mut self, rhs: Scaled) {
359 self.0 -= rhs.0;
360 }
361}
362
363impl std::ops::Mul<i32> for Scaled {
364 type Output = Scaled;
365 fn mul(self, rhs: i32) -> Self::Output {
366 Scaled(self.0 * rhs)
367 }
368}
369
370impl std::ops::Div<i32> for Scaled {
371 type Output = Scaled;
372 fn div(self, rhs: i32) -> Self::Output {
373 Scaled(self.0 / rhs)
374 }
375}
376
377impl std::ops::DivAssign<i32> for Scaled {
378 fn div_assign(&mut self, rhs: i32) {
379 self.0 = self.0 / rhs
380 }
381}
382
383impl std::ops::Rem<i32> for Scaled {
384 type Output = Scaled;
385 fn rem(self, rhs: i32) -> Self::Output {
386 Scaled(self.0 % rhs)
387 }
388}
389
390impl std::ops::Neg for Scaled {
391 type Output = Scaled;
392 fn neg(self) -> Self::Output {
393 Scaled(-self.0)
394 }
395}
396
397#[derive(Debug, Clone, Copy, PartialEq, Eq)]
401pub enum ScaledUnit {
402 Point,
403 Pica,
404 Inch,
405 BigPoint,
406 Centimeter,
407 Millimeter,
408 DidotPoint,
409 Cicero,
410 ScaledPoint,
411}
412
413impl std::fmt::Display for ScaledUnit {
414 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
415 write!(f, "{}", self.abbreviation())
416 }
417}
418
419impl ScaledUnit {
420 pub fn abbreviation(&self) -> &'static str {
422 use ScaledUnit::*;
423 match self {
424 Point => "pt",
425 Pica => "pc",
426 Inch => "in",
427 BigPoint => "bp",
428 Centimeter => "cm",
429 Millimeter => "mm",
430 DidotPoint => "dd",
431 Cicero => "cc",
432 ScaledPoint => "sp",
433 }
434 }
435
436 pub fn parse(s: &str) -> Option<Self> {
441 use ScaledUnit::*;
442 Some(match s {
443 "pt" => Point,
444 "pc" => Pica,
445 "in" => Inch,
446 "bp" => BigPoint,
447 "cm" => Centimeter,
448 "mm" => Millimeter,
449 "dd" => DidotPoint,
450 "cc" => Cicero,
451 "sp" => ScaledPoint,
452 _ => return None,
453 })
454 }
455
456 pub fn conversion_fraction(&self) -> (i32, i32) {
464 use ScaledUnit::*;
465 match self {
466 Point => (1, 1),
467 Pica => (12, 1),
468 Inch => (7227, 100),
469 BigPoint => (7227, 7200),
470 Centimeter => (7227, 254),
471 Millimeter => (7227, 2540),
472 DidotPoint => (1238, 1157),
473 Cicero => (14856, 1157),
474 ScaledPoint => (1, 1 << 16),
475 }
476 }
477}
478
479#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
490#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
491pub struct Glue {
492 pub width: Scaled,
493 pub stretch: Scaled,
494 pub stretch_order: GlueOrder,
495 pub shrink: Scaled,
496 pub shrink_order: GlueOrder,
497}
498
499impl Glue {
500 pub const ZERO: Glue = Glue {
501 width: Scaled::ZERO,
502 stretch: Scaled::ZERO,
503 stretch_order: GlueOrder::Normal,
504 shrink: Scaled::ZERO,
505 shrink_order: GlueOrder::Normal,
506 };
507 pub fn is_zero(&self) -> bool {
508 self.width == Scaled::ZERO && self.stretch == Scaled::ZERO && self.shrink == Scaled::ZERO
509 }
510}
511
512impl std::ops::Mul<i32> for Glue {
513 type Output = Glue;
514 fn mul(self, rhs: i32) -> Self::Output {
515 Glue {
516 width: self.width * rhs,
517 stretch: self.stretch * rhs,
518 stretch_order: self.stretch_order,
519 shrink: self.shrink * rhs,
520 shrink_order: self.shrink_order,
521 }
522 }
523}
524
525impl Glue {
526 pub fn wrapping_add(self, rhs: Glue) -> Self {
528 use std::cmp::Ordering::*;
529 Glue {
530 width: self.width.wrapping_add(rhs.width),
531 stretch: match self.stretch_order.cmp(&rhs.stretch_order) {
532 Less => rhs.stretch,
533 Equal => self.stretch.wrapping_add(rhs.stretch),
534 Greater => self.stretch,
535 },
536 stretch_order: self.stretch_order.max(rhs.stretch_order),
537 shrink: match self.shrink_order.cmp(&rhs.shrink_order) {
538 Less => rhs.shrink,
539 Equal => self.shrink.wrapping_add(rhs.shrink),
540 Greater => self.shrink,
541 },
542 shrink_order: self.shrink_order.max(rhs.shrink_order),
543 }
544 }
545 pub fn checked_add(self, rhs: Glue) -> Option<Self> {
546 use std::cmp::Ordering::*;
547 Some(Glue {
548 width: self.width.checked_add(rhs.width)?,
549 stretch: match self.stretch_order.cmp(&rhs.stretch_order) {
550 Less => rhs.stretch,
551 Equal => self.stretch.checked_add(rhs.stretch)?,
552 Greater => self.stretch,
553 },
554 stretch_order: self.stretch_order.max(rhs.stretch_order),
555 shrink: match self.shrink_order.cmp(&rhs.shrink_order) {
556 Less => rhs.shrink,
557 Equal => self.shrink.checked_add(rhs.shrink)?,
558 Greater => self.shrink,
559 },
560 shrink_order: self.shrink_order.max(rhs.shrink_order),
561 })
562 }
563 pub fn checked_mul(self, rhs: i32) -> Option<Self> {
564 Some(Glue {
565 width: self.width.checked_mul(rhs)?,
566 stretch: self.stretch.checked_mul(rhs)?,
567 stretch_order: self.stretch_order,
568 shrink: self.shrink.checked_mul(rhs)?,
569 shrink_order: self.shrink_order,
570 })
571 }
572 pub fn wrapping_mul(self, rhs: i32) -> Self {
573 Glue {
574 width: self.width.wrapping_mul(rhs),
575 stretch: self.stretch.wrapping_mul(rhs),
576 stretch_order: self.stretch_order,
577 shrink: self.shrink.wrapping_mul(rhs),
578 shrink_order: self.shrink_order,
579 }
580 }
581 pub fn checked_div(self, rhs: i32) -> Option<Self> {
582 Some(Glue {
583 width: self.width.checked_div(rhs)?,
584 stretch: self.stretch.checked_div(rhs)?,
585 stretch_order: self.stretch_order,
586 shrink: self.shrink.checked_div(rhs)?,
587 shrink_order: self.shrink_order,
588 })
589 }
590
591 pub fn parse_from_string(s: &str) -> Result<Glue, String> {
592 let mut glue = Glue::ZERO;
593 let (width_str, rest) = match s.find(" plus ").or_else(|| s.find(" minus ")) {
594 Some(pos) => (&s[..pos], s[pos..].trim()),
595 None => (s, ""),
596 };
597 glue.width = Scaled::parse_from_string(width_str.trim())?;
598 let rest = if let Some(r) = rest.strip_prefix("plus ") {
599 let (stretch_str, minus_rest) = match r.find(" minus ") {
600 Some(pos) => (&r[..pos], r[pos..].trim()),
601 None => (r, ""),
602 };
603 let (stretch, order) = Glue::parse_scaled_inf(stretch_str.trim())?;
604 glue.stretch = stretch;
605 glue.stretch_order = order;
606 minus_rest
607 } else {
608 rest
609 };
610 if let Some(shrink_str) = rest.strip_prefix("minus ") {
611 let (shrink, order) = Glue::parse_scaled_inf(shrink_str.trim())?;
612 glue.shrink = shrink;
613 glue.shrink_order = order;
614 } else if !rest.is_empty() {
615 return Err(format!("invalid glue {s:?}"));
616 }
617 Ok(glue)
618 }
619
620 fn parse_scaled_inf(s: &str) -> Result<(Scaled, GlueOrder), String> {
621 for (suffix, order) in [
622 ("filll", GlueOrder::Filll),
623 ("fill", GlueOrder::Fill),
624 ("fil", GlueOrder::Fil),
625 ] {
626 if let Some(num_str) = s.strip_suffix(suffix) {
627 return Ok((
628 Scaled::parse_from_string_with_unit(num_str, ScaledUnit::Point)?,
629 order,
630 ));
631 }
632 }
633 Ok((Scaled::parse_from_string(s)?, GlueOrder::Normal))
634 }
635}
636
637impl std::fmt::Display for Glue {
638 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
640 write!(f, "{}", self.width)?;
641 if self.stretch != Scaled::ZERO {
642 write!(f, " plus ")?;
643 write!(f, "{}", self.stretch.display_no_units())?;
644 write!(f, "{}", self.stretch_order)?;
645 }
646 if self.shrink != Scaled::ZERO {
647 write!(f, " minus ")?;
648 write!(f, "{}", self.shrink.display_no_units())?;
649 write!(f, "{}", self.shrink_order)?;
650 }
651 Ok(())
652 }
653}
654
655#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, PartialOrd, Ord)]
668#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
669pub enum GlueOrder {
670 #[default]
671 Normal,
672 Fil,
673 Fill,
674 Filll,
675}
676
677impl GlueOrder {
678 pub fn parse(s: &str) -> Option<Self> {
680 use GlueOrder::*;
681 Some(match s {
682 "fil" => Fil,
683 "fill" => Fill,
684 "filll" => Filll,
685 _ => return None,
686 })
687 }
688 pub fn inf_str(&self) -> Option<&'static str> {
689 use GlueOrder::*;
690 match self {
691 Normal => None,
692 Fil => Some("fil"),
693 Fill => Some("fill"),
694 Filll => Some("filll"),
695 }
696 }
697 pub fn next(&self) -> Option<Self> {
699 use GlueOrder::*;
700 match self {
701 Normal => Some(Fil),
702 Fil => Some(Fill),
703 Fill => Some(Filll),
704 Filll => None,
705 }
706 }
707}
708
709impl std::fmt::Display for GlueOrder {
710 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
711 write!(f, "{}", self.inf_str().unwrap_or("pt"))
712 }
713}
714
715#[cfg(test)]
716mod tests {
717 use super::*;
718
719 #[test]
720 fn type_sizes() {
721 assert_eq!(16, std::mem::size_of::<Glue>());
722 }
723
724 macro_rules! parse_from_string_tests {
725 ( $( $name:ident : $input:expr => $expected:expr, )* ) => {
726 $(
727 #[test]
728 fn $name() {
729 assert_eq!(Scaled::parse_from_string($input), $expected);
730 }
731 )*
732 };
733 }
734
735 parse_from_string_tests! {
736 integer_pt: "100pt" => Ok(Scaled::new(100, Scaled::ZERO, ScaledUnit::Point).unwrap()),
738 integer_pc: "6pc" => Ok(Scaled::new(6, Scaled::ZERO, ScaledUnit::Pica).unwrap()),
739 integer_in: "2in" => Ok(Scaled::new(2, Scaled::ZERO, ScaledUnit::Inch).unwrap()),
740 integer_bp: "72bp" => Ok(Scaled::new(72, Scaled::ZERO, ScaledUnit::BigPoint).unwrap()),
741 integer_cm: "10cm" => Ok(Scaled::new(10, Scaled::ZERO, ScaledUnit::Centimeter).unwrap()),
742 integer_mm: "25mm" => Ok(Scaled::new(25, Scaled::ZERO, ScaledUnit::Millimeter).unwrap()),
743 integer_dd: "10dd" => Ok(Scaled::new(10, Scaled::ZERO, ScaledUnit::DidotPoint).unwrap()),
744 integer_cc: "3cc" => Ok(Scaled::new(3, Scaled::ZERO, ScaledUnit::Cicero).unwrap()),
745 integer_sp: "65536sp" => Ok(Scaled(65536)),
746 fractional_pt: "72.27pt" => Ok(Scaled::new(72, Scaled::from_decimal_digits(&[2, 7]), ScaledUnit::Point).unwrap()),
748 fractional_in: "6.5in" => Ok(Scaled::new(6, Scaled::from_decimal_digits(&[5]), ScaledUnit::Inch).unwrap()),
749 zero_pt: "0pt" => Ok(Scaled::ZERO),
751 empty: "" => Err("invalid dimension \"\": expected <number><unit> (e.g. 100pt)".to_string()),
753 bad_unit: "10xx" => Err("invalid unit \"xx\" in dimension \"10xx\"".to_string()),
754 bad_number: "abpt" => Err("invalid number \"ab\" in dimension \"abpt\"".to_string()),
755 bad_fraction: "1.xpt" => Err("invalid fractional part \"x\" in dimension \"1.xpt\"".to_string()),
756 }
757
758 macro_rules! parse_no_units_tests {
759 ( $( $name:ident : $input:expr => $expected:expr, )* ) => {
760 $(
761 #[test]
762 fn $name() {
763 assert_eq!(Scaled::parse_no_units($input), $expected);
764 }
765 )*
766 };
767 }
768
769 parse_no_units_tests! {
770 no_units_one: "1.0" => Ok(Scaled::ONE),
771 no_units_zero: "0.0" => Ok(Scaled::ZERO),
772 no_units_negative: "-2.5" => Ok(-(Scaled::ONE * 5) / 2),
773 no_units_fraction: "0.27779" => Ok(Scaled::from_decimal_digits(&[2, 7, 7, 7, 9])),
774 no_units_overflow: "16384.0" => Err(OverflowError),
775 }
776
777 #[test]
778 fn parse_no_units_round_trips_display_no_units() {
779 for sc in [Scaled(1), Scaled(-1), Scaled(18205), Scaled::MAX_DIMEN] {
780 let printed = format!("{}", sc.display_no_units());
781 assert_eq!(Scaled::parse_no_units(&printed), Ok(sc));
782 }
783 }
784
785 #[test]
786 fn print_smallest_scaled() {
787 assert_eq!("-32768.0pt", format!("{}", Scaled(i32::MIN)));
788 }
789
790 #[test]
791 fn glue_order_ordering() {
792 assert!(GlueOrder::Normal < GlueOrder::Fil);
793 assert!(GlueOrder::Fil < GlueOrder::Fill);
794 assert!(GlueOrder::Fill < GlueOrder::Filll);
795 }
796}