use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ErrorSignature {
pub name: String,
pub signature: String,
pub selector: [u8; 4],
pub inputs: Vec<ErrorParam>,
pub source: String,
pub suggestion: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ErrorParam {
pub name: String,
pub ty: String,
}
pub trait ErrorSignatureRegistry: Send + Sync {
fn get_by_selector(&self, selector: [u8; 4]) -> Vec<ErrorSignature>;
fn get_by_name(&self, name: &str) -> Option<ErrorSignature>;
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
}
use std::collections::HashMap;
use std::sync::RwLock;
pub struct MemoryErrorRegistry {
by_selector: RwLock<HashMap<[u8; 4], Vec<ErrorSignature>>>,
by_name: RwLock<HashMap<String, ErrorSignature>>,
}
impl MemoryErrorRegistry {
pub fn new() -> Self {
Self {
by_selector: RwLock::new(HashMap::new()),
by_name: RwLock::new(HashMap::new()),
}
}
pub fn register(&self, sig: ErrorSignature) {
let mut by_sel = self.by_selector.write().unwrap();
by_sel.entry(sig.selector).or_default().push(sig.clone());
let mut by_name = self.by_name.write().unwrap();
by_name.entry(sig.name.clone()).or_insert(sig);
}
pub fn load_json(&self, json: &str) -> Result<usize, serde_json::Error> {
let sigs: Vec<ErrorSignature> = serde_json::from_str(json)?;
let count = sigs.len();
for sig in sigs {
self.register(sig);
}
Ok(count)
}
}
impl Default for MemoryErrorRegistry {
fn default() -> Self {
Self::new()
}
}
impl ErrorSignatureRegistry for MemoryErrorRegistry {
fn get_by_selector(&self, selector: [u8; 4]) -> Vec<ErrorSignature> {
self.by_selector
.read()
.unwrap()
.get(&selector)
.cloned()
.unwrap_or_default()
}
fn get_by_name(&self, name: &str) -> Option<ErrorSignature> {
self.by_name.read().unwrap().get(name).cloned()
}
fn len(&self) -> usize {
self.by_selector.read().unwrap().values().map(|v| v.len()).sum()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn make_sig(name: &str, sig_str: &str, selector: [u8; 4]) -> ErrorSignature {
ErrorSignature {
name: name.to_string(),
signature: sig_str.to_string(),
selector,
inputs: vec![],
source: "test".to_string(),
suggestion: None,
}
}
#[test]
fn register_and_lookup() {
let reg = MemoryErrorRegistry::new();
let selector = [0x08, 0xc3, 0x79, 0xa0];
reg.register(make_sig("Error", "Error(string)", selector));
let results = reg.get_by_selector(selector);
assert_eq!(results.len(), 1);
assert_eq!(results[0].name, "Error");
}
#[test]
fn lookup_by_name() {
let reg = MemoryErrorRegistry::new();
reg.register(make_sig("Foo", "Foo(uint256)", [0x00, 0x00, 0x00, 0x01]));
assert!(reg.get_by_name("Foo").is_some());
assert!(reg.get_by_name("Bar").is_none());
}
#[test]
fn load_json_empty_array() {
let reg = MemoryErrorRegistry::new();
let count = reg.load_json("[]").unwrap();
assert_eq!(count, 0);
assert!(reg.is_empty());
}
}