trading-charts 0.1.2

Rust binding of Lightweight Charts for Leptos
use serde::{
    de::{Visitor, Error},
    Deserialize,
    Serialize,
    Deserializer,
    Serializer,
};
use std::fmt::{Formatter, Result as FmtResult};

#[derive(Clone, Default)]
pub enum FlagableOptions<T: Serialize + for<'de> Deserialize<'de> + Clone + Default> {
    #[default]
    None,
    False,
    True,
    Options(T),
}

impl<T: Serialize + for<'de> Deserialize<'de> + Clone + Default> FlagableOptions<T> {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn new_options(options: T) -> Self {
        Self::Options(options)
    }

    pub fn is_none(&self) -> bool {
        matches!(self, Self::None)
    }
}

impl<T: Serialize + for<'de> Deserialize<'de> + Clone + Default> Serialize for FlagableOptions<T> {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        match self {
            FlagableOptions::None => serializer.serialize_none(),
            FlagableOptions::False => serializer.serialize_bool(false),
            FlagableOptions::True => serializer.serialize_bool(true),
            FlagableOptions::Options(options) => options.serialize(serializer),
        }
    }
}

impl<'de, T: Serialize + for<'x> Deserialize<'x> + Clone + Default> Deserialize<'de> for FlagableOptions<T> {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        deserializer.deserialize_any(FlagableOptionsVisitor::<T> {
            _marker: std::marker::PhantomData,
        })
    }
}

struct FlagableOptionsVisitor<T: Serialize + for<'de> Deserialize<'de> + Clone + Default> {
    _marker: std::marker::PhantomData<T>,
}

impl<'de, T: Serialize + for<'x> Deserialize<'x> + Clone + Default> Visitor<'de> for FlagableOptionsVisitor<T> {
    type Value = FlagableOptions<T>;

    fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
        formatter.write_str("a boolean or an object")
    }

    fn visit_bool<E: Error>(self, v: bool) -> Result<Self::Value, E> {
        Ok(if v {
            FlagableOptions::True
        } else {
            FlagableOptions::False
        })
    }

    fn visit_none<E: Error>(self) -> Result<Self::Value, E> {
        Ok(FlagableOptions::None)
    }

    fn visit_some<D: Deserializer<'de>>(self, deserializer: D) -> Result<Self::Value, D::Error> {
        Ok(FlagableOptions::Options(T::deserialize(deserializer)?))
    }
}