use std::collections::BTreeMap;
use std::collections::BTreeSet;
use serde::Deserialize;
use serde::Serialize;
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct Libraries {
#[serde(flatten)]
pub inner: BTreeMap<String, BTreeMap<String, String>>,
}
impl Libraries {
pub fn as_linker_symbols(
&self,
) -> anyhow::Result<BTreeMap<String, [u8; revive_common::BYTE_LENGTH_ETH_ADDRESS]>> {
let mut linker_symbols = BTreeMap::new();
for (file, contracts) in self.inner.iter() {
for (name, address) in contracts.iter() {
let path = format!("{file}:{name}");
let address_stripped = address.strip_prefix("0x").unwrap_or(address.as_str());
let address_vec = hex::decode(address_stripped).map_err(|error| {
anyhow::anyhow!("Invalid address `{address}` of library `{path}`: {error}.")
})?;
let address_array: [u8; revive_common::BYTE_LENGTH_ETH_ADDRESS] = address_vec.try_into().map_err(|address_vec: Vec<u8>| {
anyhow::anyhow!(
"Incorrect size of address `{address}` of library `{path}`: expected {}, found {}.",
revive_common::BYTE_LENGTH_ETH_ADDRESS,
address_vec.len(),
)
})?;
linker_symbols.insert(path, address_array);
}
}
Ok(linker_symbols)
}
pub fn as_paths(&self) -> BTreeSet<String> {
self.inner
.iter()
.flat_map(|(file, names)| {
names
.keys()
.map(|name| format!("{file}:{name}"))
.collect::<BTreeSet<String>>()
})
.collect::<BTreeSet<String>>()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn as_inner(&self) -> &BTreeMap<String, BTreeMap<String, String>> {
&self.inner
}
pub fn as_inner_mut(&mut self) -> &mut BTreeMap<String, BTreeMap<String, String>> {
&mut self.inner
}
}
impl From<BTreeMap<String, BTreeMap<String, String>>> for Libraries {
fn from(inner: BTreeMap<String, BTreeMap<String, String>>) -> Self {
Self { inner }
}
}
impl TryFrom<&[String]> for Libraries {
type Error = anyhow::Error;
fn try_from(arguments: &[String]) -> Result<Self, Self::Error> {
let mut libraries = BTreeMap::new();
for (index, library) in arguments.iter().enumerate() {
let mut path_and_address = library.split('=');
let path = path_and_address
.next()
.ok_or_else(|| anyhow::anyhow!("Library #{index} path is missing."))?;
let mut file_and_contract = path.split(':');
let file = file_and_contract
.next()
.ok_or_else(|| anyhow::anyhow!("Library `{path}` file name is missing."))?;
let contract = file_and_contract
.next()
.ok_or_else(|| anyhow::anyhow!("Library `{path}` contract name is missing."))?;
let address = path_and_address
.next()
.ok_or_else(|| anyhow::anyhow!("Library `{path}` address is missing."))?;
libraries
.entry(file.to_owned())
.or_insert_with(BTreeMap::new)
.insert(contract.to_owned(), address.to_owned());
}
Ok(Self { inner: libraries })
}
}