Skip to content

Commit b3f8d5c

Browse files
committed
pyRay : use a list of argument converters based on c function signature
1 parent 0803946 commit b3f8d5c

File tree

1 file changed

+51
-24
lines changed

1 file changed

+51
-24
lines changed

pyray/__init__.py

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
1414

1515
from raylib import rl, ffi
16-
1716
from inspect import ismethod,getmembers,isbuiltin
1817
import inflection
1918

@@ -60,31 +59,60 @@ def pointer(self, struct):
6059
# Another possibility is ffi.typeof() but that will throw an exception if you give it a type that isn't a ctype
6160
# Another way to improve performance might be to special-case simple types before doing the string comparisons
6261

63-
def makefunc(a):
62+
## simple value converters
63+
# will fail if fed wrong arguments
64+
65+
def as_is(value):
66+
return value
67+
68+
def to_bytes(value):
69+
if type(value) is bytes: return value
70+
else: return value.encode('utf-8', 'ignore')
71+
72+
def to_str(value):
73+
return ffi.string(value).decode('utf-8')
74+
75+
def to_pointer(value):
76+
return ffi.addressof(value)
77+
78+
79+
def makeFunc(c_func):
6480
#print("makefunc ",a, ffi.typeof(a).args)
81+
82+
# based on ctypes of arguments of the c function
83+
# we build a list of converters to call on python function arguments
84+
converters = []
85+
for c_arg_type in ffi.typeof(c_func).args:
86+
if c_arg_type is ffi.typeof('char *'):
87+
converters.append(to_bytes)
88+
elif c_arg_type.kind == 'pointer':
89+
converters.append(to_pointer)
90+
else:
91+
converters.append(as_is)
92+
93+
# not sure if this would bring any speedup
94+
#converters = tuple(converters)
95+
96+
resultConverter = None
97+
c_result_type = ffi.typeof(c_func).result
98+
if c_result_type is ffi.typeof('char *'):
99+
resultConverter = to_str
100+
elif c_result_type:
101+
resultConverter = as_is
102+
103+
# use a closure to bring converters into c function call
65104
def func(*args):
66-
modified_args = []
67-
for (c_arg, arg) in zip(ffi.typeof(a).args, args):
68-
#print(arg, c_arg.kind)
69-
if type(arg) == str:
70-
encoded = arg.encode('utf-8')
71-
modified_args.append(encoded)
72-
elif c_arg.kind == 'pointer' and str(type(arg)) == "<class '_cffi_backend.__CDataOwn'>":
73-
modified_args.append(ffi.addressof(arg))
74-
else:
75-
modified_args.append(arg)
76-
result = a(*modified_args)
77-
if result is None:
105+
nonlocal converters, resultConverter
106+
107+
result = c_func(* (convert(arg) for (arg, convert) in zip(args, converters) ) )
108+
109+
if result is None or resultConverter is None:
78110
return
79-
if str(type(result)) == "<class '_cffi_backend._CDataBase'>" and str(result).startswith("<cdata 'char *'"):
80-
if str(result) == "<cdata 'char *' NULL>":
81-
result = ""
82-
else:
83-
result = ffi.string(result).decode('utf-8')
84-
return result
111+
return resultConverter(result)
112+
85113
return func
86114

87-
def makeStructHelper(struct):
115+
def makeStruct(struct):
88116
def func(*args):
89117
return ffi.new(f"struct {struct} *", args)[0]
90118
return func
@@ -99,7 +127,7 @@ def func(*args):
99127
#print(attr.__text_signature__)
100128
#print(dir(attr))
101129
#print(dir(attr.__repr__))
102-
f = makefunc(attr)
130+
f = makeFunc(attr)
103131
setattr(current_module, uname, f)
104132
#def wrap(*args):
105133
# print("call to ",attr)
@@ -108,6 +136,5 @@ def func(*args):
108136
setattr(current_module, name, attr)
109137

110138
for struct in ffi.list_types()[0]:
111-
f = makeStructHelper(struct)
139+
f = makeStruct(struct)
112140
setattr(current_module, struct, f)
113-

0 commit comments

Comments
 (0)