Why not add a new()
function that does the same? Macro seems unneccessary
Rust
Welcome to the Rust community! This is a place to discuss about the Rust programming language.
Wormhole
Credits
- The icon is a modified version of the official rust logo (changing the colors to a gradient and black background)
Option<T>
has a From<T>
implementation that lets you write Option::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%3CT%3E-for-Option%3CT%3E
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>
to Some(val.into())
and Option<Into<String>>
to val.map(Into::into)
.
Now, what if there is a type T
where impl From <Option<T>> for String
is implemented?
Then we would have a conflict.
If you only need this for &str
and String
, then you can add a wrapper type OptionStringWrapper(Option<String>)
and implement From<T> for OptionStringWrapper
for all concrete type cases you want to support, and go from there.
Right, there may be too many unknowns involved. 🤔
It'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 call to_string
on it themselves.
(e) Changed it a bit to account for passing None
as the third argument.
I think the point is that the variable itself is an Option. Your example only works for literal Option (although the value inside the optional itself might not be a literal).
One option to OP's problem is to use an auxiliary trait implemented on both string and Option
One option to OP’s problem is to use an auxiliary trait implemented on both string and Option
This looks something like the following
~~* Two of your macro rules are not used 😉 (expand to see which ones).~~
- This doesn't support
Option<&str>
. If it did, we would lose literalNone
support 😉
Two of your macro rules are not used 😉 (expand to see which ones).
The macro rules are all used. (Macros are matched from top to bottom by the declared match types. The ident/expressions can't match until after the more text based Option matching.)
let _foo = Span { line: 1, column: 1, file_path: None };
let _bar = Span { line: 1, column: 1, file_path: "file.txt".upgrade() };
let _baz = Span { line: 1, column: 1, file_path: Some("file.txt".to_string()) };
let _baz = Span { line: 1, column: 1, file_path: None };
let _baz = Span { line: 1, column: 1, file_path: borrowed.upgrade() };
let _baz = Span { line: 1, column: 1, file_path: owned.upgrade() };
This doesn’t support Option<&str>. If it did, we would lose literal None support 😉
I didn't make Option<&str> an option because the struct is for type Option<String>
. It does support Option though.
impl OptionUpgrade for Option<String> {
fn upgrade(self) -> Option<String> {
self
}
}
It looks like the following, and uses the last match case.
let opt: Option<String> = Some("text".into());
let opt = span!(1, 1, opt);
With macro expansion
let opt: Option<String> = Some("text".into());
let opt = Span { line: 1, column: 1, file_path: opt.upgrade() };
There's not anything stopping it from supporting Option<&str> though. This would be the implementation
impl OptionUpgrade for Option<&str> {
fn upgrade(self) -> Option<String> {
self.map(|v| v.into())
}
}
The macro rules are all used.
Oops. I was looking at it wrong.
I didn’t make
Option<&str>
an option because the struct is for typeOption<String>
.
Re-read the end of OP's requirements.
I made an edit.
There's not anything stopping it from supporting Option<&str> though. This would be the implementation
impl OptionUpgrade for Option<&str> {
fn upgrade(self) -> Option<String> {
self.map(|v| v.into())
}
}
It's also possible to just make it generic over Option types
impl<A: ToString> OptionUpgrade for Option<A> {
fn upgrade(self) -> Option<String> {
self.map(|v| v.to_string())
}
}
Yes, but then the concrete type of None
literals becomes unknown, which is what I was trying to point out.
I had commented something similar to stating it was possible to pass the inference problem to the struct if the goal was to support more types, but I removed it because I didn't think my example was easy to understand when reading it later. I made a better example though