charming 0.6.0

A visualization library for Rust
Documentation
use std::fmt::Debug;

use serde::{Deserialize, Serialize};

use crate::element::ItemStyle;

use super::CompositeValue;

#[derive(Serialize, Deserialize, PartialOrd, Clone)]
#[serde(rename_all = "camelCase")]
pub struct DataPointItem {
    value: CompositeValue,

    #[serde(skip_serializing_if = "Option::is_none")]
    name: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    item_style: Option<ItemStyle>,
}

impl DataPointItem {
    pub fn new<C: Into<CompositeValue>>(value: C) -> Self {
        Self {
            value: value.into(),
            name: None,
            item_style: None,
        }
    }

    pub fn name<S: Into<String>>(mut self, name: S) -> Self {
        self.name = Some(name.into());
        self
    }

    pub fn item_style<I: Into<ItemStyle>>(mut self, item_style: I) -> Self {
        self.item_style = Some(item_style.into());
        self
    }
}

impl Debug for DataPointItem {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("DataPointItem")
            .field("value", &self.value)
            .field("name", &self.name)
            .finish()
    }
}

impl PartialEq for DataPointItem {
    fn eq(&self, other: &Self) -> bool {
        self.value == other.value && self.name == other.name
    }
}

impl<V> From<V> for DataPointItem
where
    V: Into<CompositeValue>,
{
    fn from(v: V) -> Self {
        DataPointItem::new(v)
    }
}

impl<V, S> From<(V, S)> for DataPointItem
where
    V: Into<CompositeValue>,
    S: Into<String>,
{
    fn from(v: (V, S)) -> Self {
        DataPointItem::new(v.0).name(v.1)
    }
}

#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Clone)]
#[serde(untagged)]
#[allow(clippy::large_enum_variant)]
pub enum DataPoint {
    Value(CompositeValue),
    Item(DataPointItem),
}

impl<V> From<V> for DataPoint
where
    V: Into<CompositeValue>,
{
    fn from(v: V) -> Self {
        DataPoint::Value(v.into())
    }
}

impl<V, S> From<(V, S)> for DataPoint
where
    V: Into<CompositeValue>,
    S: Into<String>,
{
    fn from(v: (V, S)) -> Self {
        DataPoint::Item(DataPointItem::new(v.0).name(v.1))
    }
}

impl From<DataPointItem> for DataPoint {
    fn from(item: DataPointItem) -> Self {
        DataPoint::Item(item)
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn data_point_from_composite_value() {
        let p: DataPoint = 42.into();
        let q = DataPoint::Value(42.into());
        assert_eq!(p, q);

        let p: DataPoint = (-std::f32::consts::PI).into();
        let q = DataPoint::Value((-std::f32::consts::PI).into());
        assert_eq!(p, q);

        let p: DataPoint = "foo".into();
        let q = DataPoint::Value("foo".into());
        assert_eq!(p, q);

        let p: DataPoint = vec![
            CompositeValue::from(42),
            CompositeValue::from(-std::f32::consts::PI),
            CompositeValue::from("foo"),
        ]
        .into();
        let q = DataPoint::Value(
            vec![
                CompositeValue::from(42),
                CompositeValue::from(-std::f32::consts::PI),
                CompositeValue::from("foo"),
            ]
            .into(),
        );
        assert_eq!(p, q);
    }

    #[test]
    fn data_point_from_tuple() {
        let p: DataPoint = (42, "foo").into();
        let q = DataPoint::Item((42, "foo").into());
        assert_eq!(p, q);
    }
}