Skip to content

Commit

Permalink
Merge pull request #224 from gluon-lang/try_from_string
Browse files Browse the repository at this point in the history
feat: Add a TryFrom<&str> implementation for enumerations
  • Loading branch information
Marwes committed Feb 7, 2022
2 parents 4602610 + 7337535 commit d2d3c37
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 12 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)
);
}
}
65 changes: 53 additions & 12 deletions src/lib.rs
Expand Up @@ -15,20 +15,43 @@ 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;

use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use std::{collections::HashMap, fmt::Debug};

use serde::{de, de::Error as Error_, Deserialize, Serialize};
use serde_json::Value;
pub use url::Url;

use std::collections::HashMap;
// Large enough to contain any enumeration name defined in this crate
type PascalCaseBuf = [u8; 32];
const fn fmt_pascal_case_const(name: &str) -> (PascalCaseBuf, usize) {
let mut buf = [0; 32];
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;
}

use serde::de;
use serde::de::Error as Error_;
use serde_json::Value;
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('_') {
Expand All @@ -43,7 +66,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 +84,23 @@ 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 () {
$(
_ if {
const X: (crate::PascalCaseBuf, usize) = crate::fmt_pascal_case_const(stringify!($name));
let (buf, len) = X;
&buf[..len] == value.as_bytes()
} => Ok(Self::$name),
)*
_ => Err("unknown enum variant"),
}
}
}

}
}

Expand Down Expand Up @@ -668,10 +708,10 @@ pub struct ConfigurationItem {
}

mod url_map {
use super::*;

use std::fmt;

use super::*;

pub fn deserialize<'de, D>(
deserializer: D,
) -> Result<Option<HashMap<Url, Vec<TextEdit>>>, D::Error>
Expand Down Expand Up @@ -2415,9 +2455,10 @@ impl SymbolTag {

#[cfg(test)]
mod tests {
use super::*;
use serde::{Deserialize, Serialize};

use super::*;

pub(crate) fn test_serialization<SER>(ms: &SER, expected: &str)
where
SER: Serialize + for<'de> Deserialize<'de> + PartialEq + std::fmt::Debug,
Expand Down

0 comments on commit d2d3c37

Please sign in to comment.