Hey,
Is there any way to create a macro that allows a Some<T>
or T
as input?
It’s for creating a Span
struct that I’m using:
struct Span {
line: usize,
column: usize,
file_path: Option<String>,
}
…and I have the following macro:
macro_rules! span {
($line:expr, $column:expr) => {
Span {
line: $line,
column: $column
file_path: None,
}
};
($line:expr, $column:expr, $file_path: expr) => {
Span {
line: $line,
column: $column
file_path: Some($file_path.to_string()),
}
};
}
…which allows me to do this:
let foo = span!(1, 1);
let bar = span!(1, 1, "file.txt");
However, sometimes I don’t want to pass in the file path directly but through a variable that is Option<String>. To do this, I always have to match the variable:
let file_path = Some("file.txt");
let foo = match file_path {
Some(file_path) => span!(1, 1, file_path),
None => span!(1, 1),
}
Is there a way which allows me to directly use span!(1, 1, file_path)
where file_path
could be "file.txt"
, Some("file.txt")
or None
?
Thanks in advance!
Option<T>
has aFrom<T>
implementation that lets you writeOption::from($file_path).map(|path| path.to_string())
to accept both cases in the same expression.https://doc.rust-lang.org/std/option/enum.Option.html#impl-From<T>-for-Option<T>
This does not work, as rust cannot infer the type of
path
A generic impl is impossible.
Imagine you want to turn a
Into<String>
toSome(val.into())
andOption<Into<String>>
toval.map(Into::into)
.Now, what if there is a type
T
whereimpl From <Option<T>> for String
is implemented?
Then we would have a conflict.If you only need this for
&str
andString
, then you can add a wrapper typeOptionStringWrapper(Option<String>)
and implementFrom<T> for OptionStringWrapper
for all concrete type cases you want to support, and go from there.Right, there may be too many unknowns involved. 🤔
deleted by creator
Why not add a
new()
function that does the same? Macro seems unneccessaryIt’s surprisingly simple: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=f176852c61dcf0c3382f0ac97c26de03 As a side node, asking for a value, and then immediately calling
to_string
on it seems kinda hiding the allocation. I’d suggest let the user callto_string
on it themselves.(e) Changed it a bit to account for passing
None
as the third argument.You might be okay with this:
macro_rules! span { ($line:expr, $column:expr) => { Span { line: $line, column: $column, file_path: None, } }; ($line:expr, $column:expr, $file_path:literal) => { Span { line: $line, column: $column, file_path: Some($file_path.to_string()), } }; ($line:expr, $column:expr, $file_path:expr) => { Span { line: $line, column: $column, file_path: $file_path, } }; }
However, sometimes I don’t want to pass in the file path directly but through a variable that is Option<String>.
Essentially I took this to mean
str
literals will be auto wrapped inSome
, but anything else is expected to beOption<String>