Skip to main content

revive_solc_json_interface/standard_json/input/settings/selection/
mod.rs

1//! The `solc --standard-json` output selection.
2
3pub mod file;
4
5use std::collections::BTreeMap;
6
7use serde::Deserialize;
8use serde::Serialize;
9
10use self::file::flag::Flag;
11use self::file::File as FileSelection;
12
13/// The `solc --standard-json` per-file output selection.
14#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq)]
15pub struct PerFileSelection {
16    /// Individual file selection configuration, required for foundry.
17    #[serde(skip_serializing_if = "BTreeMap::is_empty", flatten)]
18    pub files: BTreeMap<String, FileSelection>,
19}
20
21impl PerFileSelection {
22    /// Extends the output selection with another one.
23    pub fn extend(&mut self, other: Self) {
24        for (entry, file) in other.files {
25            self.files
26                .entry(entry)
27                .and_modify(|v| {
28                    v.extend(file.clone());
29                })
30                .or_insert(file);
31        }
32    }
33
34    /// Returns flags that are going to be automatically added by the compiler,
35    /// but were not explicitly requested by the user.
36    ///
37    /// Afterwards, the flags are used to prune JSON output before returning it.
38    pub fn selection_to_prune(&self) -> Self {
39        let files = self
40            .files
41            .iter()
42            .map(|(k, v)| (k.to_owned(), v.selection_to_prune()))
43            .collect();
44        Self { files }
45    }
46
47    /// Checks whether `path` contains the `flag` or `None` if there is no selection for `path`.
48    pub fn contains(&self, path: &String, flag: Flag) -> Option<bool> {
49        if let Some(file) = self.files.get(path) {
50            return Some(file.contains(flag));
51        };
52        None
53    }
54
55    /// Checks whether this is the empty per file selection.
56    pub fn is_empty(&self) -> bool {
57        self.files.is_empty()
58    }
59
60    /// Removes unneeded selections.
61    pub fn retain(&mut self) {
62        for file in self.files.values_mut() {
63            file.per_contract.retain(|flag| !flag.is_evm_codegen());
64            file.per_file.retain(|flag| !flag.is_evm_codegen());
65        }
66    }
67}
68
69/// The `solc --standard-json` output selection.
70#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq)]
71pub struct Selection {
72    /// Common configuration for all files.
73    #[serde(default, rename = "*", skip_serializing_if = "FileSelection::is_empty")]
74    pub all: FileSelection,
75    /// Individual file selection configuration, required for foundry.
76    #[serde(skip_serializing_if = "PerFileSelection::is_empty", flatten)]
77    pub files: PerFileSelection,
78}
79
80impl Selection {
81    /// Creates the selection for all contracts in all files with arbitrary `flags`.
82    pub fn new_all(flags: Vec<Flag>) -> Self {
83        Self {
84            all: FileSelection::new(flags),
85            files: Default::default(),
86        }
87    }
88
89    /// Creates the selection required by our compilation process for all contracts in all files.
90    pub fn new_required_for_codegen_all() -> Self {
91        Self::new_all(Flag::codegen_requirements().into())
92    }
93
94    /// Creates the selection required by our compilation process for each contract in
95    /// `output_selection` requesting code generation.
96    pub fn new_required_for_codegen(output_selection: &Self) -> Self {
97        if output_selection.all.requests_codegen() {
98            return Self::new_required_for_codegen_all();
99        }
100
101        let mut files = PerFileSelection::default();
102        for (file_name, file_selection) in &output_selection.files.files {
103            if file_selection.requests_codegen() {
104                files.files.insert(
105                    file_name.to_owned(),
106                    FileSelection::new_required_for_codegen(),
107                );
108            }
109        }
110
111        Self {
112            all: Default::default(),
113            files,
114        }
115    }
116
117    /// Creates the selection required for test compilation (includes EVM bytecode) for all
118    /// contracts in all files.
119    pub fn new_required_for_tests() -> Self {
120        Self {
121            all: FileSelection::new_required_for_tests(),
122            files: Default::default(),
123        }
124    }
125
126    /// Creates the selection required by Yul validation process.
127    pub fn new_yul_validation() -> Self {
128        Self::new_all(vec![Flag::EVM])
129    }
130
131    /// Extends the output selection with another one.
132    pub fn extend(&mut self, other: Self) -> &mut Self {
133        self.all.extend(other.all);
134        self.files.extend(other.files);
135        self
136    }
137
138    /// Returns flags that were not explicitly requested by the user.
139    ///
140    /// These flags are used to prune JSON output before returning it,
141    /// removing any output that was automatically added but not requested.
142    pub fn selection_to_prune(&self) -> Self {
143        Self {
144            all: self.all.selection_to_prune(),
145            files: self.files.selection_to_prune(),
146        }
147    }
148
149    /// Checks whether the `flag` is requested.
150    pub fn contains(&self, path: &String, flag: Flag) -> bool {
151        self.files
152            .contains(path, flag)
153            .unwrap_or(self.all.contains(flag))
154    }
155
156    /// Removes unneeded selections.
157    pub fn retain(&mut self) {
158        self.all.per_file.retain(|flag| !flag.is_evm_codegen());
159        self.all.per_contract.retain(|flag| !flag.is_evm_codegen());
160        self.files.retain();
161    }
162}