Skip to main content

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

1//! The `solc --standard-json` output file selection.
2
3pub mod flag;
4
5use std::collections::HashSet;
6
7use serde::Deserialize;
8use serde::Serialize;
9
10use self::flag::Flag as SelectionFlag;
11
12/// The `solc --standard-json` output file selection.
13#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
14pub struct File {
15    /// The per-file output selections.
16    #[serde(default, rename = "", skip_serializing_if = "HashSet::is_empty")]
17    pub per_file: HashSet<SelectionFlag>,
18    /// The per-contract output selections, common for all contracts.
19    /// Only the "all" (`*`) wildcard is available for robustness reasons.
20    #[serde(default, rename = "*", skip_serializing_if = "HashSet::is_empty")]
21    pub per_contract: HashSet<SelectionFlag>,
22}
23
24impl File {
25    /// Creates the selection for all contracts with arbitrary `flags`.
26    pub fn new(flags: Vec<SelectionFlag>) -> Self {
27        let mut per_file = HashSet::new();
28        let mut per_contract = HashSet::new();
29        for flag in flags.into_iter() {
30            match flag {
31                SelectionFlag::AST => {
32                    per_file.insert(SelectionFlag::AST);
33                }
34                flag => {
35                    per_contract.insert(flag);
36                }
37            }
38        }
39        Self {
40            per_file,
41            per_contract,
42        }
43    }
44
45    /// Creates the selection required by our compilation process.
46    pub fn new_required_for_codegen() -> Self {
47        Self::new(SelectionFlag::codegen_requirements().into())
48    }
49
50    /// Creates the selection required for test compilation (includes EVM bytecode).
51    pub fn new_required_for_tests() -> Self {
52        Self {
53            per_file: HashSet::from_iter([SelectionFlag::AST]),
54            per_contract: HashSet::from_iter([
55                SelectionFlag::EVMBC,
56                SelectionFlag::EVMDBC,
57                SelectionFlag::MethodIdentifiers,
58                SelectionFlag::Metadata,
59                SelectionFlag::Yul,
60            ]),
61        }
62    }
63
64    /// Extends the output selection with another one.
65    pub fn extend(&mut self, other: Self) -> &mut Self {
66        self.per_file.extend(other.per_file);
67        self.per_contract.extend(other.per_contract);
68        self
69    }
70
71    /// Returns flags that were not explicitly requested by the user.
72    ///
73    /// These flags are used to prune JSON output before returning it,
74    /// removing any output that was automatically added but not requested.
75    pub fn selection_to_prune(&self) -> Self {
76        let unset_per_file = SelectionFlag::all()
77            .iter()
78            .copied()
79            .filter(|flag| !self.per_file.contains(flag))
80            .collect();
81
82        let requests_evm_parent = self.contains(SelectionFlag::EVM);
83        let evm_children = SelectionFlag::evm_children();
84        let requests_evm_child = self.contains_any(evm_children);
85
86        let unset_per_contract: HashSet<_> = SelectionFlag::all()
87            .iter()
88            .copied()
89            .filter(|flag| {
90                // Never prune EVM children when the EVM parent is requested.
91                if requests_evm_parent && evm_children.contains(flag) {
92                    return false;
93                }
94                // Never prune the EVM parent when any of its children are requested.
95                if requests_evm_child && *flag == SelectionFlag::EVM {
96                    return false;
97                }
98                !self.per_contract.contains(flag)
99            })
100            .collect();
101
102        Self {
103            per_file: unset_per_file,
104            per_contract: unset_per_contract,
105        }
106    }
107
108    /// Checks whether the `flag` is requested.
109    pub fn contains(&self, flag: SelectionFlag) -> bool {
110        match flag {
111            SelectionFlag::AST => self.per_file.contains(&flag),
112            _ => self.per_contract.contains(&flag),
113        }
114    }
115
116    /// Checks whether any of the `flags` is requested.
117    pub fn contains_any(&self, flags: &[SelectionFlag]) -> bool {
118        flags.iter().any(|&flag| self.contains(flag))
119    }
120
121    /// Checks whether code generation is requested.
122    pub fn requests_codegen(&self) -> bool {
123        self.contains_any(&[
124            SelectionFlag::EVM,
125            SelectionFlag::EVMBC,
126            SelectionFlag::EVMDBC,
127            SelectionFlag::Assembly,
128        ])
129    }
130
131    /// Checks whether the selection is empty.
132    pub fn is_empty(&self) -> bool {
133        self.per_file.is_empty() && self.per_contract.is_empty()
134    }
135}