use indexmap::IndexSet; use serde::{Deserialize, Serialize}; /// A MarkerPlacement defines how a marker affects dimension values. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct MarkerPlacement { /// Only apply this placement if all markers in `if_with` are also present. #[serde(default)] pub if_with: IndexSet, /// The dimension to place a value in. pub dimension: String, /// The value to place. If None, uses the marker name itself. #[serde(default)] pub value: Option, /// Whether this placement should overwrite existing values in the dimension. #[serde(default = "default_overwrites")] pub overwrites: bool, } fn default_overwrites() -> bool { true } impl MarkerPlacement { pub fn new(dimension: impl Into) -> Self { Self { if_with: IndexSet::new(), dimension: dimension.into(), value: None, overwrites: true, } } pub fn with_if_with(mut self, if_with: impl IntoIterator>) -> Self { self.if_with = if_with.into_iter().map(Into::into).collect(); self } pub fn with_value(mut self, value: impl Into) -> Self { self.value = Some(value.into()); self } pub fn with_overwrites(mut self, overwrites: bool) -> Self { self.overwrites = overwrites; self } } /// A Marker defines how an @-tag should be interpreted for dimensional placement. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Marker { /// Human-readable name for display purposes. pub display_name: String, /// The dimensional placements this marker creates. #[serde(default)] pub placements: Vec, } impl Marker { pub fn new(display_name: impl Into) -> Self { Self { display_name: display_name.into(), placements: Vec::new(), } } pub fn with_placements(mut self, placements: Vec) -> Self { self.placements = placements; self } }