From 2aa4a82499d4becd2284cdb482213d541b8804dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 16:29:10 +0200 Subject: Adding upstream version 86.0.1. Signed-off-by: Daniel Baumann --- .../rust/lucet-module-wasmsbx/src/bindings.rs | 203 +++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 third_party/rust/lucet-module-wasmsbx/src/bindings.rs (limited to 'third_party/rust/lucet-module-wasmsbx/src/bindings.rs') 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>, +} + +impl Bindings { + pub fn new(bindings: HashMap>) -> Bindings { + Self { bindings: bindings } + } + + pub fn env(env: HashMap) -> 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 { + 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 { + let top: Value = serde_json::from_str(s)?; + Ok(Self::from_json(&top)?) + } + + pub fn from_file>(path: P) -> Result { + 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) -> Result { + 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) -> Result, 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 { + 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 { + 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) -> Map { + 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" + ); + } +} -- cgit v1.2.3