diff --git a/ethers-solc/src/artifacts/output_selection.rs b/ethers-solc/src/artifacts/output_selection.rs index 21a169b6..b5546350 100644 --- a/ethers-solc/src/artifacts/output_selection.rs +++ b/ethers-solc/src/artifacts/output_selection.rs @@ -1,6 +1,6 @@ //! bindings for standard json output selection -use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use serde::{ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer}; use std::{collections::BTreeMap, fmt, str::FromStr}; /// Represents the desired outputs based on a File `(file -> (contract -> [outputs]))` @@ -68,7 +68,7 @@ pub type FileOutputSelection = BTreeMap>; /// } /// } /// ``` -#[derive(Debug, Clone, Eq, PartialEq, Default, Serialize, Deserialize)] +#[derive(Debug, Clone, Eq, PartialEq, Default, Deserialize)] #[serde(transparent)] pub struct OutputSelection(pub BTreeMap); @@ -121,6 +121,39 @@ impl OutputSelection { } } +// this will make sure that if the `FileOutputSelection` for a certain file is empty will be +// serializes as `"*" : []` because +// > Contract level (needs the contract name or "*") +impl Serialize for OutputSelection { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + struct EmptyFileOutput; + + impl Serialize for EmptyFileOutput { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut map = serializer.serialize_map(Some(1))?; + map.serialize_entry("*", &[] as &[String])?; + map.end() + } + } + + let mut map = serializer.serialize_map(Some(self.0.len()))?; + for (file, selection) in self.0.iter() { + if selection.is_empty() { + map.serialize_entry(file, &EmptyFileOutput {})?; + } else { + map.serialize_entry(file, selection)?; + } + } + map.end() + } +} + impl AsRef> for OutputSelection { fn as_ref(&self) -> &BTreeMap { &self.0 @@ -532,4 +565,12 @@ mod tests { assert_eq!(json, serde_json::to_string(&deserde_selection).unwrap()); } + + #[test] + fn empty_outputselection_serde_works() { + let mut empty = OutputSelection::default(); + empty.0.insert("contract.sol".to_string(), OutputSelection::empty_file_output_select()); + let s = serde_json::to_string(&empty).unwrap(); + assert_eq!(s, r#"{"contract.sol":{"*":[]}}"#); + } }