Thanks for all help!!
I'm novice to macros and found even different from C.
trait PrometheusAnnotations
cannot find the implementation in into_map_derive.
How can I convert Stats to String using trait prometheus_annotations
?
main.rs
use into_map_derive::PrometheusAnnotations;
#[derive(PrometheusAnnotations)]
pub struct Stats {
/// auth label
#[metric_type("counter")]
//#[serde(foo)]
auth_errors: u64,
}
fn main() {
let mut out = "".to_string();
let a = Stats {
auth_errors: 4,
};
out.push_str(
a
);
Cargo.toml
[package]
name = "into_map_demo"
version = "0.1.0"
edition = "2018"
[dependencies]
into_map = { path = "into_map" }
into_map_derive = { path = "into_map_derive" }
into_map\src\lib.rs
pub trait PrometheusAnnotations { //0 Implementations
fn prometheus_annotations() -> &'static str;
}
into_map/Cargo.toml
[package]
name = "into_map"
version = "0.1.0"
edition = "2018"
into_map_derive/src/lib.rs
#![allow(nonstandard_style, unused_imports)]
use ::proc_macro::{
TokenStream,
};
use ::proc_macro2::{
Span,
TokenStream as TokenStream2,
};
use ::quote::{
format_ident,
quote, quote_spanned,
ToTokens,
};
use ::syn::{*,
parse::{Parse, Parser, ParseStream},
punctuated::Punctuated,
spanned::Spanned,
Result,
};
/// The `= "…"` in a `#[doc = "…"]` attribute,
/// _i.e._, the `…` in `/// …`.
struct DocString(String);
impl Parse for DocString {
fn parse (input: ParseStream<'_>)
-> Result<DocString>
{
let _: Token![=] = input.parse()?;
let line: LitStr = input.parse()?;
Ok(Self(line.value()))
}
}
#[proc_macro_derive(PrometheusAnnotations, attributes(metric_type))]
pub fn test (input: TokenStream)
-> TokenStream
{
prometheus_annotations(input.into())
.unwrap_or_else(|err| err.to_compile_error())
.into()
}
fn prometheus_annotations (
input: TokenStream2,
) -> Result<TokenStream2>
{
use ::core::fmt::Write;
let input: ItemStruct = parse2(input)?;
let mut prometheus_string = String::new();
for field in &input.fields {
let attrs = &field.attrs;
let doc_strings =
attrs.iter().filter_map(|attr| bool::then(
attr.path.is_ident("doc"),
|| parse2::<DocString>(attr.tokens.clone()).ok(),
).flatten());
doc_strings.for_each(|DocString(doc_string)| {
writeln!(prometheus_string, "HELP {}", doc_string).unwrap();
//prometheus_string = format!("HELP {}", doc_string);
//writeln!(prometheus_string, "HELP auth label").unwrap();
});
let mut metric_types = attrs.iter().filter(|attr| attr.path.is_ident("metric_type"));
match (metric_types.next(), metric_types.next()) {
| (Some(attr), None) => {
let metric_type: String = attr.parse_args::<LitStr>()?.value();
//writeln!(prometheus_string, "TYPE {metric_type}").unwrap();
prometheus_string = format!("TYPE {}", metric_type);
prometheus_string += "\n";
//writeln!(prometheus_string, "TYPE counter").unwrap();
},
| (None, None) => {
// No `metric_type` provided: error or ignore?
//…
},
| (Some(_), Some(duplicate)) => return Err(Error::new_spanned(
// code to highlight / blame
duplicate,
// error message
"Duplicate `metric_type` attribute",
)),
(None, Some(_)) => todo!(),
};
if let Some(ref field_name) = field.ident {
//writeln!(prometheus_string, "{field_name} 4").unwrap();
prometheus_string = format!("{} ", field_name);
prometheus_string += "\n";
//writeln!(prometheus_string, "auth_errors 4").unwrap();
} else {
return Err(Error::new(Span::call_site(), "expected a braced struct"));
}
}
let (intro_generics, fwd_generics, where_clause) = input.generics.split_for_impl();
let StructName @ _ = &input.ident;
let pub_ = &input.vis;
Ok(quote!(
impl #intro_generics
// ::my_crate::PrometheusAnnotations for
#StructName #fwd_generics
#where_clause
{
#pub_ // <- remove if implementing trait rather than inherent function.
fn prometheus_annotations ()
-> &'static ::core::primitive::str
{
#prometheus_string
}
}
))
}
into_map_derive/Cargo.toml
[package]
name = "into_map_derive"
version = "0.1.0"
edition = "2018"
[lib]
proc-macro = true
[dependencies]
proc-macro2.version = "1.0.37"
quote.version = "1.0.17"
syn.version = "1.0.91"
syn.features = ["full"]
into_map = { path="../into_map" }
$ cargo run
error[E0308]: mismatched types
--> src\main.rs:43:9
|
43 | a
| ^ expected `&str`, found struct `Stats`
We call function defined inside trait on structure, but pub trait PrometheusAnnotations
shows 0 implementation.
out.push_str(
a.prometheus_annotations() //no method named `prometheus_annotations` found for struct `Stats`
);