Skip to content

feat: external from_hex function#212

Closed
l0uisgrange wants to merge 5 commits into
linebender:mainfrom
l0uisgrange:hex-color
Closed

feat: external from_hex function#212
l0uisgrange wants to merge 5 commits into
linebender:mainfrom
l0uisgrange:hex-color

Conversation

@l0uisgrange

Copy link
Copy Markdown
Contributor

This PR adds a new Color function from_hex in addition to from_rgb8 and from_rgba8.

I'm not sure about the name, since it does more than just hex, so maybe from_css?

@waywardmonkeys

Copy link
Copy Markdown
Collaborator

This is handled by parse_color and parse_color_prefix, no?

@l0uisgrange

l0uisgrange commented Apr 29, 2026

Copy link
Copy Markdown
Contributor Author

Yes, that's correct.
Here the only goal is to be consistent with from_rgb8. Using parse_color directly is possible but the from_hex (or from_css) just provides a clean shortcut (uses the function behind anyway).
Also, parse_color is difficult to find, I wouldn't have found it without Xilem's team help, I thought the only possible color declaration was rgb8...

@DJMcNab DJMcNab left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Welcome! I really appreciate the spirit of coming to improve infrastructure directly, and wish more contributors would do so!

Unfortunately, we can't land this PR as-is, due to the numerous issues with boundary conditions here.
I have a few thoughts:

  1. We should probably make it easier to transition a DynamicColor to an AlphaColor (edit: This is DynamicColor::to_alpha_color)
  2. I believe that an sRGB-only from_hex function could be valuable, if (and possibly iff) we can make it const, and the input string gets a colour picker in vscode.
  3. Our documentation about how to create a colour is lacking. I believe the correct place for that would actually be in Peniko, although adding doc examples to the colour types wouldn't be amiss.

Practically, the way forward I'd suggest for this PR is either of the following:

  1. add a const fn from_hex which does the right thing, iff our MSRV permits it. The reason for that function existing would be being const.
  2. adding an example to any non-empty subset of DynamicColor, AlphaColor, OpaqueColor and PremulColor. For AlphaColor, we should also mention the css module, and for DynamicColor we should mention the From implementation.

If you want to do both, the latter would ideally be a separate PR to make review easier.

Comment thread color/src/lib.rs Outdated
Comment thread color/src/lib.rs Outdated
Comment thread color/src/lib.rs Outdated
Comment thread color/src/lib.rs Outdated
@waywardmonkeys

Copy link
Copy Markdown
Collaborator

I'd be more inclined to say we should impl FromStr and then parse would work, which is the most idiomatic way of handling this.

@waywardmonkeys

Copy link
Copy Markdown
Collaborator

Oh! We already do. I guess this really is a documentation thing then.

@l0uisgrange

l0uisgrange commented Apr 30, 2026

Copy link
Copy Markdown
Contributor Author

It is not possible to produce a const function since parse_color is not const. Why do you need it to be const?
If that's breaking for you, I understand.
It is more a documentation issue then. I think we can close this PR.

@DJMcNab

DJMcNab commented Apr 30, 2026

Copy link
Copy Markdown
Member

I think that a const fn from_hex could be valuable, even if we don't have a full const parsing of colours in arbitrary colour spaces. That would be a custom const function based on the pre-existing get_4bit_hex_channels, which is already const. The reason that would be useful is for defining custom colours, e.g. const MY_COLOR: Color = Color::from_hex("#abcdef").

A function called from_hex definitely shouldn't accept inputs of the form 'rgb(10, 10, 10)' or w/e.

I do think that improved documentation here would still be valuable.

@l0uisgrange

l0uisgrange commented May 1, 2026

Copy link
Copy Markdown
Contributor Author

I've used get_4bit_hex_channels, and it is better. I am really happy with the current solution if you are ready to merge 😇

@l0uisgrange l0uisgrange requested a review from DJMcNab May 1, 2026 11:09

@DJMcNab DJMcNab left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for taking on the review feedback. This is so much better ❤️

I probably won't get to this until next week. A couple of thoughts:

  1. This should handle a leading #. I think having it be optional would be fine.
  2. I would lean towards giving a parse error if 4 or 8 channels are specified in OpaqueColor::from_hex (i.e. an alpha was provided for an opaque colour.
  3. we should have a handful of simple tests of this functionality.
  4. we should validate that this works In a const context, including unwrapping being ergonomic. If we can't unwrap (which I think we probably can't...), then I think it would be worth panicking on failure instead
  5. the docs should be expanded slightly.

Of these, 1 and 3 would block this landing. 2 is a matter of taste, and I'm happy for this to land without it. 4 is important, but could be deferred, so long as we were careful to resolve it before a release. I'm happy to complete 5 myself just before merging.

Comment thread color/src/lib.rs
Comment on lines +194 to +195
/// Create a color from a hexadecimal value.
pub const fn from_hex(hex: &str) -> Result<Self, ParseError> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation should at the very least:

  • Point to parse_color and explain the differences with it.
  • Include one doctest showing how to use the function.

@DJMcNab DJMcNab closed this May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants