aboutsummaryrefslogtreecommitdiff
path: root/crate_universe/src/utils/starlark/glob.rs
blob: c8bf4bf5b9dcc818ce76e6fa494448989e4fd90d (plain)
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use std::collections::BTreeSet;
use std::fmt;

use serde::de::value::{MapAccessDeserializer, SeqAccessDeserializer};
use serde::de::{Deserialize, Deserializer, MapAccess, SeqAccess, Visitor};
use serde::ser::{Serialize, SerializeStruct, Serializer};

#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub(crate) struct Glob {
    pub(crate) allow_empty: bool,
    pub(crate) include: BTreeSet<String>,
    pub(crate) exclude: BTreeSet<String>,
}

impl Glob {
    pub(crate) fn new_rust_srcs() -> Self {
        Self {
            allow_empty: false,
            include: BTreeSet::from(["**/*.rs".to_owned()]),
            exclude: BTreeSet::new(),
        }
    }

    pub(crate) fn has_any_include(&self) -> bool {
        self.include.is_empty()
        // Note: self.exclude intentionally not considered. A glob is empty if
        // there are no included globs. A glob cannot have only excludes.
    }
}

impl Serialize for Glob {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let has_exclude = !self.exclude.is_empty();
        let len = 2 + if has_exclude { 1 } else { 0 };

        // Serialize as glob(allow_empty = False, include = [...], exclude = [...]).
        let mut call = serializer.serialize_struct("glob", len)?;
        call.serialize_field("allow_empty", &self.allow_empty)?;
        call.serialize_field("include", &self.include)?;
        if has_exclude {
            call.serialize_field("exclude", &self.exclude)?;
        }
        call.end()
    }
}

struct GlobVisitor;

impl<'de> Deserialize<'de> for Glob {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_any(GlobVisitor)
    }
}

impl<'de> Visitor<'de> for GlobVisitor {
    type Value = Glob;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("glob")
    }

    // Deserialize ["included","globs","only"]
    fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
    where
        A: SeqAccess<'de>,
    {
        Ok(Glob {
            // At time of writing the default value of allow_empty is true.
            // We may want to change this if the default changes in Bazel.
            allow_empty: true,
            include: BTreeSet::deserialize(SeqAccessDeserializer::new(seq))?,
            exclude: BTreeSet::new(),
        })
    }

    // Deserialize {"include":["included","globs"],"exclude":["excluded","globs"]}
    fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
    where
        A: MapAccess<'de>,
    {
        fn default_true() -> bool {
            true
        }

        #[derive(serde::Deserialize)]
        struct GlobMap {
            #[serde(default = "default_true")]
            allow_empty: bool,
            include: BTreeSet<String>,
            #[serde(default)]
            exclude: BTreeSet<String>,
        }

        let glob_map = GlobMap::deserialize(MapAccessDeserializer::new(map))?;
        Ok(Glob {
            allow_empty: glob_map.allow_empty,
            include: glob_map.include,
            exclude: glob_map.exclude,
        })
    }
}