xref: /aosp_15_r20/external/bazelbuild-rules_rust/crate_universe/src/utils/starlark/glob.rs (revision d4726bddaa87cc4778e7472feed243fa4b6c267f)
1 use std::collections::BTreeSet;
2 use std::fmt;
3 
4 use serde::de::value::{MapAccessDeserializer, SeqAccessDeserializer};
5 use serde::de::{Deserialize, Deserializer, MapAccess, SeqAccess, Visitor};
6 use serde::ser::{Serialize, SerializeStruct, Serializer};
7 
8 #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Clone)]
9 pub(crate) struct Glob {
10     pub(crate) allow_empty: bool,
11     pub(crate) include: BTreeSet<String>,
12     pub(crate) exclude: BTreeSet<String>,
13 }
14 
15 impl Glob {
new_rust_srcs(allow_empty: bool) -> Self16     pub(crate) fn new_rust_srcs(allow_empty: bool) -> Self {
17         Self {
18             allow_empty,
19             include: BTreeSet::from(["**/*.rs".to_owned()]),
20             exclude: BTreeSet::new(),
21         }
22     }
23 
has_any_include(&self) -> bool24     pub(crate) fn has_any_include(&self) -> bool {
25         self.include.is_empty()
26         // Note: self.exclude intentionally not considered. A glob is empty if
27         // there are no included globs. A glob cannot have only excludes.
28     }
29 }
30 
31 impl Serialize for Glob {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,32     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
33     where
34         S: Serializer,
35     {
36         let has_exclude = !self.exclude.is_empty();
37         let len = 2 + if has_exclude { 1 } else { 0 };
38 
39         // Serialize as glob(allow_empty = False, include = [...], exclude = [...]).
40         let mut call = serializer.serialize_struct("glob", len)?;
41         call.serialize_field("allow_empty", &self.allow_empty)?;
42         call.serialize_field("include", &self.include)?;
43         if has_exclude {
44             call.serialize_field("exclude", &self.exclude)?;
45         }
46         call.end()
47     }
48 }
49 
50 struct GlobVisitor;
51 
52 impl<'de> Deserialize<'de> for Glob {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,53     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
54     where
55         D: Deserializer<'de>,
56     {
57         deserializer.deserialize_any(GlobVisitor)
58     }
59 }
60 
61 impl<'de> Visitor<'de> for GlobVisitor {
62     type Value = Glob;
63 
expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result64     fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
65         formatter.write_str("glob")
66     }
67 
68     // Deserialize ["included","globs","only"]
visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error> where A: SeqAccess<'de>,69     fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
70     where
71         A: SeqAccess<'de>,
72     {
73         Ok(Glob {
74             // At time of writing the default value of allow_empty is true.
75             // We may want to change this if the default changes in Bazel.
76             allow_empty: true,
77             include: BTreeSet::deserialize(SeqAccessDeserializer::new(seq))?,
78             exclude: BTreeSet::new(),
79         })
80     }
81 
82     // Deserialize {"include":["included","globs"],"exclude":["excluded","globs"]}
visit_map<A>(self, map: A) -> Result<Self::Value, A::Error> where A: MapAccess<'de>,83     fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
84     where
85         A: MapAccess<'de>,
86     {
87         fn default_true() -> bool {
88             true
89         }
90 
91         #[derive(serde::Deserialize)]
92         struct GlobMap {
93             #[serde(default = "default_true")]
94             allow_empty: bool,
95             include: BTreeSet<String>,
96             #[serde(default)]
97             exclude: BTreeSet<String>,
98         }
99 
100         let glob_map = GlobMap::deserialize(MapAccessDeserializer::new(map))?;
101         Ok(Glob {
102             allow_empty: glob_map.allow_empty,
103             include: glob_map.include,
104             exclude: glob_map.exclude,
105         })
106     }
107 }
108