diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/lucet-module-wasmsbx/src/bindings.rs | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/lucet-module-wasmsbx/src/bindings.rs')
-rw-r--r-- | third_party/rust/lucet-module-wasmsbx/src/bindings.rs | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/third_party/rust/lucet-module-wasmsbx/src/bindings.rs b/third_party/rust/lucet-module-wasmsbx/src/bindings.rs new file mode 100644 index 0000000000..3c1dab3855 --- /dev/null +++ b/third_party/rust/lucet-module-wasmsbx/src/bindings.rs @@ -0,0 +1,203 @@ +use failure::{format_err, Error}; +use serde_json::{self, Map, Value}; +use std::collections::{hash_map::Entry, HashMap}; +use std::fs; +use std::path::Path; + +#[derive(Debug, Clone)] +pub struct Bindings { + bindings: HashMap<String, HashMap<String, String>>, +} + +impl Bindings { + pub fn new(bindings: HashMap<String, HashMap<String, String>>) -> Bindings { + Self { bindings: bindings } + } + + pub fn env(env: HashMap<String, String>) -> Bindings { + let mut bindings = HashMap::new(); + bindings.insert("env".to_owned(), env); + Self::new(bindings) + } + + pub fn empty() -> Bindings { + Self::new(HashMap::new()) + } + + pub fn from_json(v: &Value) -> Result<Bindings, Error> { + match v.as_object() { + Some(modules) => Self::parse_modules_json_obj(modules), + None => Err(format_err!("top level json expected to be object"))?, + } + } + + pub fn from_str(s: &str) -> Result<Bindings, Error> { + let top: Value = serde_json::from_str(s)?; + Ok(Self::from_json(&top)?) + } + + pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Bindings, Error> { + let contents = fs::read_to_string(path.as_ref())?; + Ok(Self::from_str(&contents)?) + } + + pub fn extend(&mut self, other: &Bindings) -> Result<(), Error> { + for (modname, othermodbindings) in other.bindings.iter() { + match self.bindings.entry(modname.clone()) { + Entry::Occupied(mut e) => { + let existing = e.get_mut(); + for (bindname, binding) in othermodbindings { + match existing.entry(bindname.clone()) { + Entry::Vacant(e) => { + e.insert(binding.clone()); + } + Entry::Occupied(e) => { + if binding != e.get() { + Err(format_err!( + "cannot re-bind {} from {} to {}", + e.key(), + binding, + e.get() + ))?; + } + } + } + } + } + Entry::Vacant(e) => { + e.insert(othermodbindings.clone()); + } + } + } + Ok(()) + } + + pub fn translate(&self, module: &str, symbol: &str) -> Result<&str, Error> { + match self.bindings.get(module) { + Some(m) => match m.get(symbol) { + Some(s) => Ok(s), + None => Err(format_err!("Unknown symbol `{}::{}`", module, symbol)), + }, + None => Err(format_err!( + "Unknown module for symbol `{}::{}`", + module, + symbol + )), + } + } + + fn parse_modules_json_obj(m: &Map<String, Value>) -> Result<Self, Error> { + let mut res = HashMap::new(); + for (modulename, values) in m { + match values.as_object() { + Some(methods) => { + let methodmap = Self::parse_methods_json_obj(methods)?; + res.insert(modulename.to_owned(), methodmap); + } + None => Err(format_err!(""))?, + } + } + Ok(Self::new(res)) + } + + fn parse_methods_json_obj(m: &Map<String, Value>) -> Result<HashMap<String, String>, Error> { + let mut res = HashMap::new(); + for (method, i) in m { + match i.as_str() { + Some(importbinding) => { + res.insert(method.to_owned(), importbinding.to_owned()); + } + None => Err(format_err!(""))?, + } + } + Ok(res) + } + + pub fn to_string(&self) -> Result<String, Error> { + let s = serde_json::to_string(&self.to_json())?; + Ok(s) + } + + pub fn to_json(&self) -> Value { + Value::from(self.serialize_modules_json_obj()) + } + + fn serialize_modules_json_obj(&self) -> Map<String, Value> { + let mut m = Map::new(); + for (modulename, values) in self.bindings.iter() { + m.insert( + modulename.to_owned(), + Value::from(Self::serialize_methods_json_obj(values)), + ); + } + m + } + + fn serialize_methods_json_obj(methods: &HashMap<String, String>) -> Map<String, Value> { + let mut m = Map::new(); + for (methodname, symbol) in methods.iter() { + m.insert(methodname.to_owned(), Value::from(symbol.to_owned())); + } + m + } +} + +#[cfg(test)] +mod tests { + fn test_file(f: &str) -> PathBuf { + PathBuf::from(format!("tests/bindings/{}", f)) + } + + use super::Bindings; + use std::collections::HashMap; + use std::path::PathBuf; + + #[test] + fn explicit() { + let mut explicit_map = HashMap::new(); + explicit_map.insert(String::from("hello"), String::from("goodbye")); + let map = Bindings::env(explicit_map); + + let result = map.translate("env", "hello").unwrap(); + assert!(result == "goodbye"); + + let result = map.translate("env", "nonexistent"); + if let Ok(_) = result { + assert!( + false, + "explicit import map returned value for non-existent symbol" + ) + } + } + + #[test] + fn explicit_from_nonexistent_file() { + let fail_map = Bindings::from_file(&test_file("nonexistent_bindings.json")); + assert!( + fail_map.is_err(), + "ImportMap::explicit_from_file did not fail on a non-existent file" + ); + } + + #[test] + fn explicit_from_garbage_file() { + let fail_map = Bindings::from_file(&test_file("garbage.json")); + assert!( + fail_map.is_err(), + "ImportMap::explicit_from_file did not fail on a garbage file" + ); + } + + #[test] + fn explicit_from_file() { + let map = Bindings::from_file(&test_file("bindings_test.json")) + .expect("load valid bindings from file"); + let result = map.translate("env", "hello").expect("hello has a binding"); + assert!(result == "json is cool"); + + assert!( + map.translate("env", "nonexistent").is_err(), + "bindings from file returned value for non-existent symbol" + ); + } +} |