Skip to content

Consider adding parse as a free standing function  #4

@Stranger6667

Description

@Stranger6667

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 :)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions