Skip to content

Commit

Permalink
feat: Add a TryFrom<&str> implementation for enumerations
Browse files Browse the repository at this point in the history
Closes #223

cc @krobelus
  • Loading branch information
Marwes committed Nov 21, 2021
1 parent 4be8da3 commit 19b85cf
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 3 deletions.
10 changes: 10 additions & 0 deletions src/completion.rs
Expand Up @@ -587,4 +587,14 @@ mod tests {
"TypeParameter"
);
}

#[test]
fn test_try_from_enum() {
use std::convert::TryInto;
assert_eq!("Text".try_into(), Ok(CompletionItemKind::TEXT));
assert_eq!(
"TypeParameter".try_into(),
Ok(CompletionItemKind::TYPE_PARAMETER)
);
}
}
44 changes: 41 additions & 3 deletions src/lib.rs
Expand Up @@ -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;

Expand All @@ -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();
Expand All @@ -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])*
Expand All @@ -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 {
$(
_ if { let (buf, len) = crate::fmt_pascal_case_const(stringify!($name)); &buf[..len] == value.as_bytes() } => Ok(Self::$name),
)*
_ => Err("unknown enum variant"),
}
}
}

}
}

Expand Down

0 comments on commit 19b85cf

Please sign in to comment.