meplang 0.1.8

An EVM low-level language that gives full control over the control flow of the smart contract.
Documentation
use std::collections::HashMap;

use bytes::Bytes;
use serde::ser::SerializeMap;
use serde::{Deserialize, Deserializer, Serialize, Serializer};

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields, rename_all = "camelCase")]
pub struct CompilerSettings {
    #[serde(default = "bool_true")]
    pub push0: bool,
    #[serde(default)]
    pub filling_pattern: FillingPatern,
    #[serde(
        default,
        serialize_with = "serialize_variables",
        deserialize_with = "deserialize_variables"
    )]
    pub variables: HashMap<String, Bytes>,
}

impl Default for CompilerSettings {
    fn default() -> Self {
        Self {
            push0: true,
            filling_pattern: FillingPatern::default(),
            variables: HashMap::default(),
        }
    }
}

impl CompilerSettings {
    pub fn add_variable(&mut self, name: &str, value: Bytes) {
        self.variables.insert(name.to_owned(), value);
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields, rename_all = "camelCase")]
pub enum FillingPatern {
    Random,
    #[serde(serialize_with = "serialize_bytes", deserialize_with = "deserialize_bytes")]
    Repeat(Bytes),
}

impl Default for FillingPatern {
    fn default() -> Self {
        Self::Repeat(vec![0x00u8].into())
    }
}

pub fn serialize_bytes<S, T>(x: T, s: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,
    T: AsRef<[u8]>,
{
    s.serialize_str(&format!("0x{}", hex::encode(x.as_ref())))
}

pub fn deserialize_bytes<'de, D>(d: D) -> Result<Bytes, D::Error>
where
    D: Deserializer<'de>,
{
    let value = String::deserialize(d)?;
    if let Some(value) = value.strip_prefix("0x") {
        hex::decode(value)
    } else {
        hex::decode(&value)
    }
    .map(Into::into)
    .map_err(|e| serde::de::Error::custom(e.to_string()))
}

fn serialize_variables<S>(x: &HashMap<String, Bytes>, s: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    let mut map = s.serialize_map(Some(x.len()))?;
    for (k, v) in x.iter() {
        map.serialize_entry(k, &format!("0x{}", hex::encode(v)))?;
    }
    map.end()
}

fn deserialize_variables<'de, D>(d: D) -> Result<HashMap<String, Bytes>, D::Error>
where
    D: Deserializer<'de>,
{
    let des: HashMap<String, String> = Deserialize::deserialize(d)?;
    let mut res = HashMap::<String, Bytes>::with_capacity(des.len());
    for (k, v) in des {
        let value = if let Some(v) = v.strip_prefix("0x") {
            hex::decode(v)
        } else {
            hex::decode(&v)
        }
        .map(Into::into)
        .map_err(|e| serde::de::Error::custom(e.to_string()))?;
        res.insert(k, value);
    }
    Ok(res)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    pub fn test_serialize() {
        let settings: CompilerSettings =
            serde_json::from_str("{\"push0\": true, \"fillingPattern\": {\"repeat\": \"0x11\"}}").unwrap();
        dbg!(&settings);
    }
}

fn bool_true() -> bool {
    true
}