Repository: typst/typst
File: crates/typst-pdf/src/color.rs (Rust)

Code before:
                ctx.content.set_stroke_color([r, g, b]);
            }
            Color::Rgb(_) => {
                ctx.resources.colors.mark_as_used(ColorSpace::Srgb);
                ctx.set_stroke_color_space(SRGB);

                let [r, g, b, _] = ColorSpace::Srgb.encode(*self);
                ctx.content.set_stroke_color([r, g, b]);
            }
            Color::Cmyk(_) => {
                ctx.reset_stroke_color_space();

                let [c, m, y, k] = ColorSpace::Cmyk.encode(*self);
                ctx.content.set_stroke_cmyk(c, m, y, k);
            }
        }
    }
}

/// Extra color space functions.
pub(super) trait ColorSpaceExt {
    /// Returns the range of the color space.
    fn range(self) -> &'static [f32];

    /// Converts a color to the color space.
    fn convert<U: QuantizedColor>(self, color: Color) -> SmallVec<[U; 4]>;
}

impl ColorSpaceExt for ColorSpace {
    fn range(self) -> &'static [f32] {
        match self {
            ColorSpace::Cmyk => &[0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0],
            ColorSpace::D65Gray => &[0.0, 1.0],
            _ => &[0.0, 1.0, 0.0, 1.0, 0.0, 1.0],
        }
    }

    fn convert<U: QuantizedColor>(self, color: Color) -> SmallVec<[U; 4]> {
        let components = self.encode(color);

        self.range()
            .chunks(2)
            .zip(components)
            .map(|(range, component)| U::quantize(component, [range[0], range[1]]))
            .collect()
    }
}

/// Quantizes a color component to a specific type.
pub(super) trait QuantizedColor {
    fn quantize(color: f32, range: [f32; 2]) -> Self;

Review comment (suggestion):
If the vector is always of length `< 4`, then `ArrayVec` is a bit better than `SmallVec`

Code after:
                ctx.content.set_stroke_color([r, g, b]);
            }
            Color::Rgb(_) => {
                ctx.resources.colors.mark_as_used(ColorSpace::Srgb);
                ctx.set_stroke_color_space(SRGB);

                let [r, g, b, _] = ColorSpace::Srgb.encode(*self);
                ctx.content.set_stroke_color([r, g, b]);
            }
            Color::Cmyk(_) => {
                ctx.reset_stroke_color_space();

                let [c, m, y, k] = ColorSpace::Cmyk.encode(*self);
                ctx.content.set_stroke_cmyk(c, m, y, k);
            }
        }
    }
}

/// Extra color space functions.
pub(super) trait ColorSpaceExt {
    /// Returns the range of the color space.
    fn range(self) -> &'static [f32];

    /// Converts a color to the color space.
    fn convert<U: QuantizedColor>(self, color: Color) -> ArrayVec<U, 4>;
}

impl ColorSpaceExt for ColorSpace {
    fn range(self) -> &'static [f32] {
        match self {
            ColorSpace::D65Gray => &[0.0, 1.0],
            ColorSpace::Oklab => &[0.0, 1.0, 0.0, 1.0, 0.0, 1.0],
            ColorSpace::Oklch => &[0.0, 1.0, 0.0, 1.0, 0.0, 1.0],
            ColorSpace::LinearRgb => &[0.0, 1.0, 0.0, 1.0, 0.0, 1.0],
            ColorSpace::Srgb => &[0.0, 1.0, 0.0, 1.0, 0.0, 1.0],
            ColorSpace::Cmyk => &[0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0],
            ColorSpace::Hsl => &[0.0, 1.0, 0.0, 1.0, 0.0, 1.0],
            ColorSpace::Hsv => &[0.0, 1.0, 0.0, 1.0, 0.0, 1.0],
        }
    }

    fn convert<U: QuantizedColor>(self, color: Color) -> ArrayVec<U, 4> {
        let components = self.encode(color);

        self.range()
            .chunks(2)
            .zip(components)
            .map(|(range, component)| U::quantize(component, [range[0], range[1]]))
            .collect()
    }