diff --git a/rust/hg-cpython/src/utils.rs b/rust/hg-cpython/src/utils.rs --- a/rust/hg-cpython/src/utils.rs +++ b/rust/hg-cpython/src/utils.rs @@ -1,4 +1,7 @@ -use cpython::{PyDict, PyObject, PyResult, PyTuple, Python}; +use cpython::exc::ValueError; +use cpython::{PyBytes, PyDict, PyErr, PyObject, PyResult, PyTuple, Python}; +use hg::revlog::Node; +use std::convert::TryFrom; #[allow(unused)] pub fn print_python_trace(py: Python) -> PyResult { @@ -11,3 +14,34 @@ kwargs.set_item(py, "file", sys.get(py, "stderr")?)?; traceback.call(py, "print_stack", PyTuple::new(py, &[]), Some(&kwargs)) } + +// Necessary evil for the time being, could maybe be moved to +// a TryFrom in Node itself +const NODE_BYTES_LENGTH: usize = 20; +type NodeData = [u8; NODE_BYTES_LENGTH]; + +/// Copy incoming Python bytes given as `PyObject` into `Node`, +/// doing the necessary checks +pub fn node_from_py_object<'a>( + py: Python, + bytes: &'a PyObject, +) -> PyResult { + let as_py_bytes: &'a PyBytes = bytes.extract(py)?; + node_from_py_bytes(py, as_py_bytes) +} + +/// Clone incoming Python bytes given as `PyBytes` as a `Node`, +/// doing the necessary checks. +pub fn node_from_py_bytes<'a>( + py: Python, + bytes: &'a PyBytes, +) -> PyResult { + ::try_from(bytes.data(py)) + .map_err(|_| { + PyErr::new::( + py, + format!("{}-byte hash required", NODE_BYTES_LENGTH), + ) + }) + .map(|n| n.into()) +}