Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework of struct definition #209

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
2 changes: 2 additions & 0 deletions ctypesgen/printer_python/defaultheader.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@
Do not modify this file.
"""

from __future__ import annotations

__docformat__ = "restructuredtext"
13 changes: 13 additions & 0 deletions ctypesgen/printer_python/preamble.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
import ctypes
import sys
from ctypes import * # noqa: F401, F403
from typing import get_type_hints


def finalize_struct(cls):
fields = []
for name, ctype in get_type_hints(cls).items():
entry = [name, ctype]
if name in cls._tmp_bitfields_:
entry.append(cls._tmp_bitfields_[name])
fields.append(tuple(entry))
cls._fields_ = fields
del cls._tmp_bitfields_


_int_types = (ctypes.c_int16, ctypes.c_int32)
if hasattr(ctypes, "c_int64"):
Expand Down
78 changes: 43 additions & 35 deletions ctypesgen/printer_python/printer.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,47 @@ def print_typedef(self, typedef):
def print_struct(self, struct):
self.srcinfo(struct.src)
base = {"union": "Union", "struct": "Structure"}[struct.variety]
self.file.write("class %s_%s(%s):\n" " pass\n" % (struct.variety, struct.tag, base))
self.file.write("class %s_%s(%s):\n" % (struct.variety, struct.tag, base))
if struct.opaque:
self.file.write(" pass\n")
else:
# handle unnamed fields.
unnamed_fields = []
names = set([x[0] for x in struct.members])
anon_prefix = "unnamed_"
n = 1
for mi in range(len(struct.members)):
mem = list(struct.members[mi])
if mem[0] is None:
while True:
name = "%s%i" % (anon_prefix, n)
n += 1
if name not in names:
break
mem[0] = name
names.add(name)
if type(mem[1]) is CtypesStruct:
unnamed_fields.append(name)
struct.members[mi] = mem
struct.unnamed_fields = unnamed_fields

# print annotations
for name, ctype in struct.members:
self.file.write(f" {name} : {ctype.py_string()}\n")

self.file.write(f"\n")
self.file.write(f" __slots__ = list(__annotations__.keys())\n")

# TODO: maybe not implement this using a static member to avoid user confusion?
self.file.write("\n")
bitfields = list(filter(lambda x: isinstance(x[1], CtypesBitfield), struct.members))
if len(bitfields) == 0:
self.file.write(f" _tmp_bitfields_ = dict()\n")
else:
self.file.write(f" _tmp_bitfields_ = dict(\n")
for name, ctype in bitfields:
self.file.write(f" {name} = {ctype.bitfield.py_string(False)},\n")
self.file.write(" )\n")

def print_struct_members(self, struct):
if struct.opaque:
Expand All @@ -245,46 +285,14 @@ def print_struct_members(self, struct):
aligned = aligned.evaluate(None)
self.file.write("{}_{}._pack_ = {}\n".format(struct.variety, struct.tag, aligned))

# handle unnamed fields.
unnamed_fields = []
names = set([x[0] for x in struct.members])
anon_prefix = "unnamed_"
n = 1
for mi in range(len(struct.members)):
mem = list(struct.members[mi])
if mem[0] is None:
while True:
name = "%s%i" % (anon_prefix, n)
n += 1
if name not in names:
break
mem[0] = name
names.add(name)
if type(mem[1]) is CtypesStruct:
unnamed_fields.append(name)
struct.members[mi] = mem

self.file.write("%s_%s.__slots__ = [\n" % (struct.variety, struct.tag))
for name, ctype in struct.members:
self.file.write(" '%s',\n" % name)
self.file.write("]\n")

unnamed_fields = struct.unnamed_fields
if len(unnamed_fields) > 0:
self.file.write("%s_%s._anonymous_ = [\n" % (struct.variety, struct.tag))
for name in unnamed_fields:
self.file.write(" '%s',\n" % name)
self.file.write("]\n")

self.file.write("%s_%s._fields_ = [\n" % (struct.variety, struct.tag))
for name, ctype in struct.members:
if isinstance(ctype, CtypesBitfield):
self.file.write(
" ('%s', %s, %s),\n"
% (name, ctype.py_string(), ctype.bitfield.py_string(False))
)
else:
self.file.write(" ('%s', %s),\n" % (name, ctype.py_string()))
self.file.write("]\n")
self.file.write(f"finalize_struct({struct.variety}_{struct.tag})\n")

def print_enum(self, enum):
self.file.write("enum_%s = c_int" % enum.tag)
Expand Down