Skip to content

[IDEA]: Add helper for implementing EncodeLabelSet manually #288

@nastynaz

Description

@nastynaz

Problem

Manually implementing EncodeLabelSet for a struct currently involves a lot of boilerplate:

pub struct MyLabels {
    pub method: &'static str,  // or String, Cow<'static, str>, etc.
    pub status: u16
   // many other fields
}

impl EncodeLabelSet for MyLabels {
    fn encode(&self, encoder: &mut LabelSetEncoder) -> Result<(), fmt::Error> {
        // label: method = self.method
        {
            let mut label = encoder.encode_label();
            let mut key = label.encode_label_key()?;
            // field name -> key string (handle raw-idents manually if you used them)
            EncodeLabelKey::encode("method", &mut key)?;

            let mut value = key.encode_label_value()?;
            EncodeLabelValue::encode(&self.method, &mut value)?;
            value.finish()?;
        }
        // label: status = self.status
        {
            let mut label = encoder.encode_label();
            let mut key = label.encode_label_key()?;
            EncodeLabelKey::encode("status", &mut key)?;
            let mut value = key.encode_label_value()?;
            EncodeLabelValue::encode(&self.status, &mut value)?;
            value.finish()?;
        }

        // repeated for all other fields

        Ok(())
    }
}

This can become a chore if you have to implement it manually (e.g. because you want conditional encoding).

Solution

A new LabelSetWriter struct that allows you to easily specify (key, value) pairs to encode.

Usage

 pub struct MyLabels {
     pub status: u16,
     pub method: &'static str,
     pub optional: Option<&'static str>,
     // suppose we want to flatten these (like `#[prometheus(flatten)]`)
     pub common: CommonLabels
 }

 impl EncodeLabelSet for MyLabels {
     fn encode(&self, enc: &mut LabelSetEncoder) -> Result<(), fmt::Error> {
         let mut writer = LabelSetWriter::new(enc);
             .kv("status", &self.status)?
             .kv("method", &self.method)?;

         // allows for conditional encoding
         if let Some(optional) = &self.optional {
             writer.kv("optional", optional)?;
         }
        // allows flattening
         writer.flatten(&self.common)?;

         Ok(())
     }
 }

Discussion

I've written the code for LabelSetWriter and it's helpful for me in reducing boilerplate.
Would anyone else find this useful? I'm open to making a PR if so.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions