-
Notifications
You must be signed in to change notification settings - Fork 177
Expand file tree
/
Copy pathshared.rs
More file actions
58 lines (53 loc) · 2.33 KB
/
Copy pathshared.rs
File metadata and controls
58 lines (53 loc) · 2.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
use heck::ToSnakeCase;
use proc_macro2::TokenStream;
use quote::quote;
use std::borrow::Cow;
/// Convert to snake_case while preserving leading underscores.
/// This is important for GraphQL fields like `_id` which should become `_id` not `id`.
pub(crate) fn to_snake_case_preserve_leading_underscores(s: &str) -> String {
let leading_underscores = s.chars().take_while(|&c| c == '_').count();
if leading_underscores == 0 {
s.to_snake_case()
} else {
let prefix = "_".repeat(leading_underscores);
let rest = &s[leading_underscores..];
format!("{}{}", prefix, rest.to_snake_case())
}
}
// List of keywords based on https://doc.rust-lang.org/reference/keywords.html
// code snippet: `[...new Set($$("code.hljs").map(x => x.textContent).filter(x => x.match(/^[_a-z0-9]+$/i)))].sort()`
const RUST_KEYWORDS: &[&str] = &[
"Self", "abstract", "as", "async", "await", "become", "box", "break", "const", "continue",
"crate", "do", "dyn", "else", "enum", "extern", "false", "final", "fn", "for", "if", "impl",
"in", "let", "loop", "macro", "match", "mod", "move", "mut", "override", "priv", "pub", "ref",
"return", "self", "static", "struct", "super", "trait", "true", "try", "type", "typeof",
"union", "unsafe", "unsized", "use", "virtual", "where", "while", "yield",
];
pub(crate) fn keyword_replace<'a>(needle: impl Into<Cow<'a, str>>) -> Cow<'a, str> {
let needle = needle.into();
match RUST_KEYWORDS.binary_search(&needle.as_ref()) {
Ok(index) => [RUST_KEYWORDS[index], "_"].concat().into(),
Err(_) => needle,
}
}
/// Given the GraphQL schema name for an object/interface/input object field and
/// the equivalent rust name, produces a serde annotation to map them during
/// (de)serialization if it is necessary, otherwise an empty TokenStream.
pub(crate) fn field_rename_annotation(graphql_name: &str, rust_name: &str) -> Option<TokenStream> {
if graphql_name != rust_name {
Some(quote!(#[serde(rename = #graphql_name)]))
} else {
None
}
}
#[cfg(test)]
mod tests {
#[test]
fn keyword_replace_works() {
use super::keyword_replace;
assert_eq!("fora", keyword_replace("fora"));
assert_eq!("in_", keyword_replace("in"));
assert_eq!("fn_", keyword_replace("fn"));
assert_eq!("struct_", keyword_replace("struct"));
}
}