#![cfg(any(not(Py_LIMITED_API), Py_3_11))]

use pyo3::prelude::*;

/// Objects related to PyBuffer and PyStr
#[pymodule]
pub mod buf_and_str {
    use pyo3::buffer::PyBuffer;
    use pyo3::prelude::*;
    use pyo3::types::{PyBytes, PyMemoryView, PyString};
    use std::borrow::Cow;

    /// This is for confirming that PyBuffer does not cause memory leak
    #[pyclass]
    struct BytesExtractor {}

    #[pymethods]
    impl BytesExtractor {
        #[new]
        pub fn __new__() -> Self {
            BytesExtractor {}
        }

        #[staticmethod]
        pub fn from_bytes(bytes: &Bound<'_, PyBytes>) -> PyResult<usize> {
            let byte_vec: Vec<u8> = bytes.extract()?;
            Ok(byte_vec.len())
        }

        #[staticmethod]
        pub fn from_str(string: &Bound<'_, PyString>) -> PyResult<usize> {
            let rust_string: String = string.extract()?;
            Ok(rust_string.len())
        }

        #[staticmethod]
        pub fn from_str_lossy(string: &Bound<'_, PyString>) -> usize {
            let rust_string_lossy: String = string.to_string_lossy().to_string();
            rust_string_lossy.len()
        }

        #[staticmethod]
        pub fn from_buffer(buf: &Bound<'_, PyAny>) -> PyResult<usize> {
            let buf = PyBuffer::<u8>::get(buf)?;
            Ok(buf.item_count())
        }
    }

    #[pyfunction]
    fn return_memoryview(py: Python<'_>) -> PyResult<Bound<'_, PyMemoryView>> {
        let bytes = PyBytes::new(py, b"hello world");
        PyMemoryView::from(&bytes)
    }

    #[pyfunction]
    fn map_byte_slice(bytes: &[u8]) -> &[u8] {
        bytes
    }

    #[pyfunction]
    fn map_byte_cow(bytes: Cow<'_, [u8]>) -> Cow<'_, [u8]> {
        bytes
    }

    #[pyfunction]
    fn map_byte_vec(bytes: Vec<u8>) -> Vec<u8> {
        bytes
    }
}
