1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
better_scoped_tls::scoped_tls!(static FLAVOR: Flavor);

#[repr(u8)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum Flavor {
    Babel,
    Acorn { extra_comments: bool },
}

impl Default for Flavor {
    fn default() -> Self {
        Flavor::Babel
    }
}

impl Flavor {
    pub fn with<F, Ret>(self, op: F) -> Ret
    where
        F: FnOnce() -> Ret,
    {
        FLAVOR.set(&self, op)
    }

    pub fn current() -> Self {
        if FLAVOR.is_set() {
            FLAVOR.with(|v| *v)
        } else {
            Flavor::default()
        }
    }

    pub fn emit_loc(&self) -> bool {
        true
    }

    pub(crate) fn skip_range(_: &Option<[u32; 2]>) -> bool {
        matches!(Self::current(), Flavor::Babel)
    }

    pub(crate) fn skip_empty<T>(v: &T) -> bool
    where
        T: IsEmpty,
    {
        matches!(Self::current(), Flavor::Acorn { .. }) && v.is_empty()
    }

    pub(crate) fn skip_none<T>(v: &Option<T>) -> bool {
        matches!(Self::current(), Flavor::Acorn { .. }) && v.is_none()
    }

    pub(crate) fn skip_none_and_false(v: &Option<bool>) -> bool {
        matches!(Self::current(), Flavor::Acorn { .. }) && matches!(v, None | Some(false))
    }
}

pub(crate) trait IsEmpty {
    fn is_empty(&self) -> bool;
}

impl IsEmpty for String {
    fn is_empty(&self) -> bool {
        self.is_empty()
    }
}

impl<T> IsEmpty for Vec<T> {
    fn is_empty(&self) -> bool {
        self.is_empty()
    }
}

impl<T> IsEmpty for Option<T>
where
    T: IsEmpty,
{
    fn is_empty(&self) -> bool {
        match self {
            Some(v) => v.is_empty(),
            None => true,
        }
    }
}