Repository navigation
Expand file tree
/
Copy pathbytearrayobject.rs
More file actions
127 lines (113 loc) · 3.8 KB
/
Copy pathbytearrayobject.rs
File metadata and controls
127 lines (113 loc) · 3.8 KB
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use crate::PyObject;
use crate::object::define_py_check;
use crate::pystate::with_vm;
use core::ffi::c_char;
use rustpython_vm::builtins::PyByteArray;
use rustpython_vm::byte::bytes_from_object;
define_py_check!(fn PyByteArray_Check, types.bytearray_type);
/// # Safety
///
/// If `bytes` is `NULL`, the returned bytearray may contain uninitialized
/// bytes. The caller is responsible for initializing all bytes before any read.
#[unsafe(no_mangle)]
#[allow(clippy::uninit_vec)]
pub unsafe extern "C" fn PyByteArray_FromStringAndSize(
bytes: *const c_char,
len: isize,
) -> *mut PyObject {
with_vm(|vm| {
let len: usize = len.try_into().map_err(|_| {
vm.new_system_error("Negative size passed to PyByteArray_FromStringAndSize")
})?;
let data = if bytes.is_null() {
let mut data = Vec::with_capacity(len);
// SAFETY: `bytes == NULL` follows CPython semantics here; caller must
// initialize all bytes before any read. We keep this behavior for C-API
// compatibility and to avoid unnecessary zero-initialization overhead.
unsafe { data.set_len(len) };
data
} else {
unsafe { core::slice::from_raw_parts(bytes.cast::<u8>(), len) }.to_vec()
};
Ok(vm.ctx.new_bytearray(data))
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn PyByteArray_FromObject(obj: *mut PyObject) -> *mut PyObject {
with_vm(|vm| {
let obj = unsafe { &*obj };
let data = bytes_from_object(vm, obj)?;
Ok(vm.ctx.new_bytearray(data))
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn PyByteArray_Size(bytearray: *mut PyObject) -> isize {
with_vm(|vm| {
let bytearray = unsafe { &*bytearray }.try_downcast_ref::<PyByteArray>(vm)?;
Ok(bytearray.borrow_buf().len())
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn PyByteArray_AsString(bytearray: *mut PyObject) -> *mut c_char {
with_vm(|vm| {
let bytearray = unsafe { &*bytearray }.try_downcast_ref::<PyByteArray>(vm)?;
Ok(bytearray.borrow_buf_mut().as_mut_ptr())
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn PyByteArray_Resize(bytearray: *mut PyObject, len: isize) -> i32 {
with_vm(|vm| {
let bytearray = unsafe { &*bytearray }.try_downcast_ref::<PyByteArray>(vm)?;
bytearray.resize(len, vm)?;
Ok(())
})
}
#[cfg(test)]
mod tests {
use pyo3::prelude::*;
use pyo3::types::{PyByteArray, PyBytes};
#[test]
fn bytearray_size() {
Python::attach(|py| {
let bytearray = PyByteArray::new(py, b"abc");
assert_eq!(bytearray.len(), 3);
})
}
#[test]
fn bytearray_resize() {
Python::attach(|py| {
let bytearray = PyByteArray::new(py, b"abcde");
bytearray.resize(3).unwrap();
assert_eq!(bytearray.len(), 3);
assert_eq!(bytearray.to_vec(), b"abc");
})
}
#[test]
fn bytearray_from_string_and_size() {
Python::attach(|py| {
let bytearray = PyByteArray::new(py, b"hello");
assert_eq!(bytearray.len(), 5);
assert_eq!(bytearray.to_vec(), b"hello");
})
}
#[test]
fn bytearray_new_with_zero_initialized() {
Python::attach(|py| {
let bytearray = PyByteArray::new_with(py, 4, |bytes| {
bytes[..2].copy_from_slice(b"hi");
Ok(())
})
.unwrap();
assert_eq!(bytearray.len(), 4);
assert_eq!(bytearray.to_vec(), b"hi\0\0");
})
}
#[test]
fn bytearray_from_object() {
Python::attach(|py| {
let source = PyBytes::new(py, b"ABC");
let bytearray = PyByteArray::from(&source).unwrap();
assert_eq!(bytearray.to_vec(), b"ABC");
})
}
}