diff --git a/Cargo.toml b/Cargo.toml index 32d0fcf..b1c67bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ license = "MIT/Apache-2.0" exclude = [".gitignore", "builder", "examples"] [dependencies] +serde = "1.0" serde_json = "1.0" cpython = { version = "0.1", default-features = false } cpython-json = { version = "0.2", default-features = false } diff --git a/src/lib.rs b/src/lib.rs index 1c39afb..e9a96a0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,12 +66,13 @@ extern crate cpython; extern crate cpython_json; extern crate serde_json; +extern crate serde; #[doc(hidden)] pub use cpython::{PyResult, PyObject}; pub use serde_json::value::Value; -/// Result object that accepts `Ok(Value)` or any `Err(Error)`. +/// Result object that accepts `Ok(T)` or any `Err(Error)`. /// /// crowbar uses [the `Box` method of error handling] /// (https://doc.rust-lang.org/stable/book/error-handling.html#error-handling-with-boxerror) so @@ -79,7 +80,7 @@ pub use serde_json::value::Value; /// /// If an error is thrown, it is converted to a Python `RuntimeError`, and the `Debug` string for /// the `Error` returned is used as the value. -pub type LambdaResult = Result>; +pub type LambdaResult = Result>; use cpython::{Python, PyUnicode, PyTuple, PyErr, PythonObject, PythonObjectWithTypeObject, ObjectProtocol}; @@ -217,21 +218,22 @@ impl std::error::Error for ContextError { } #[doc(hidden)] -pub fn handler(py: Python, f: F, py_event: PyObject, py_context: PyObject) -> PyResult - where F: Fn(Value, LambdaContext) -> LambdaResult +pub fn handler(py: Python, f: F, py_event: PyObject, py_context: PyObject) -> PyResult + where F: FnOnce(Value, LambdaContext) -> LambdaResult, + O: serde::Serialize { - let event = to_json(py, &py_event).or_else(|e| Err(e.to_pyerr(py)))?; - let result = match f(event, LambdaContext::new(&py, &py_context)?) { - Ok(r) => r, - Err(e) => { - return Err(PyErr { - ptype: cpython::exc::RuntimeError::type_object(py).into_object(), - pvalue: Some(PyUnicode::new(py, &format!("{:?}", e)).into_object()), - ptraceback: None, - }) - } - }; - from_json(py, result).or_else(|e| Err(e.to_pyerr(py))) + let event = to_json(py, &py_event).map_err(|e| e.to_pyerr(py))?; + f(event, LambdaContext::new(&py, &py_context)?) + .map_err(|e| PyErr { + ptype: cpython::exc::RuntimeError::type_object(py).into_object(), + pvalue: Some(PyUnicode::new(py, &format!("{:?}", e)).into_object()), + ptraceback: None, + }).and_then(|v| serde_json::value::to_value(v) + .map_err(cpython_json::JsonError::SerdeJsonError) + .map_err(|e| e.to_pyerr(py)) + ).and_then(|v| from_json(py, v) + .map_err(|e| e.to_pyerr(py)) + ) } #[macro_export]