use serde::de::{Error, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
use std::marker::PhantomData;
use crate::schema::*;
#[derive(Clone, Debug, Default)]
pub enum RemovableValue<T: Clone> {
#[default]
Default,
Remove,
Specified(T),
}
impl<T: Clone> RemovableValue<T> {
pub(crate) fn is_default(&self) -> bool {
matches!(self, RemovableValue::Default)
}
}
impl<T: Clone> From<T> for RemovableValue<T> {
fn from(value: T) -> Self {
RemovableValue::Specified(value)
}
}
macro_rules! from_into_with_removable{
( $( $from:ty => $to:ty ),* $(,)? ) => {
$(
impl From<$from> for RemovableValue<$to>
{
fn from(v: $from) -> Self {
RemovableValue::Specified(v.into())
}
}
)*
};
}
from_into_with_removable! {
&str => String,
&str => ClearUnion,
&str => Color,
&str => ConditionalAxisPropertyFontStyleNull,
&str => ConditionalAxisPropertyStringNull,
&str => ConditionalPredicateValueDefTextExprRefText,
&str => ConditionalValueDefGradientStringNullExprRefValue,
&str => ConditionalValueDefNumberExprRefPredicateComposition,
&str => ConditionalValueDefNumberExprRefSelectionComposition,
&str => ConditionalValueDefTextExprRefText,
&str => Day,
&str => DomainElement,
&str => Equal,
&str => Field,
&str => FluffyRange,
&str => FluffyStream,
&str => Format,
&str => GridColorUnion,
&str => InitValue,
&str => InlineDatasetValue,
&str => LegendText,
&str => LegendUnion,
&str => Lt,
&str => MarkConfigExprOrSignalRefColor,
&str => MarkConfigExprOrSignalRefFill,
&str => MarkConfigExprOrSignalRefTooltip,
&str => Month,
&str => OnUnion,
&str => PredicateCompositionElement,
&str => PrimitiveValue,
&str => PurpleStream,
&str => RangeM,
&str => RangeText,
&str => Scheme,
&str => SelectionCompositionElement,
&str => SelectionInit,
&str => SelectionInitInterval,
&str => StyleColor,
&str => StyleFill,
&str => StyleTooltip,
&str => TitleUnion,
&str => Translate,
&str => UrlDataInlineDataset,
Sort => SortUnion,
EncodingSortField => SortUnion,
}
impl<T> Serialize for RemovableValue<T>
where
T: Serialize + Clone,
{
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
RemovableValue::Specified(ref value) => serializer.serialize_some(value),
RemovableValue::Default => serializer.serialize_none(),
RemovableValue::Remove => serializer.serialize_none(),
}
}
}
struct RemovableValueVisitor<T> {
marker: PhantomData<T>,
}
impl<'de, T> Visitor<'de> for RemovableValueVisitor<T>
where
T: Deserialize<'de> + Clone,
{
type Value = RemovableValue<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("option")
}
#[inline]
fn visit_unit<E>(self) -> Result<Self::Value, E>
where
E: Error,
{
Ok(RemovableValue::Remove)
}
#[inline]
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: Error,
{
Ok(RemovableValue::Remove)
}
#[inline]
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
T::deserialize(deserializer).map(RemovableValue::Specified)
}
#[doc(hidden)]
fn __private_visit_untagged_option<D>(self, deserializer: D) -> Result<Self::Value, ()>
where
D: Deserializer<'de>,
{
Ok(match T::deserialize(deserializer) {
Ok(v) => RemovableValue::Specified(v),
_ => RemovableValue::Remove,
})
}
}
impl<'de, T> Deserialize<'de> for RemovableValue<T>
where
T: Deserialize<'de> + Clone,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_option(RemovableValueVisitor {
marker: PhantomData,
})
}
}