Skip to content

fix(derive-encode): Cumulative fixes #267

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `Family::get_or_create_owned` can access a metric in a labeled family. This
method avoids the risk of runtime deadlocks at the expense of creating an
owned type. See [PR 244].

[PR 244]: https://github.com/prometheus/client_rust/pull/244
[PR 257]: https://github.com/prometheus/client_rust/pull/257

### Changed

- `EncodeLabelSet::encode()` now accepts a mutable reference to its encoder parameter.
- Emit better compilation error message when deriving marcos `EncodeLabelSet` and `EncodeLabelValue`.
See [PR 267].

### Fixed

- Fixed an issue where the derive marcos `EncodeLabelSet` and `EncodeLabelValue` didn't work
when the `struct` has generic parameters (like `'a`).
See [PR 265].

- Fixed an issue where the derive macro `EncodeLabelSet` didn't work
when the `struct` has generic parameters (like `'a`).
See [PR 267].

[PR 265]: https://github.com/prometheus/client_rust/pull/265
[PR 267]: https://github.com/prometheus/client_rust/pull/266

## [0.23.1]

Expand Down
47 changes: 39 additions & 8 deletions derive-encode/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use quote::{quote, ToTokens};
use syn::DeriveInput;

/// Derive `prometheus_client::encoding::EncodeLabelSet`.
Expand Down Expand Up @@ -60,18 +60,41 @@ pub fn derive_encode_label_set(input: TokenStream) -> TokenStream {
})
.collect(),
syn::Fields::Unnamed(_) => {
panic!("Can not derive Encode for struct with unnamed fields.")
return syn::Error::new_spanned(
name,
"Can not derive `EncodeLabelSet` for struct with unnamed fields.",
)
.to_compile_error()
.to_token_stream()
.into();
}
syn::Fields::Unit => {
return syn::Error::new_spanned(
name,
"Can not derive `EncodeLabelSet` for unit struct.",
)
.to_compile_error()
.to_token_stream()
.into();
}
syn::Fields::Unit => panic!("Can not derive Encode for struct with unit field."),
},
syn::Data::Enum(syn::DataEnum { .. }) => {
panic!("Can not derive Encode for enum.")
return syn::Error::new_spanned(name, "Can not derive `EncodeLabelSet` for enum.")
.to_compile_error()
.to_token_stream()
.into();
}
syn::Data::Union(_) => {
return syn::Error::new_spanned(name, "Can not derive `EncodeLabelSet` for union.")
.to_compile_error()
.to_token_stream()
.into()
}
syn::Data::Union(_) => panic!("Can not derive Encode for union."),
};

let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
let gen = quote! {
impl ::prometheus_client::encoding::EncodeLabelSet for #name {
impl #impl_generics ::prometheus_client::encoding::EncodeLabelSet for #name #ty_generics #where_clause {
fn encode(&self, encoder: &mut ::prometheus_client::encoding::LabelSetEncoder) -> ::core::result::Result<(), ::core::fmt::Error> {
use ::prometheus_client::encoding::EncodeLabel;
use ::prometheus_client::encoding::EncodeLabelKey;
Expand All @@ -95,7 +118,10 @@ pub fn derive_encode_label_value(input: TokenStream) -> TokenStream {

let body = match ast.clone().data {
syn::Data::Struct(_) => {
panic!("Can not derive EncodeLabel for struct.")
return syn::Error::new_spanned(name, "Can not derive `EncodeLabelValue` for struct.")
.to_compile_error()
.to_token_stream()
.into();
}
syn::Data::Enum(syn::DataEnum { variants, .. }) => {
let match_arms: TokenStream2 = variants
Expand All @@ -114,7 +140,12 @@ pub fn derive_encode_label_value(input: TokenStream) -> TokenStream {
}
}
}
syn::Data::Union(_) => panic!("Can not derive Encode for union."),
syn::Data::Union(_) => {
return syn::Error::new_spanned(name, "Can not derive `EncodeLabelValue` for union.")
.to_compile_error()
.to_token_stream()
.into()
}
};

let gen = quote! {
Expand Down
50 changes: 50 additions & 0 deletions derive-encode/tests/build/friendly-compilation-error-msg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use prometheus_client::encoding::EncodeLabelSet;
use prometheus_client::encoding::EncodeLabelValue;

mod A {
use super::*;

#[derive(Debug, Clone, PartialEq, Eq, Hash, EncodeLabelSet)]
struct Unnamed(String);

#[derive(Debug, Clone, PartialEq, Eq, Hash, EncodeLabelSet)]
struct Unit;

#[derive(Debug, Clone, PartialEq, Eq, Hash, EncodeLabelSet)]
enum Enum {
A,
B,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash, EncodeLabelSet)]
enum DataEnum {
A,
B(String),
}

#[derive(Clone, Copy, EncodeLabelSet)]
#[repr(C)]
union Union {
a: u32,
b: u64,
}
}

mod B {
use super::*;

#[derive(Debug, Clone, PartialEq, Eq, Hash, EncodeLabelValue)]
struct Struct {
a: String,
b: String,
}

#[derive(Clone, Copy, EncodeLabelValue)]
#[repr(C)]
union Union {
a: u32,
b: u64,
}
}

fn main() {}
41 changes: 41 additions & 0 deletions derive-encode/tests/build/friendly-compilation-error-msg.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
error: Can not derive `EncodeLabelSet` for struct with unnamed fields.
--> tests/build/friendly-compilation-error-msg.rs:8:12
|
8 | struct Unnamed(String);
| ^^^^^^^

error: Can not derive `EncodeLabelSet` for unit struct.
--> tests/build/friendly-compilation-error-msg.rs:11:12
|
11 | struct Unit;
| ^^^^

error: Can not derive `EncodeLabelSet` for enum.
--> tests/build/friendly-compilation-error-msg.rs:14:10
|
14 | enum Enum {
| ^^^^

error: Can not derive `EncodeLabelSet` for enum.
--> tests/build/friendly-compilation-error-msg.rs:20:10
|
20 | enum DataEnum {
| ^^^^^^^^

error: Can not derive `EncodeLabelSet` for union.
--> tests/build/friendly-compilation-error-msg.rs:27:11
|
27 | union Union {
| ^^^^^

error: Can not derive `EncodeLabelValue` for struct.
--> tests/build/friendly-compilation-error-msg.rs:37:12
|
37 | struct Struct {
| ^^^^^^

error: Can not derive `EncodeLabelValue` for union.
--> tests/build/friendly-compilation-error-msg.rs:44:11
|
44 | union Union {
| ^^^^^
18 changes: 18 additions & 0 deletions derive-encode/tests/build/keep-impl-generics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use prometheus_client::encoding::EncodeLabelSet;
use prometheus_client::encoding::EncodeLabelValue;

#[derive(Debug, Clone, PartialEq, Eq, Hash, EncodeLabelValue)]
enum CpuUsageLabelMode {
User,
System,
Irq,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash, EncodeLabelSet)]
struct CpuUsageLabelSet<'a> { // <-- `'a` lifetime is used in the struct,
// this should be preserved in the impl block
mode: CpuUsageLabelMode,
service: &'a str
}

fn main() {}
4 changes: 3 additions & 1 deletion derive-encode/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,5 +209,7 @@ fn flatten() {
#[test]
fn build() {
let t = trybuild::TestCases::new();
t.pass("tests/build/redefine-prelude-symbols.rs")
t.pass("tests/build/redefine-prelude-symbols.rs");
t.pass("tests/build/keep-impl-generics.rs");
t.compile_fail("tests/build/friendly-compilation-error-msg.rs");
}
Loading