What do you think of adding httparse.parse
function, so the user doesn't have to create a parser instance? E.g.
#[pyfunction]
fn parse(buff: &PyBytes, py: Python<'_>) -> PyResult<Option<ParsedRequest>> {
...
}
The code pyo3
generates for the class method involves a few extra steps (working with PyCell
to get the RequestParser
instance), which should be slower than using a free-standing function. In my local experiments, I can observe this difference.
Method code
unsafe extern "C" fn __pymethod_parse__(
_slf: *mut _pyo3::ffi::PyObject,
_args: *mut _pyo3::ffi::PyObject,
_kwargs: *mut _pyo3::ffi::PyObject,
) -> *mut _pyo3::ffi::PyObject {
let gil = _pyo3::GILPool::new();
let _py = gil.python();
_pyo3::callback::panic_result_into_callback_output(
_py,
::std::panic::catch_unwind(move || -> _pyo3::PyResult<_> {
let _cell = _py
.from_borrowed_ptr::<_pyo3::PyAny>(_slf)
.downcast::<_pyo3::PyCell<RequestParser>>()?;
let mut _ref = _cell.try_borrow_mut()?;
let _slf: &mut RequestParser = &mut *_ref;
const DESCRIPTION: _pyo3::impl_::extract_argument::FunctionDescription =
_pyo3::impl_::extract_argument::FunctionDescription {
cls_name: ::std::option::Option::Some(
<RequestParser as _pyo3::type_object::PyTypeInfo>::NAME,
),
func_name: "parse",
positional_parameter_names: &["buff"],
positional_only_parameters: 0usize,
required_positional_parameters: 1usize,
keyword_only_parameters: &[],
};
let mut output = [::std::option::Option::None; 1usize];
let (_args, _kwargs) = DESCRIPTION.extract_arguments_tuple_dict::<_pyo3::impl_::extract_argument::NoVarargs, _pyo3::impl_::extract_argument::NoVarkeywords>(_py, _args, _kwargs, &mut output)?;
let mut ret = RequestParser::parse(
_slf,
_pyo3::impl_::extract_argument::extract_argument(
_pyo3::impl_::extract_argument::unwrap_required_argument(output[0usize]),
&mut { _pyo3::impl_::extract_argument::FunctionArgumentHolder::INIT },
"buff",
)?,
_py,
);
if false {
use _pyo3::impl_::ghost::IntoPyResult;
ret.assert_into_py_result();
}
_pyo3::callback::convert(_py, ret)
}),
)
}
Function code
unsafe extern "C" fn __pyfunction_parse(
_slf: *mut _pyo3::ffi::PyObject,
_args: *mut _pyo3::ffi::PyObject,
_kwargs: *mut _pyo3::ffi::PyObject,
) -> *mut _pyo3::ffi::PyObject {
let gil = _pyo3::GILPool::new();
let _py = gil.python();
_pyo3::callback::panic_result_into_callback_output(
_py,
::std::panic::catch_unwind(move || -> _pyo3::PyResult<_> {
const DESCRIPTION: _pyo3::impl_::extract_argument::FunctionDescription =
_pyo3::impl_::extract_argument::FunctionDescription {
cls_name: ::std::option::Option::None,
func_name: "parse",
positional_parameter_names: &["buff"],
positional_only_parameters: 0usize,
required_positional_parameters: 1usize,
keyword_only_parameters: &[],
};
let mut output = [::std::option::Option::None; 1usize];
let (_args, _kwargs) = DESCRIPTION.extract_arguments_tuple_dict::<_pyo3::impl_::extract_argument::NoVarargs, _pyo3::impl_::extract_argument::NoVarkeywords>(_py, _args, _kwargs, &mut output)?;
let mut ret = parse(
_pyo3::impl_::extract_argument::extract_argument(
_pyo3::impl_::extract_argument::unwrap_required_argument(output[0usize]),
&mut { _pyo3::impl_::extract_argument::FunctionArgumentHolder::INIT },
"buff",
)?,
_py,
);
if false {
use _pyo3::impl_::ghost::IntoPyResult;
ret.assert_into_py_result();
}
_pyo3::callback::convert(_py, ret)
}),
)
}
Though, the parser instance still could be helpful for cases if you'd like to pass some configuration to the httparse::Request::parse
call.
Let me know what you think about this possible API design approach :)