-
Notifications
You must be signed in to change notification settings - Fork 61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement FromStr
method for Rgb<S, u8>
#157
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for doing this! There are just a few points that will need to be changes, primarily to maintain the #[no_std]
support, but also a couple of other details.
palette/src/rgb/rgb.rs
Outdated
@@ -2,6 +2,7 @@ use core::any::TypeId; | |||
use core::fmt; | |||
use core::marker::PhantomData; | |||
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; | |||
use std::str::FromStr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This need to be changed to get it from core
instead, for the #[no_std]
support to work.
use std::str::FromStr; | |
use core::str::FromStr; |
palette/src/rgb/rgb.rs
Outdated
@@ -953,14 +954,50 @@ where | |||
} | |||
} | |||
|
|||
impl FromStr for Rgb { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While this may be the more convenient option for many cases, I would still prefer to implement it for Rgb<Srgb, u8>
. I think that's less surprising than only having it for f32
. Ideally both would be supported, but then what about if it's a u16
hex string? Or even larger? So, in the end I think it's better to start small, as you have, but for Rgb<Srgb, u8>
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thinking some more about this, I don't think there's any reason to limit it to only Srgb
.
impl FromStr for Rgb { | |
impl<S: RgbStandard> FromStr for Rgb<S, u8> { |
It would also be great to have one for Alpha<Rgb<S, u8>>
.
palette/src/rgb/rgb.rs
Outdated
@@ -953,14 +954,50 @@ where | |||
} | |||
} | |||
|
|||
impl FromStr for Rgb { | |||
type Err = Box<dyn std::error::Error>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will have to change to something that isn't Box
ed, due to the #[no_std]
support requirement. A simple error type like
enum FromHexError {
ParseIntError(ParseIntError),
HexFormatError(&'static str), // Like "invalid hex code length" or "unexpected hex code prefix"
}
with all the impls it would need, would do the trick.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I struggle with this. Sorry, I am fairly new to rust, but there is no Error type in core only in std.
Do you have a suggestion how to do this ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, ok. No worries! :) You are right, it seems like the Error
trait is only in std
. In that case we will have to make use of conditional compilation if we want to use it (it's good practice to implement Error
, so we should). #[no_std]
is a particularly prickly feature. If we use std
anywhere, unconditionally, it's all out the window, and it's hard to notice unless it's used on a platform that doesn't support the std
library. I have set up a CI test to detect it, and that's what made this PR fail the tests.
For this case we have to give up the convenience of having the boxed trait in either case, since Box
is also not available, so the first step would be to add an enum like the one I suggested and change this line like this:
type Err = Box<dyn std::error::Error>; | |
type Err = FromHexError; |
That way, the parsing will work both with and without std
.
Then the FromHexError
type will need some traits (I would look at ParseIntError
for inspiration), including Error
. That's where we will have to check if the library user is allowing the std
library:
#[cfg(feature = "std")] // Checks if the "std" feature from Cargo.toml is enabled
impl std::error::Error for FromHexError {
// `std` is safe to use in this `impl` item, because of the `cfg` attribute.
// It will not be included at all if the "std" feature is disabled.
//
// ...
}
The same goes for any other trait that is not in core
.
palette/src/rgb/rgb.rs
Outdated
impl FromStr for Rgb { | ||
type Err = Box<dyn std::error::Error>; | ||
|
||
// parses a color hex code of format '#ff00bb' or '#abc' into a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It mentions "#" being part of the format, but never checks that it's there. Better to be strict and relax the rules later, rather than the opposite. Besides, it would also be technically possible to support strings without the "#". Maybe that should be added too?
Also, capital "P" in "parses". 🙂
awesome, thanks.
…On Sun, 8 Dec 2019 at 16:07, Erik Hedvall ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In palette/src/rgb/rgb.rs
<#157 (comment)>:
> @@ -953,14 +954,50 @@ where
}
}
+impl FromStr for Rgb {
+ type Err = Box<dyn std::error::Error>;
Ah, ok. No worries! :) You are right, it seems like the Error trait is
only in std. In that case we will have to make use of conditional
compilation if we want to use it (it's good practice to implement Error,
so we should). #[no_std] is a particularly prickly feature. If we use std
anywhere, unconditionally, it's all out the window, and it's hard to notice
unless it's used on a platform that doesn't support the std library. I
have set up a CI test to detect it, and that's what made this PR fail the
tests.
For this case we have to give up the convenience of having the boxed trait
in either case, since Box is also not available, so the first step would
be to add an enum like the one I suggested and change this line like this:
⬇️ Suggested change
- type Err = Box<dyn std::error::Error>;
+ type Err = FromHexError;
That way, the parsing will work both with and without std.
Then the FromHexError type will need some traits (I would look at
ParseIntError for inspiration), including Error. That's where we will
have to check if the library user is allowing the std library:
#[cfg(feature = "std")] // Checks if the "std" feature from Cargo.toml is enabled
impl std::error::Error for FromHexError {
// `std` is safe to use in this `impl` item, because of the `cfg` attribute.
// It will not be included at all if the "std" feature is disabled.
//
// ...
}
The same goes for any other trait that is not in core.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#157?email_source=notifications&email_token=AARK7OUQWK266FL355XDTITQXULUTA5CNFSM4JTGHB6KYY3PNVWWK3TUL52HS4DFWFIHK3DMKJSXC5LFON2FEZLWNFSXPKTDN5WW2ZLOORPWSZGOCOLE4AY#discussion_r355196778>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AARK7OXGSQFVW2DIBJKK6WLQXULUTANCNFSM4JTGHB6A>
.
|
palette/src/rgb/rgb.rs
Outdated
fn from_str(hex_code: &str) -> Result<Self, Self::Err> { | ||
match hex_code.len() { | ||
3 | 4 | 6 | 7 => { | ||
let (red, green, blue, factor) = if hex_code.len() == 3 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm just stopping by to see how it's going. Looks promising! I would just recommend to either drop this if-else chain and only use the match, or the other way around. Both would work. As it is now, you are checking the length twice, at least. 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An additional idea, to halve the amount of cases, is to check for the existence of #
at the beginning first. If it's there, you slice it away. That way, you are down to only two possible lengths when parsing the components.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I've done it this way. (December is a really busy month, :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, it is. But don't feel like you have to rush it or anything. :)
I think this looks really good! The only addition I think would be good to have would be to implement |
palette/src/rgb/rgb.rs
Outdated
write!(f, "ParseIntError: {}", e) | ||
} | ||
FromHexError::HexFormatError(s) => { | ||
write!(f, "HexFormatError: {}, please use format '#fff', 'fff', '#ffffff' or\ | ||
'ffffff'.", s) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be better to skip the ParseIntError:
and HexFormatError:
prefixes. I don't think they will be that interesting to someone who would read the error message, to be honest. They just want to know what went wrong and how to fix it. 🙂
This looks really nice! Well done! There's just that detail with the error messages. Also, I think the common convention in general is to just have a plain sentence without an initial capital letter, so there's that too. |
Ok, done, and a happy new year to you 🍾 |
Thanks and happy new year to you too! Oh, I forgot, you may want to squash those commits. Just to keep the history a bit shorter. |
Sorry, I didn't see the notification for the squash. It must have gotten lost somewhere... Thanks you! bors r+ |
Build succeeded |
FromStr
method for Srgb<f32>
FromStr
method for Srgb<f32>
FromStr
method for Rgb<S, u8>
This enables converting hex colors like '#00ddff' or '#fff' to Rgb.
this closes #148.