_ctypes pt. 4 (#5582) · RustPython/RustPython@01d470f · GitHub
Skip to content

Commit 01d470f

Browse files
authored
_ctypes pt. 4 (#5582)
* correct error type when symbol is not found * restype get/set * base of PyCSimple for PyCArray * PyCSimple::to_arg * par down ctypes * nt._LOAD_LIBRARY_SEARCH_DEFAULT_DIRS * arguments for ctypes function * force failure to import ctypes
1 parent 9779de9 commit 01d470f

7 files changed

Lines changed: 368 additions & 29 deletions

File tree

Lib/ctypes/__init__.py

Lines changed: 16 additions & 7 deletions

extra_tests/snippets/builtins_ctypes.py

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,16 @@ def create_string_buffer(init, size=None):
3333
if size is None:
3434
size = len(init)+1
3535
_sys.audit("ctypes.create_string_buffer", init, size)
36-
buftype = c_char * size
36+
buftype = c_char.__mul__(size)
37+
print(type(c_char.__mul__(size)))
38+
# buftype = c_char * size
3739
buf = buftype()
3840
buf.value = init
3941
return buf
4042
elif isinstance(init, int):
4143
_sys.audit("ctypes.create_string_buffer", None, init)
42-
buftype = c_char * init
44+
buftype = c_char.__mul__(init)
45+
# buftype = c_char * init
4346
buf = buftype()
4447
return buf
4548
raise TypeError(init)
@@ -260,8 +263,62 @@ def LoadLibrary(self, name):
260263

261264
cdll = LibraryLoader(CDLL)
262265

266+
test_byte_array = create_string_buffer(b"Hello, World!\n")
267+
assert test_byte_array._length_ == 15
268+
263269
if _os.name == "posix" or _sys.platform == "darwin":
264270
pass
265271
else:
272+
import os
273+
266274
libc = cdll.msvcrt
267-
print("rand", libc.rand())
275+
libc.rand()
276+
i = c_int(1)
277+
print("start srand")
278+
print(libc.srand(i))
279+
print(test_byte_array)
280+
print(test_byte_array._type_)
281+
# print("start printf")
282+
# libc.printf(test_byte_array)
283+
284+
# windows pip support
285+
286+
def get_win_folder_via_ctypes(csidl_name: str) -> str:
287+
"""Get folder with ctypes."""
288+
# There is no 'CSIDL_DOWNLOADS'.
289+
# Use 'CSIDL_PROFILE' (40) and append the default folder 'Downloads' instead.
290+
# https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid
291+
292+
import ctypes # noqa: PLC0415
293+
294+
csidl_const = {
295+
"CSIDL_APPDATA": 26,
296+
"CSIDL_COMMON_APPDATA": 35,
297+
"CSIDL_LOCAL_APPDATA": 28,
298+
"CSIDL_PERSONAL": 5,
299+
"CSIDL_MYPICTURES": 39,
300+
"CSIDL_MYVIDEO": 14,
301+
"CSIDL_MYMUSIC": 13,
302+
"CSIDL_DOWNLOADS": 40,
303+
"CSIDL_DESKTOPDIRECTORY": 16,
304+
}.get(csidl_name)
305+
if csidl_const is None:
306+
msg = f"Unknown CSIDL name: {csidl_name}"
307+
raise ValueError(msg)
308+
309+
buf = ctypes.create_unicode_buffer(1024)
310+
windll = getattr(ctypes, "windll") # noqa: B009 # using getattr to avoid false positive with mypy type checker
311+
windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf)
312+
313+
# Downgrade to short path name if it has high-bit chars.
314+
if any(ord(c) > 255 for c in buf): # noqa: PLR2004
315+
buf2 = ctypes.create_unicode_buffer(1024)
316+
if windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024):
317+
buf = buf2
318+
319+
if csidl_name == "CSIDL_DOWNLOADS":
320+
return os.path.join(buf.value, "Downloads") # noqa: PTH118
321+
322+
return buf.value
323+
324+
# print(get_win_folder_via_ctypes("CSIDL_DOWNLOADS"))

