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