1
1
use crate :: builtins:: { PyStr , PyTuple , PyTypeRef } ;
2
+ use crate :: class:: StaticType ;
3
+ use crate :: convert:: ToPyObject ;
4
+ use crate :: function:: FuncArgs ;
2
5
use crate :: stdlib:: ctypes:: PyCData ;
6
+ use crate :: stdlib:: ctypes:: base:: { PyCSimple , ffi_type_from_str} ;
3
7
use crate :: types:: { Callable , Constructor } ;
4
8
use crate :: { AsObject , Py , PyObjectRef , PyResult , VirtualMachine } ;
5
9
use crossbeam_utils:: atomic:: AtomicCell ;
6
- use std:: fmt:: Debug ;
7
- use crate :: class:: StaticType ;
8
- use crate :: stdlib:: ctypes:: base:: PyCSimple ;
9
10
use libffi:: middle:: { Arg , Cif , CodePtr , Type } ;
10
11
use libloading:: Symbol ;
11
12
use num_traits:: ToPrimitive ;
12
13
use rustpython_common:: lock:: PyRwLock ;
13
- use crate :: convert:: ToPyObject ;
14
- use crate :: function:: FuncArgs ;
15
- // https://github.com/python/cpython/blob/4f8bb3947cfbc20f970ff9d9531e1132a9e95396/Modules/_ctypes/callproc.c#L15
14
+ use std:: fmt:: Debug ;
16
15
16
+ // https://github.com/python/cpython/blob/4f8bb3947cfbc20f970ff9d9531e1132a9e95396/Modules/_ctypes/callproc.c#L15
17
17
18
18
#[ derive( Debug ) ]
19
19
pub struct Function {
20
20
// TODO: no protection from use-after-free
21
21
pointer : CodePtr ,
22
- cif : Cif
22
+ cif : Cif ,
23
23
}
24
24
25
25
unsafe impl Send for Function { }
26
26
unsafe impl Sync for Function { }
27
27
28
- type FP = unsafe extern "C" fn ( ) ;
28
+ type FP = unsafe extern "C" fn ( ) ;
29
29
30
30
impl Function {
31
31
pub unsafe fn load (
@@ -36,25 +36,29 @@ impl Function {
36
36
vm : & VirtualMachine ,
37
37
) -> PyResult < Self > {
38
38
// map each arg to a PyCSimple
39
- let args = args. into_iter ( ) . map ( |arg| {
40
- if arg. is_subclass ( PyCSimple :: static_type ( ) . as_object ( ) , vm) . unwrap ( ) {
41
- let arg_type = arg. get_attr ( "_type_" , vm) . unwrap ( ) . str ( vm) . unwrap ( ) . to_string ( ) ;
42
- let _value = arg. get_attr ( "value" , vm) . unwrap ( ) ;
43
- match & * arg_type {
44
- _ => todo ! ( "HANDLE ARG TYPE" )
39
+ let args = args
40
+ . into_iter ( )
41
+ . map ( |arg| {
42
+ if let Some ( data) = arg. downcast_ref :: < PyCSimple > ( ) {
43
+ Ok ( ffi_type_from_str ( & data. _type_ ) . unwrap ( ) )
44
+ } else {
45
+ Err ( vm. new_type_error ( "Expected a ctypes simple type" . to_string ( ) ) )
45
46
}
46
- } else {
47
- todo ! ( "HANDLE ERROR" )
48
- }
49
- } ) . collect :: < Vec < Type > > ( ) ;
47
+ } )
48
+ . collect :: < PyResult < Vec < Type > > > ( ) ?;
50
49
let terminated = format ! ( "{}\0 " , function) ;
51
- let pointer: Symbol < FP > = unsafe { library
52
- . get ( terminated. as_bytes ( ) )
53
- . map_err ( |err| err. to_string ( ) )
54
- . unwrap ( ) } ;
50
+ let pointer: Symbol < FP > = unsafe {
51
+ library
52
+ . get ( terminated. as_bytes ( ) )
53
+ . map_err ( |err| err. to_string ( ) )
54
+ . map_err ( |err| vm. new_value_error ( err) ) ?
55
+ } ;
55
56
let code_ptr = CodePtr ( * pointer as * mut _ ) ;
56
57
let return_type = match ret_type {
57
- Some ( _t) => todo ! ( "HANDLE RETURN TYPE" ) ,
58
+ // TODO: Fix this
59
+ Some ( _t) => {
60
+ return Err ( vm. new_not_implemented_error ( "Return type not implemented" . to_string ( ) ) ) ;
61
+ }
58
62
None => Type :: c_int ( ) ,
59
63
} ;
60
64
let cif = Cif :: new ( args. into_iter ( ) , return_type) ;
@@ -64,11 +68,25 @@ impl Function {
64
68
} )
65
69
}
66
70
67
- pub unsafe fn call ( & self , _args : Vec < PyObjectRef > , vm : & VirtualMachine ) -> PyObjectRef {
68
- let args: Vec < Arg > = vec ! [ ] ;
71
+ pub unsafe fn call (
72
+ & self ,
73
+ args : Vec < PyObjectRef > ,
74
+ vm : & VirtualMachine ,
75
+ ) -> PyResult < PyObjectRef > {
76
+ let args = args
77
+ . into_iter ( )
78
+ . map ( |arg| {
79
+ if let Some ( data) = arg. downcast_ref :: < PyCSimple > ( ) {
80
+ dbg ! ( & data) ;
81
+ todo ! ( "HANDLE ARGUMENTS" )
82
+ } else {
83
+ Err ( vm. new_type_error ( "Expected a ctypes simple type" . to_string ( ) ) )
84
+ }
85
+ } )
86
+ . collect :: < PyResult < Vec < Arg > > > ( ) ?;
69
87
// TODO: FIX return type
70
88
let result: i32 = unsafe { self . cif . call ( self . pointer , & args) } ;
71
- vm. ctx . new_int ( result) . into ( )
89
+ Ok ( vm. ctx . new_int ( result) . into ( ) )
72
90
}
73
91
}
74
92
@@ -80,7 +98,7 @@ pub struct PyCFuncPtr {
80
98
// FIXME(arihant2math): This shouldn't be an option, setting the default as the none type should work
81
99
// This is a workaround for now and I'll fix it later
82
100
pub _restype_ : PyRwLock < Option < PyTypeRef > > ,
83
- pub handler : PyObjectRef
101
+ pub handler : PyObjectRef ,
84
102
}
85
103
86
104
impl Debug for PyCFuncPtr {
@@ -95,16 +113,31 @@ impl Constructor for PyCFuncPtr {
95
113
type Args = FuncArgs ;
96
114
97
115
fn py_new ( _cls : PyTypeRef , args : Self :: Args , vm : & VirtualMachine ) -> PyResult {
98
- let tuple = args. args . first ( ) . unwrap ( ) ;
99
- let tuple: & Py < PyTuple > = tuple. downcast_ref ( ) . unwrap ( ) ;
100
- let name = tuple. first ( ) . unwrap ( ) . downcast_ref :: < PyStr > ( ) . unwrap ( ) . to_string ( ) ;
101
- let handler = tuple. into_iter ( ) . nth ( 1 ) . unwrap ( ) . clone ( ) ;
116
+ let tuple = args. args . first ( ) . ok_or_else ( || {
117
+ vm. new_type_error ( "CFuncPtr() takes exactly 1 argument (0 given)" . to_string ( ) )
118
+ } ) ?;
119
+ let tuple: & Py < PyTuple > = tuple
120
+ . downcast_ref ( )
121
+ . ok_or ( vm. new_type_error ( "Expected a tuple" . to_string ( ) ) ) ?;
122
+ let name = tuple
123
+ . first ( )
124
+ . ok_or ( vm. new_type_error ( "Expected a tuple with at least 2 elements" . to_string ( ) ) ) ?
125
+ . downcast_ref :: < PyStr > ( )
126
+ . ok_or ( vm. new_type_error ( "Expected a string" . to_string ( ) ) ) ?
127
+ . to_string ( ) ;
128
+ let handler = tuple
129
+ . into_iter ( )
130
+ . nth ( 1 )
131
+ . ok_or ( vm. new_type_error ( "Expected a tuple with at least 2 elements" . to_string ( ) ) ) ?
132
+ . to_object ( )
133
+ . clone ( ) ;
102
134
Ok ( Self {
103
135
_flags_ : AtomicCell :: new ( 0 ) ,
104
136
name : PyRwLock :: new ( name) ,
105
137
_restype_ : PyRwLock :: new ( None ) ,
106
- handler
107
- } . to_pyobject ( vm) )
138
+ handler,
139
+ }
140
+ . to_pyobject ( vm) )
108
141
}
109
142
}
110
143
@@ -115,12 +148,24 @@ impl Callable for PyCFuncPtr {
115
148
let handle = zelf. handler . get_attr ( "_handle" , vm) ?;
116
149
let handle = handle. try_int ( vm) ?. as_bigint ( ) . clone ( ) ;
117
150
let library_cache = crate :: stdlib:: ctypes:: library:: libcache ( ) . read ( ) ;
118
- let library = library_cache. get_lib ( handle. to_usize ( ) . unwrap ( ) ) . unwrap ( ) ;
151
+ let library = library_cache
152
+ . get_lib (
153
+ handle
154
+ . to_usize ( )
155
+ . ok_or ( vm. new_value_error ( "Invalid handle" . to_string ( ) ) ) ?,
156
+ )
157
+ . ok_or_else ( || vm. new_value_error ( "Library not found" . to_string ( ) ) ) ?;
119
158
let inner_lib = library. lib . lock ( ) ;
120
159
let name = zelf. name . read ( ) ;
121
160
let res_type = zelf. _restype_ . read ( ) ;
122
- let func = Function :: load ( inner_lib. as_ref ( ) . unwrap ( ) , & name, & args. args , & res_type, vm) ?;
123
- Ok ( func. call ( args. args , vm) )
161
+ let func = Function :: load (
162
+ inner_lib. as_ref ( ) . unwrap ( ) ,
163
+ & name,
164
+ & args. args ,
165
+ & res_type,
166
+ vm,
167
+ ) ?;
168
+ Ok ( func. call ( args. args , vm) ?)
124
169
}
125
170
}
126
171
}
0 commit comments