foundry_compilers/compile/output/
contracts.rs1use crate::{ArtifactId, compilers::CompilerContract};
2use foundry_compilers_artifacts::{
3 CompactContractBytecode, CompactContractRef, FileToContractsMap,
4};
5use semver::Version;
6use serde::{Deserialize, Deserializer, Serialize, Serializer};
7use std::{
8 collections::BTreeMap,
9 ops::{Deref, DerefMut},
10 path::{Path, PathBuf},
11};
12
13#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
15#[serde(transparent)]
16pub struct VersionedContracts<C>(pub FileToContractsMap<Vec<VersionedContract<C>>>);
17
18impl<C> Default for VersionedContracts<C> {
19 fn default() -> Self {
20 Self(BTreeMap::new())
21 }
22}
23
24impl<C> VersionedContracts<C>
25where
26 C: CompilerContract,
27{
28 #[allow(clippy::missing_const_for_fn)]
30 pub fn slash_paths(&mut self) {
31 #[cfg(windows)]
32 {
33 use path_slash::PathExt;
34 self.0 = std::mem::take(&mut self.0)
35 .into_iter()
36 .map(|(path, files)| (PathBuf::from(path.to_slash_lossy().as_ref()), files))
37 .collect()
38 }
39 }
40 pub fn is_empty(&self) -> bool {
41 self.0.is_empty()
42 }
43
44 pub fn len(&self) -> usize {
45 self.0.len()
46 }
47
48 pub fn files(&self) -> impl Iterator<Item = &PathBuf> + '_ {
50 self.0.keys()
51 }
52
53 pub fn find_first(&self, contract_name: &str) -> Option<CompactContractRef<'_>> {
65 self.contracts().find_map(|(name, contract)| {
66 (name == contract_name).then(|| contract.as_compact_contract_ref())
67 })
68 }
69
70 pub fn find(
82 &self,
83 contract_path: &Path,
84 contract_name: &str,
85 ) -> Option<CompactContractRef<'_>> {
86 self.contracts_with_files().find_map(|(path, name, contract)| {
87 (path == contract_path && name == contract_name)
88 .then(|| contract.as_compact_contract_ref())
89 })
90 }
91
92 pub fn remove_first(&mut self, contract_name: &str) -> Option<C> {
104 self.0.values_mut().find_map(|all_contracts| {
105 let mut contract = None;
106 if let Some((c, mut contracts)) = all_contracts.remove_entry(contract_name) {
107 if !contracts.is_empty() {
108 contract = Some(contracts.remove(0).contract);
109 }
110 if !contracts.is_empty() {
111 all_contracts.insert(c, contracts);
112 }
113 }
114 contract
115 })
116 }
117
118 pub fn remove(&mut self, path: &Path, contract_name: &str) -> Option<C> {
130 let (key, mut all_contracts) = self.0.remove_entry(path)?;
131 let mut contract = None;
132 if let Some((c, mut contracts)) = all_contracts.remove_entry(contract_name) {
133 if !contracts.is_empty() {
134 contract = Some(contracts.remove(0).contract);
135 }
136 if !contracts.is_empty() {
137 all_contracts.insert(c, contracts);
138 }
139 }
140
141 if !all_contracts.is_empty() {
142 self.0.insert(key, all_contracts);
143 }
144 contract
145 }
146
147 pub fn get(&self, path: &Path, contract: &str) -> Option<CompactContractRef<'_>> {
150 self.0
151 .get(path)
152 .and_then(|contracts| {
153 contracts.get(contract).and_then(|c| c.first().map(|c| &c.contract))
154 })
155 .map(|c| c.as_compact_contract_ref())
156 }
157
158 pub fn contracts(&self) -> impl Iterator<Item = (&String, &C)> {
160 self.0
161 .values()
162 .flat_map(|c| c.iter().flat_map(|(name, c)| c.iter().map(move |c| (name, &c.contract))))
163 }
164
165 pub fn contracts_with_files(&self) -> impl Iterator<Item = (&PathBuf, &String, &C)> {
167 self.0.iter().flat_map(|(file, contracts)| {
168 contracts
169 .iter()
170 .flat_map(move |(name, c)| c.iter().map(move |c| (file, name, &c.contract)))
171 })
172 }
173
174 pub fn contracts_with_files_and_version(
176 &self,
177 ) -> impl Iterator<Item = (&PathBuf, &String, &C, &Version)> {
178 self.0.iter().flat_map(|(file, contracts)| {
179 contracts.iter().flat_map(move |(name, c)| {
180 c.iter().map(move |c| (file, name, &c.contract, &c.version))
181 })
182 })
183 }
184
185 pub fn into_contracts(self) -> impl Iterator<Item = (String, C)> {
187 self.0.into_values().flat_map(|c| {
188 c.into_iter()
189 .flat_map(|(name, c)| c.into_iter().map(move |c| (name.clone(), c.contract)))
190 })
191 }
192
193 pub fn into_contracts_with_files(self) -> impl Iterator<Item = (PathBuf, String, C)> {
195 self.0.into_iter().flat_map(|(file, contracts)| {
196 contracts.into_iter().flat_map(move |(name, c)| {
197 let file = file.clone();
198 c.into_iter().map(move |c| (file.clone(), name.clone(), c.contract))
199 })
200 })
201 }
202
203 pub fn into_contracts_with_files_and_version(
205 self,
206 ) -> impl Iterator<Item = (PathBuf, String, C, Version)> {
207 self.0.into_iter().flat_map(|(file, contracts)| {
208 contracts.into_iter().flat_map(move |(name, c)| {
209 let file = file.clone();
210 c.into_iter().map(move |c| (file.clone(), name.clone(), c.contract, c.version))
211 })
212 })
213 }
214
215 pub fn join_all(&mut self, root: &Path) -> &mut Self {
217 self.0 = std::mem::take(&mut self.0)
218 .into_iter()
219 .map(|(contract_path, contracts)| (root.join(contract_path), contracts))
220 .collect();
221 self
222 }
223
224 pub fn strip_prefix_all(&mut self, base: &Path) -> &mut Self {
226 self.0 = std::mem::take(&mut self.0)
227 .into_iter()
228 .map(|(contract_path, contracts)| {
229 (
230 contract_path.strip_prefix(base).unwrap_or(&contract_path).to_path_buf(),
231 contracts,
232 )
233 })
234 .collect();
235 self
236 }
237}
238
239impl<C> AsRef<FileToContractsMap<Vec<VersionedContract<C>>>> for VersionedContracts<C>
240where
241 C: CompilerContract,
242{
243 fn as_ref(&self) -> &FileToContractsMap<Vec<VersionedContract<C>>> {
244 &self.0
245 }
246}
247
248impl<C> AsMut<FileToContractsMap<Vec<VersionedContract<C>>>> for VersionedContracts<C>
249where
250 C: CompilerContract,
251{
252 fn as_mut(&mut self) -> &mut FileToContractsMap<Vec<VersionedContract<C>>> {
253 &mut self.0
254 }
255}
256
257impl<C> Deref for VersionedContracts<C>
258where
259 C: CompilerContract,
260{
261 type Target = FileToContractsMap<Vec<VersionedContract<C>>>;
262
263 fn deref(&self) -> &Self::Target {
264 &self.0
265 }
266}
267
268impl<C> IntoIterator for VersionedContracts<C>
269where
270 C: CompilerContract,
271{
272 type Item = (PathBuf, BTreeMap<String, Vec<VersionedContract<C>>>);
273 type IntoIter =
274 std::collections::btree_map::IntoIter<PathBuf, BTreeMap<String, Vec<VersionedContract<C>>>>;
275
276 fn into_iter(self) -> Self::IntoIter {
277 self.0.into_iter()
278 }
279}
280
281#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
283pub struct VersionedContract<C> {
284 pub contract: C,
285 pub version: Version,
286 pub build_id: String,
287 pub profile: String,
288}
289
290#[derive(Clone, Debug, Default, PartialEq, Eq)]
292pub struct ArtifactContracts<T = CompactContractBytecode>(pub BTreeMap<ArtifactId, T>);
293
294impl<T: Serialize> Serialize for ArtifactContracts<T> {
295 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
296 where
297 S: Serializer,
298 {
299 self.0.serialize(serializer)
300 }
301}
302
303impl<'de, T: Deserialize<'de>> Deserialize<'de> for ArtifactContracts<T> {
304 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
305 where
306 D: Deserializer<'de>,
307 {
308 Ok(Self(BTreeMap::<_, _>::deserialize(deserializer)?))
309 }
310}
311
312impl<T> Deref for ArtifactContracts<T> {
313 type Target = BTreeMap<ArtifactId, T>;
314
315 fn deref(&self) -> &Self::Target {
316 &self.0
317 }
318}
319
320impl<T> DerefMut for ArtifactContracts<T> {
321 fn deref_mut(&mut self) -> &mut Self::Target {
322 &mut self.0
323 }
324}
325
326impl<V, C: Into<V>> FromIterator<(ArtifactId, C)> for ArtifactContracts<V> {
327 fn from_iter<T: IntoIterator<Item = (ArtifactId, C)>>(iter: T) -> Self {
328 Self(iter.into_iter().map(|(k, v)| (k, v.into())).collect())
329 }
330}
331
332impl<T> IntoIterator for ArtifactContracts<T> {
333 type Item = (ArtifactId, T);
334 type IntoIter = std::collections::btree_map::IntoIter<ArtifactId, T>;
335
336 fn into_iter(self) -> Self::IntoIter {
337 self.0.into_iter()
338 }
339}