Skip to content

Commit

Permalink
derive-text-encode: Handle keyword identifiers aka raw identifiers
Browse files Browse the repository at this point in the history
Field names like `r#type` are problematic as `r#` is not a valid
OpenMetrics label name but one needs to use keyword identifier syntax
(aka. raw identifiers) as `type` is a keyword.

Makes sure `r#type` is replaced by `type` in the OpenMetrics output.
  • Loading branch information
mxinden committed May 27, 2021
1 parent 3f05d29 commit 7d67fa7
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 1 deletion.
61 changes: 60 additions & 1 deletion derive-text-encode/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,20 @@ pub fn derive_encode(input: TokenStream) -> TokenStream {
.enumerate()
.map(|(i, f)| {
let ident = f.ident.unwrap();
let ident_string = KEYWORD_IDENTIFIERS
.iter()
.find(|pair| ident == pair.1)
.map(|pair| pair.0.to_string())
.unwrap_or_else(|| ident.to_string());

let maybe_comma = if i == 0 {
TokenStream2::default()
} else {
quote! { writer.write_all(b",")?; }
};
quote! {
#maybe_comma
writer.write_all(concat!(stringify!(#ident), "=\"").as_bytes())?;
writer.write_all(concat!(#ident_string, "=\"").as_bytes())?;
open_metrics_client::encoding::text::Encode::encode(&self.#ident, writer)?;
writer.write_all(b"\"")?;
}
Expand Down Expand Up @@ -66,3 +72,56 @@ pub fn derive_encode(input: TokenStream) -> TokenStream {
};
gen.into()
}

// Copied from https://github.com/djc/askama (MIT and APACHE licensed) and
// modified.
static KEYWORD_IDENTIFIERS: [(&str, &str); 48] = [
("as", "r#as"),
("break", "r#break"),
("const", "r#const"),
("continue", "r#continue"),
("crate", "r#crate"),
("else", "r#else"),
("enum", "r#enum"),
("extern", "r#extern"),
("false", "r#false"),
("fn", "r#fn"),
("for", "r#for"),
("if", "r#if"),
("impl", "r#impl"),
("in", "r#in"),
("let", "r#let"),
("loop", "r#loop"),
("match", "r#match"),
("mod", "r#mod"),
("move", "r#move"),
("mut", "r#mut"),
("pub", "r#pub"),
("ref", "r#ref"),
("return", "r#return"),
("static", "r#static"),
("struct", "r#struct"),
("trait", "r#trait"),
("true", "r#true"),
("type", "r#type"),
("unsafe", "r#unsafe"),
("use", "r#use"),
("where", "r#where"),
("while", "r#while"),
("async", "r#async"),
("await", "r#await"),
("dyn", "r#dyn"),
("abstract", "r#abstract"),
("become", "r#become"),
("box", "r#box"),
("do", "r#do"),
("final", "r#final"),
("macro", "r#macro"),
("override", "r#override"),
("priv", "r#priv"),
("typeof", "r#typeof"),
("unsized", "r#unsized"),
("virtual", "r#virtual"),
("yield", "r#yield"),
("try", "r#try"),
];
25 changes: 25 additions & 0 deletions derive-text-encode/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,28 @@ fn basic_flow() {
+ "# EOF\n";
assert_eq!(expected, String::from_utf8(buffer).unwrap());
}

#[test]
fn remap_keyword_identifiers() {
#[derive(Encode, Hash, Clone, Eq, PartialEq)]
struct Labels {
// `r#type` is problematic as `r#` is not a valid OpenMetrics label name
// but one needs to use keyword identifier syntax (aka. raw identifiers)
// as `type` is a keyword.
//
// Test makes sure `r#type` is replaced by `type` in the OpenMetrics
// output.
r#type: u64,
};

let labels = Labels { r#type: 42 };

let mut buffer = vec![];

labels.encode(&mut buffer);

assert_eq!(
"type=\"42\"".to_string(),
String::from_utf8(buffer).unwrap()
);
}

0 comments on commit 7d67fa7

Please sign in to comment.