Crate charming_macros

Source
Expand description

CharmingSetters is a derive macro for the Charming chart rendering library. It is used to remove a lot of boilerplate code in the library by implementing common methods to set the fields of structs.

Example without the macro

use serde::{Serialize, Deserialize};
use charming::component::Title;
use charming::element::{Color, Tooltip};
use charming::datatype::{DataFrame, DataPoint};

#[serde_with::apply(
  Option => #[serde(skip_serializing_if = "Option::is_none")],
  Vec => #[serde(default, skip_serializing_if = "Vec::is_empty")]
)]
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
struct Component {
    title: Vec<Title>,
    tooltip: Option<Tooltip>,
    color: Vec<Color>,
    position: Option<(String, String)>,
    data: DataFrame

    // many fields cut for brevity
}
// For setting these fields with the setter pattern we would need to implement the following
// methods manually when we are not using the derive macro
impl Component {
    pub fn new() -> Self {
        Self {
            title: Vec::new(),
            tooltip: None,
            color: Vec::new(),
            position: None,
            data: DataFrame::default(),
        }
    }
    pub fn title<T: Into<Title>>(mut self, title: T) -> Self {
        self.title.push(title.into());
        self
    }
    pub fn tooltip<T: Into<Tooltip>>(mut self, tooltip: T) -> Self {
        self.tooltip = Some(tooltip.into());
        self
    }
    pub fn color<C: Into<Color>>(mut self, color: Vec<C>) -> Self {
        self.color = color.into_iter().map(|c| c.into()).collect();
        self
    }
    pub fn position<S: Into<String>>(mut self, position: (S, S)) -> Self {
        self.position = Some((position.0.into(), position.1.into()));
        self
    }
    pub fn data<D: Into<DataPoint>>(mut self, data: Vec<D>) -> Self {
        self.data = data.into_iter().map(|d| d.into()).collect();
        self
    }
    // many methods cut for brevity
}

Example with the macro

use serde::{Serialize, Deserialize};
use charming::component::Title;
use charming::element::{Color, Tooltip};
use charming::datatype::{DataFrame, DataPoint};
use charming_macros::CharmingSetters;

#[serde_with::apply(
  Option => #[serde(skip_serializing_if = "Option::is_none")],
  Vec => #[serde(default, skip_serializing_if = "Vec::is_empty")]
)]
#[derive(Serialize, Deserialize, CharmingSetters, Debug, PartialEq, Clone)]
struct Component {
    title: Vec<Title>,
    tooltip: Option<Tooltip>,
    #[charming_set_vec]
    color: Vec<Color>,
    #[charming_skip_setter]
    position: Option<(String, String)>,
    data: DataFrame

    // many fields cut for brevity
}

impl Component {
    pub fn position<S: Into<String>>(mut self, position: (S, S)) -> Self {
        self.position = Some((position.0.into(), position.1.into()));
        self
    }
}
// All other methods from the previous example are now getting generated automatically

Derive Macrosยง

CharmingSetters