Repository: typst/typst
File: crates/typst/src/layout/length.rs (Rust)

Code before:
            Some(self.em / other.em)
        } else if self.em.is_zero() && other.em.is_zero() {
            Some(self.abs / other.abs)
        } else {
            None
        }
    }

    /// Convert to an absolute length at the given font size.
    pub fn at(self, font_size: Abs) -> Abs {
        self.abs + self.em.at(font_size)
    }

    /// Fails with an error if the length has a non-zero font-relative part.
    fn ensure_that_em_is_zero(&self, span: Span, unit: &str) -> SourceResult<()> {
        if self.em == Em::zero() {
            return Ok(());
        }

        bail!(
            span,
            "cannot convert a length with non-zero em units (`{}`) to {unit}",
            self.repr();
            hint: "use `length.abs.{unit}()` instead to ignore its em component";
            hint: "or use `length.to-absolute()` to resolve its em component \
                   (requires a context)"
        )
    }
}

#[scope]
impl Length {
    /// Converts this length to points.
    ///
    /// Fails with an error if this length has non-zero `em` units (such as
    /// `5em + 2pt` instead of just `2pt`). Use the `abs` field (such as in
    /// `(5em + 2pt).abs.pt()`) to ignore the `em` component of the length (thus
    /// converting only its absolute component).
    #[func(name = "pt", title = "Points")]
    pub fn to_pt(&self, span: Span) -> SourceResult<f64> {
        self.ensure_that_em_is_zero(span, "pt")?;
        Ok(self.abs.to_pt())
    }

    /// Converts this length to millimeters.
    ///
    /// Fails with an error if this length has non-zero `em` units. See the
    /// [`pt`]($length.pt) method for more details.
    #[func(name = "mm", title = "Millimeters")]
    pub fn to_mm(&self, span: Span) -> SourceResult<f64> {
        self.ensure_that_em_is_zero(span, "mm")?;

Review comment (suggestion):
```suggestion
                   (requires context)"
```
maybe we should also flip the order of the hints? ignoring is generally not as advisable.

Code after:
            Some(self.em / other.em)
        } else if self.em.is_zero() && other.em.is_zero() {
            Some(self.abs / other.abs)
        } else {
            None
        }
    }

    /// Convert to an absolute length at the given font size.
    pub fn at(self, font_size: Abs) -> Abs {
        self.abs + self.em.at(font_size)
    }

    /// Fails with an error if the length has a non-zero font-relative part.
    fn ensure_that_em_is_zero(&self, span: Span, unit: &str) -> SourceResult<()> {
        if self.em == Em::zero() {
            return Ok(());
        }

        bail!(
            span,
            "cannot convert a length with non-zero em units (`{}`) to {unit}",
            self.repr();
            hint: "use `length.to-absolute()` to resolve its em component \
                   (requires context)";
            hint: "or use `length.abs.{unit}()` instead to ignore its em component"
        )
    }
}

#[scope]
impl Length {
    /// Converts this length to points.
    ///
    /// Fails with an error if this length has non-zero `em` units (such as
    /// `5em + 2pt` instead of just `2pt`). Use the `abs` field (such as in
    /// `(5em + 2pt).abs.pt()`) to ignore the `em` component of the length (thus
    /// converting only its absolute component).
    #[func(name = "pt", title = "Points")]
    pub fn to_pt(&self, span: Span) -> SourceResult<f64> {
        self.ensure_that_em_is_zero(span, "pt")?;
        Ok(self.abs.to_pt())
    }

    /// Converts this length to millimeters.
    ///
    /// Fails with an error if this length has non-zero `em` units. See the
    /// [`pt`]($length.pt) method for more details.
    #[func(name = "mm", title = "Millimeters")]
    pub fn to_mm(&self, span: Span) -> SourceResult<f64> {
        self.ensure_that_em_is_zero(span, "mm")?;