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

Code before:
}

cast! {
    OuterVAlignment,
    self => VAlignment::from(self).into_value(),
    align: Alignment => match align {
        Alignment::V(VAlignment::Top) => Self::Top,
        Alignment::V(VAlignment::Bottom) => Self::Bottom,
        v => bail!("expected `top` or `bottom`, found {}", v.repr()),
    }
}

/// An internal representation that combines horizontal or vertical alignments. The
/// allowed alignment positions are designated by the type parameter `H` and `V`.
///
/// This is not user-visible, but an internal type to impose type safety. For example,
/// `SpecificAlignment<HAlignment, OuterVAlignment>` does not allow vertical alignment
/// position "center", because `V = OuterVAlignment` doesn't have it.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum SpecificAlignment<H, V>
where
    H: Into<HAlignment> + Copy,
    V: Into<VAlignment> + Copy,
    HAlignment: Into<H>,
    VAlignment: Into<V>,
{
    H(H),
    V(V),
    Both(H, V),
}

impl<H, V> SpecificAlignment<H, V>
where
    H: Into<HAlignment> + Copy,
    V: Into<VAlignment> + Copy,
    HAlignment: Into<H>,
    VAlignment: Into<V>,
{
    /// The horizontal component.
    pub const fn x(self) -> Option<H> {
        match self {
            Self::H(x) | Self::Both(x, _) => Some(x),
            Self::V(_) => None,
        }
    }

    /// The vertical component.
    pub const fn y(self) -> Option<V> {
        match self {
            Self::V(y) | Self::Both(_, y) => Some(y),
            Self::H(_) => None,

Review comment (bug):
We don't need any of those traits when constructing the enum (perhaps the Copy ones might be needed though, but I think the #[derive(Copy)] macro already takes care of this, and only implements Copy if both parameters are Copy; if it fails to compile, you can force it with `<H: Copy, V: Copy>` instead).

```suggestion
pub enum SpecificAlignment<H, V> {
```


Code after:
}

impl OuterVAlignment {
    /// Resolve the axis alignment based on the vertical direction.
    pub const fn fix(self) -> FixedAlignment {
        match self {
            Self::Top => FixedAlignment::Start,
            Self::Bottom => FixedAlignment::End,
        }
    }
}

impl From<OuterVAlignment> for VAlignment {
    fn from(value: OuterVAlignment) -> Self {
        match value {
            OuterVAlignment::Top => Self::Top,
            OuterVAlignment::Bottom => Self::Bottom,
        }
    }
}

impl TryFrom<Alignment> for OuterVAlignment {
    type Error = EcoString;

    fn try_from(value: Alignment) -> StrResult<Self> {
        match value {
            Alignment::V(VAlignment::Top) => Ok(Self::Top),
            Alignment::V(VAlignment::Bottom) => Ok(Self::Bottom),
            v => bail!("expected `top` or `bottom`, found {}", v.repr()),
        }
    }
}

cast! {
    OuterVAlignment,
    self => VAlignment::from(self).into_value(),
    align: Alignment => Self::try_from(align)?,
}

/// An internal representation that combines horizontal or vertical alignments. The
/// allowed alignment positions are designated by the type parameter `H` and `V`.
///
/// This is not user-visible, but an internal type to impose type safety. For example,
/// `SpecificAlignment<HAlignment, OuterVAlignment>` does not allow vertical alignment
/// position "center", because `V = OuterVAlignment` doesn't have it.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum SpecificAlignment<H, V> {
    H(H),
    V(V),
    Both(H, V),
}