diff --git a/.gitignore b/.gitignore index 81c1a16d62..7bdb2237b4 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,9 @@ tests/lenses/rust_wasm32_remove/pkg tests/lenses/rust_wasm32_copy/Cargo.lock tests/lenses/rust_wasm32_copy/target tests/lenses/rust_wasm32_copy/pkg +tests/lenses/rust_wasm32_prepend/Cargo.lock +tests/lenses/rust_wasm32_prepend/target +tests/lenses/rust_wasm32_prepend/pkg # Ignore OS X metadata files. .history diff --git a/tests/lenses/Makefile b/tests/lenses/Makefile index 7370a04b80..57807e10b2 100644 --- a/tests/lenses/Makefile +++ b/tests/lenses/Makefile @@ -2,3 +2,4 @@ build: cargo build --target wasm32-unknown-unknown --manifest-path "./rust_wasm32_set_default/Cargo.toml" cargo build --target wasm32-unknown-unknown --manifest-path "./rust_wasm32_remove/Cargo.toml" cargo build --target wasm32-unknown-unknown --manifest-path "./rust_wasm32_copy/Cargo.toml" + cargo build --target wasm32-unknown-unknown --manifest-path "./rust_wasm32_prepend/Cargo.toml" diff --git a/tests/lenses/rust_wasm32_prepend/Cargo.toml b/tests/lenses/rust_wasm32_prepend/Cargo.toml new file mode 100644 index 0000000000..7038a68b9c --- /dev/null +++ b/tests/lenses/rust_wasm32_prepend/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "rust-wasm32-prepend" +version = "0.1.0" +edition = "2018" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0.87" +lens_sdk = "^0.5" diff --git a/tests/lenses/rust_wasm32_prepend/src/lib.rs b/tests/lenses/rust_wasm32_prepend/src/lib.rs new file mode 100644 index 0000000000..30dcab58f8 --- /dev/null +++ b/tests/lenses/rust_wasm32_prepend/src/lib.rs @@ -0,0 +1,111 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +use std::collections::HashMap; +use std::sync::RwLock; +use std::error::Error; +use std::{fmt, error}; +use serde::Deserialize; +use lens_sdk::StreamOption; +use lens_sdk::option::StreamOption::{Some, None, EndOfStream}; + +#[link(wasm_import_module = "lens")] +extern "C" { + fn next() -> *mut u8; +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +enum ModuleError { + ParametersNotSetError, +} + +impl error::Error for ModuleError { } + +impl fmt::Display for ModuleError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match &*self { + ModuleError::ParametersNotSetError => f.write_str("Parameters have not been set."), + } + } +} + +#[derive(Deserialize, Clone)] +pub struct Parameters { + pub values: Vec>, +} + +static PARAMETERS: RwLock> = RwLock::new(None); +static PARAM_INDEX: RwLock = RwLock::new(0); + +#[no_mangle] +pub extern fn alloc(size: usize) -> *mut u8 { + lens_sdk::alloc(size) +} + +#[no_mangle] +pub extern fn set_param(ptr: *mut u8) -> *mut u8 { + match try_set_param(ptr) { + Ok(_) => lens_sdk::nil_ptr(), + Err(e) => lens_sdk::to_mem(lens_sdk::ERROR_TYPE_ID, &e.to_string().as_bytes()) + } +} + +fn try_set_param(ptr: *mut u8) -> Result<(), Box> { + let parameter = lens_sdk::try_from_mem::(ptr)? + .ok_or(ModuleError::ParametersNotSetError)? + .clone(); + + let mut dst = PARAMETERS.write()?; + *dst = Some(parameter); + Ok(()) +} + +#[no_mangle] +pub extern fn transform() -> *mut u8 { + match try_transform() { + Ok(o) => match o { + Some(result_json) => lens_sdk::to_mem(lens_sdk::JSON_TYPE_ID, &result_json), + None => lens_sdk::nil_ptr(), + EndOfStream => lens_sdk::to_mem(lens_sdk::EOS_TYPE_ID, &[]), + }, + Err(e) => lens_sdk::to_mem(lens_sdk::ERROR_TYPE_ID, &e.to_string().as_bytes()) + } +} + +fn try_transform() -> Result>, Box> { + let params = PARAMETERS.read()? + .clone() + .ok_or(ModuleError::ParametersNotSetError)? + .clone(); + + let param_index = PARAM_INDEX.read()? + .clone(); + + if param_index < params.values.len() { + let result = ¶ms.values[param_index]; + let result_json = serde_json::to_vec(&result)?; + + let mut dst = PARAM_INDEX.write()?; + *dst = param_index+1; + return Ok(Some(result_json)) + } + + // Note: The following is a very unperformant, but simple way of yielding the input documents, + // as this module is only used for testing, this is preferred. + + let ptr = unsafe { next() }; + let input = match lens_sdk::try_from_mem::>(ptr)? { + Some(v) => v, + // Implementations of `transform` are free to handle nil however they like. In this + // implementation we chose to return nil given a nil input. + None => return Ok(None), + EndOfStream => return Ok(EndOfStream) + }; + + let result = input.clone(); + + let result_json = serde_json::to_vec(&result)?; + lens_sdk::free_transport_buffer(ptr)?; + Ok(Some(result_json)) +} diff --git a/tests/lenses/utils.go b/tests/lenses/utils.go index 132c7d33c4..97619a6124 100644 --- a/tests/lenses/utils.go +++ b/tests/lenses/utils.go @@ -44,6 +44,15 @@ var CopyModulePath string = getPathRelativeToProjectRoot( "/tests/lenses/rust_wasm32_copy/target/wasm32-unknown-unknown/debug/rust_wasm32_copy.wasm", ) +// PrependModulePath is the path to the `Prepend` lens module compiled to wasm. +// +// The module has one parameter: +// - `values` is an array of `map[string]string`s, the module will yield these documents before +// any documents fed to it (from Defra). +var PrependModulePath string = getPathRelativeToProjectRoot( + "/tests/lenses/rust_wasm32_prepend/target/wasm32-unknown-unknown/debug/rust_wasm32_prepend.wasm", +) + func getPathRelativeToProjectRoot(relativePath string) string { _, filename, _, _ := runtime.Caller(0) root := path.Dir(path.Dir(path.Dir(filename)))