vm/src/stdlib/ctypes.rs

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub fn extend_module_nodes(vm: &VirtualMachine, module: &Py<PyModule>) {
1717
extend_module!(vm, module, {
1818
"_CData" => PyCData::make_class(ctx),
1919
"_SimpleCData" => PyCSimple::make_class(ctx),
20+
"ArrayType" => array::PyCArrayType::make_class(ctx),
2021
"Array" => array::PyCArray::make_class(ctx),
2122
"CFuncPtr" => function::PyCFuncPtr::make_class(ctx),
2223
"_Pointer" => pointer::PyCPointer::make_class(ctx),
@@ -37,7 +38,7 @@ pub(crate) mod _ctypes {
3738
use super::base::PyCSimple;
3839
use crate::builtins::PyTypeRef;
3940
use crate::class::StaticType;
40-
use crate::function::{Either, OptionalArg};
41+
use crate::function::{Either, FuncArgs, OptionalArg};
4142
use crate::stdlib::ctypes::library;
4243
use crate::{AsObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine};
4344
use crossbeam_utils::atomic::AtomicCell;
@@ -124,11 +125,12 @@ pub(crate) mod _ctypes {
124125
"d" | "g" => mem::size_of::<c_double>(),
125126
"?" | "B" => mem::size_of::<c_uchar>(),
126127
"P" | "z" | "Z" => mem::size_of::<usize>(),
128+
"O" => mem::size_of::<PyObjectRef>(),
127129
_ => unreachable!(),
128130
}
129131
}
130132

131-
const SIMPLE_TYPE_CHARS: &str = "cbBhHiIlLdfguzZPqQ?";
133+
const SIMPLE_TYPE_CHARS: &str = "cbBhHiIlLdfguzZPqQ?O";
132134

133135
pub fn new_simple_type(
134136
cls: Either<&PyObjectRef, &PyTypeRef>,
@@ -218,9 +220,14 @@ pub(crate) mod _ctypes {
218220
#[pyfunction(name = "POINTER")]
219221
pub fn pointer(_cls: PyTypeRef) {}
220222

221-
#[pyfunction]
223+
#[pyfunction(name = "pointer")]
222224
pub fn pointer_fn(_inst: PyObjectRef) {}
223225

226+
#[pyfunction]
227+
fn _pointer_type_cache() -> PyObjectRef {
228+
todo!()
229+
}
230+
224231
#[cfg(target_os = "windows")]
225232
#[pyfunction(name = "_check_HRESULT")]
226233
pub fn check_hresult(_self: PyObjectRef, hr: i32, _vm: &VirtualMachine) -> PyResult<i32> {
@@ -243,6 +250,24 @@ pub(crate) mod _ctypes {
243250
}
244251
}
245252

253+
#[pyfunction]
254+
fn byref(_args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
255+
// TODO: RUSTPYTHON
256+
Err(vm.new_value_error("not implemented".to_string()))
257+
}
258+
259+
#[pyfunction]
260+
fn alignment(_args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
261+
// TODO: RUSTPYTHON
262+
Err(vm.new_value_error("not implemented".to_string()))
263+
}
264+
265+
#[pyfunction]
266+
fn resize(_args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
267+
// TODO: RUSTPYTHON
268+
Err(vm.new_value_error("not implemented".to_string()))
269+
}
270+
246271
#[pyfunction]
247272
fn get_errno() -> i32 {
248273
errno::errno().0
@@ -252,4 +277,41 @@ pub(crate) mod _ctypes {
252277
fn set_errno(value: i32) {
253278
errno::set_errno(errno::Errno(value));
254279
}
280+
281+
#[cfg(windows)]
282+
#[pyfunction]
283+
fn get_last_error() -> PyResult<u32> {
284+
Ok(unsafe { windows_sys::Win32::Foundation::GetLastError() })
285+
}
286+
287+
#[cfg(windows)]
288+
#[pyfunction]
289+
fn set_last_error(value: u32) -> PyResult<()> {
290+
unsafe { windows_sys::Win32::Foundation::SetLastError(value) };
291+
Ok(())
292+
}
293+
294+
#[pyattr]
295+
fn _memmove_addr(_vm: &VirtualMachine) -> usize {
296+
let f = libc::memmove;
297+
f as usize
298+
}
299+
300+
#[pyattr]
301+
fn _memset_addr(_vm: &VirtualMachine) -> usize {
302+
let f = libc::memset;
303+
f as usize
304+
}
305+
306+
#[pyattr]
307+
fn _string_at_addr(_vm: &VirtualMachine) -> usize {
308+
let f = libc::strnlen;
309+
f as usize
310+
}
311+
312+
#[pyattr]
313+
fn _cast_addr(_vm: &VirtualMachine) -> usize {
314+
// TODO: RUSTPYTHON
315+
0
316+
}
255317
}

vm/src/stdlib/ctypes/array.rs

Lines changed: 106 additions & 4 deletions

0 commit comments

Comments
 (0)