1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// Code is copied and modified from the original source code: https://github.com/apache/incubator-opendal/blob/main/bindings/python/src/utils.rs
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use std::os::raw::c_int;

use pyo3::ffi;
use pyo3::prelude::*;

pub(crate) const INLINED_U8: usize = 64;

pub type Bytes = smallvec::SmallVec<[u8; INLINED_U8]>;

/// A bytes-like object that implements buffer protocol.
#[pyclass]
pub struct Buffer(Bytes);

impl From<Bytes> for Buffer {
  fn from(inner: Bytes) -> Self {
    Buffer(inner)
  }
}

impl From<Vec<u8>> for Buffer {
  fn from(inner: Vec<u8>) -> Self {
    Buffer(inner.into())
  }
}

impl From<&[u8]> for Buffer {
  fn from(inner: &[u8]) -> Self {
    Buffer(inner.into())
  }
}

impl From<&str> for Buffer {
  fn from(inner: &str) -> Self {
    Buffer(inner.as_bytes().into())
  }
}

impl From<String> for Buffer {
  fn from(inner: String) -> Self {
    Buffer(inner.into_bytes().into())
  }
}

impl From<Buffer> for Bytes {
  fn from(buffer: Buffer) -> Self {
    buffer.0
  }
}

impl Buffer {
  pub fn new(inner: Bytes) -> Self {
    Buffer(inner)
  }

  /// Consume self to build a memory view
  pub fn into_memory_view(self, py: Python) -> PyResult<Py<PyAny>> {
    let buffer = self.into_py(py);

    unsafe { PyObject::from_owned_ptr_or_err(py, ffi::PyMemoryView_FromObject(buffer.as_ptr())) }
  }

  /// Consume self to build a memory view ref.
  pub fn into_memory_view_ref(self, py: Python) -> PyResult<&PyAny> {
    let buffer = self.into_py(py);
    let view = unsafe { py.from_owned_ptr_or_err(ffi::PyMemoryView_FromObject(buffer.as_ptr()))? };

    Ok(view)
  }
}

#[pymethods]
impl Buffer {
  unsafe fn __getbuffer__(
    slf: PyRefMut<Self>,
    view: *mut ffi::Py_buffer,
    flags: c_int,
  ) -> PyResult<()> {
    let bytes = slf.0.as_slice();
    let ret = ffi::PyBuffer_FillInfo(
      view,
      slf.as_ptr() as *mut _,
      bytes.as_ptr() as *mut _,
      bytes.len().try_into().unwrap(),
      1, // read only
      flags,
    );
    if ret == -1 {
      return Err(PyErr::fetch(slf.py()));
    }
    Ok(())
  }
}