swc_config/types/
bool_or_data.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4use crate::merge::Merge;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
7pub struct BoolOrDataConfig<T>(#[serde(default)] Option<BoolOr<T>>);
8
9impl<T> BoolOrDataConfig<T> {
10    pub fn from_bool(v: bool) -> Self {
11        Self(Some(BoolOr::Bool(v)))
12    }
13
14    pub fn from_obj(v: T) -> Self {
15        v.into()
16    }
17
18    pub fn as_ref(&self) -> BoolOrDataConfig<&T> {
19        match &self.0 {
20            Some(BoolOr::Data(v)) => BoolOrDataConfig::from_obj(v),
21            Some(BoolOr::Bool(b)) => BoolOrDataConfig::from_bool(*b),
22            None => BoolOrDataConfig::default(),
23        }
24    }
25
26    pub fn or<F>(self, default: F) -> Self
27    where
28        F: FnOnce() -> Self,
29    {
30        match self.0 {
31            Some(..) => self,
32            None => default(),
33        }
34    }
35
36    pub fn unwrap_as_option<F>(self, default: F) -> Option<T>
37    where
38        F: FnOnce(Option<bool>) -> Option<T>,
39    {
40        match self.0 {
41            Some(BoolOr::Data(v)) => Some(v),
42            Some(BoolOr::Bool(b)) => default(Some(b)),
43            None => default(None),
44        }
45    }
46
47    pub fn map<F, N>(self, op: F) -> BoolOrDataConfig<N>
48    where
49        F: FnOnce(T) -> N,
50    {
51        match self.0 {
52            Some(BoolOr::Data(v)) => BoolOrDataConfig::from_obj(op(v)),
53            Some(BoolOr::Bool(b)) => BoolOrDataConfig::from_bool(b),
54            None => BoolOrDataConfig::default(),
55        }
56    }
57
58    pub fn is_true(&self) -> bool {
59        matches!(self.0, Some(BoolOr::Bool(true)))
60    }
61
62    pub fn is_false(&self) -> bool {
63        matches!(self.0, Some(BoolOr::Bool(false)))
64    }
65
66    pub fn is_obj(&self) -> bool {
67        matches!(self.0, Some(BoolOr::Data(_)))
68    }
69
70    pub fn into_inner(self) -> Option<BoolOr<T>> {
71        self.0
72    }
73
74    pub fn inner(&self) -> Option<BoolOr<&T>> {
75        match &self.0 {
76            Some(BoolOr::Data(v)) => Some(BoolOr::Data(v)),
77            Some(BoolOr::Bool(b)) => Some(BoolOr::Bool(*b)),
78            None => None,
79        }
80    }
81}
82
83impl<T> From<T> for BoolOrDataConfig<T> {
84    fn from(v: T) -> Self {
85        Self(Some(BoolOr::Data(v)))
86    }
87}
88
89impl<T> Default for BoolOrDataConfig<T> {
90    fn default() -> Self {
91        Self(Default::default())
92    }
93}
94
95impl<T> Merge for BoolOrDataConfig<T> {
96    #[inline]
97    fn merge(&mut self, other: Self) {
98        self.0.merge(other.0)
99    }
100}
101
102#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
103#[serde(untagged)]
104pub enum BoolOr<T> {
105    Bool(bool),
106    Data(T),
107}
108
109impl<'de, T> Deserialize<'de> for BoolOr<T>
110where
111    T: Deserialize<'de>,
112{
113    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
114    where
115        D: serde::Deserializer<'de>,
116    {
117        // Try to deserialize as JSON Value first, then match on it
118        let value = Value::deserialize(deserializer)?;
119
120        match value {
121            Value::Bool(b) => Ok(BoolOr::Bool(b)),
122            Value::Object(map) if map.is_empty() => Ok(BoolOr::Bool(true)),
123            other => {
124                // Try to deserialize the value as T
125                T::deserialize(other)
126                    .map(BoolOr::Data)
127                    .map_err(|_| serde::de::Error::custom("expected boolean or object"))
128            }
129        }
130    }
131}