-
Notifications
You must be signed in to change notification settings - Fork 91
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
feat: Add a TryFrom<&str> implementation for enumerations #224
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,8 +15,7 @@ able to parse any URI, such as `urn:isbn:0451450523`. | |
|
||
*/ | ||
#![allow(non_upper_case_globals)] | ||
#![forbid(unsafe_code)] | ||
|
||
#[forbid(unsafe_code)] | ||
#[macro_use] | ||
extern crate bitflags; | ||
|
||
|
@@ -30,6 +29,32 @@ use serde::de; | |
use serde::de::Error as Error_; | ||
use serde_json::Value; | ||
|
||
const fn fmt_pascal_case_const(name: &str) -> ([u8; 128], usize) { | ||
let mut buf = [0; 128]; | ||
let mut buf_i = 0; | ||
let mut name_i = 0; | ||
let name = name.as_bytes(); | ||
while name_i < name.len() { | ||
let first = name[name_i]; | ||
name_i += 1; | ||
|
||
buf[buf_i] = first; | ||
buf_i += 1; | ||
|
||
while name_i < name.len() { | ||
let rest = name[name_i]; | ||
name_i += 1; | ||
if rest == b'_' { | ||
break; | ||
} | ||
|
||
buf[buf_i] = rest.to_ascii_lowercase(); | ||
buf_i += 1; | ||
} | ||
} | ||
(buf, buf_i) | ||
} | ||
|
||
fn fmt_pascal_case(f: &mut std::fmt::Formatter<'_>, name: &str) -> std::fmt::Result { | ||
for word in name.split('_') { | ||
let mut chars = word.chars(); | ||
|
@@ -43,7 +68,7 @@ fn fmt_pascal_case(f: &mut std::fmt::Formatter<'_>, name: &str) -> std::fmt::Res | |
} | ||
|
||
macro_rules! lsp_enum { | ||
(impl $typ: ty { $( $(#[$attr:meta])* pub const $name: ident : $enum_type: ty = $value: expr; )* }) => { | ||
(impl $typ: ident { $( $(#[$attr:meta])* pub const $name: ident : $enum_type: ty = $value: expr; )* }) => { | ||
impl $typ { | ||
$( | ||
$(#[$attr])* | ||
|
@@ -61,6 +86,19 @@ macro_rules! lsp_enum { | |
} | ||
} | ||
} | ||
|
||
impl std::convert::TryFrom<&str> for $typ { | ||
type Error = &'static str; | ||
fn try_from(value: &str) -> Result<Self, Self::Error> { | ||
match value { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess we can also write |
||
$( | ||
_ if { let (buf, len) = crate::fmt_pascal_case_const(stringify!($name)); &buf[..len] == value.as_bytes() } => Ok(Self::$name), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. great idea. The only weird thing is that when I change the max length from 128 to 5 we will error at runtime (not at compile time!) if the So we might save allocations but we still run the code at runtime and don't generate the neat match-statement a human would write, which is Anyway, that's not so important. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So at this point it seems better to write |
||
)* | ||
_ => Err("unknown enum variant"), | ||
} | ||
} | ||
} | ||
|
||
} | ||
} | ||
|
||
|
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.
not sure why, also the other
: ty
is still here