aboutsummaryrefslogtreecommitdiff
path: root/crate_universe/src/utils/starlark/glob.rs
blob: a7bcebbbad91ddbbd423167e28553e5a30cd67b8 (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
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 struct Glob {
    pub include: BTreeSet<String>,
    pub exclude: BTreeSet<String>,
}

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

    pub fn is_empty(&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,
    {
        if self.exclude.is_empty() {
            // Serialize as glob([...]).
            serializer.serialize_newtype_struct("glob", &self.include)
        } else {
            // Serialize as glob(include = [...], exclude = [...]).
            let mut call = serializer.serialize_struct("glob", 2)?;
            call.serialize_field("include", &self.include)?;
            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 {
            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>,
    {
        #[derive(serde::Deserialize)]
        struct GlobMap {
            include: BTreeSet<String>,
            exclude: BTreeSet<String>,
        }

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