Get a Palette colour as a command-line argument with Clap
Wrapping a Palette:Srgb
in a struct and implementing FromStr
for the struct allows you to take hexadecimal colours as command-line inputs.
I was writing a command-line tool using the Clap crate, and I wanted to be able to pass a hexadecimal string as an argument and have it be parsed as a Palette colour. Some of this work might be reusable if I ever want to parse different types with Clap.
These examples use Clap 4.5.4 and Palette 0.7.6.
Parsing a string argument as a Rust type
Clap uses the ValueParser
trait to convert a raw argument value into a typed value. It has built-in implementations of this trait for certain common types.
For example, here’s a simple program that takes a single argument which is validated as and converted to a usize
:
use clap::{Arg, Command};
fn main() {
let arg = Arg::new("count")
.value_parser(clap::value_parser!(usize));
let m = Command::new("My Program")
.arg(arg)
.get_matches();
let count: &usize = m.get_one::<usize>("count").unwrap();
println!("count = {}", count);
}
// $ cargo run 42
// count = 42
Parsing a string argument as a custom type
Initially I was looking at how to implement ValueParser
for the Srgb
type, but then I came across a Reddit post by Kbknapp that suggested instead implementing FromStr
.
Initially I considered writing my own wrapper type and implementing FromStr
myself, but then I remember that I can use from_str()
to parse hex codes as Palette colours, which means it already implements FromStr
– I get the behaviour I want “for free”:
use clap::{Arg, Command};
use palette::Srgb;
fn main() {
let arg = Arg::new("wrapper")
.value_parser(clap::value_parser!(Srgb<u8>));
let m = Command::new("My Program").arg(arg).get_matches();
let wrapper: &Srgb<u8> = m.get_one::<Srgb<u8>>("wrapper").unwrap();
println!("color = {:?}", wrapper);
}
// $ cargo run '#d01c11'
// color = Rgb { red: 208, green: 28, blue: 17, … }
Initially I thought I’d have to write my own wrapper struct and implement FromStr
on it, but then I realised I can just use the implementation of FromStr
that’s provided by Palette.
You can’t implement traits for types defined outside the current crate, so a wrapper struct would be useful if I ever want to do this with a type that doesn’t already implement FromStr
.