struct.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. from .writer import Writer
  2. from .converters import get_converter, Converter
  3. from .schema import Struct, StructField
  4. def gen_getter(w: Writer, name: str, cvt: Converter, field: StructField):
  5. w.write(f'static bool {name}__get_{field.name}(int argc, py_Ref argv) {{')
  6. w.indent()
  7. w.write(f'PY_CHECK_ARGC(1);')
  8. w.write(f'{name}* self = py_touserdata(argv);')
  9. cvt.c2py(w, 'py_retval()', f'self->{field.name}')
  10. w.write('return true;')
  11. w.dedent()
  12. w.write('}')
  13. def gen_setter(w: Writer, name: str, cvt: Converter, field: StructField):
  14. w.write(f'static bool {name}__set_{field.name}(int argc, py_Ref argv) {{')
  15. w.indent()
  16. w.write(f'PY_CHECK_ARGC(2);')
  17. w.write(f'{name}* self = py_touserdata(argv);')
  18. cvt.py2c(w, f'self->{field.name}', 'py_arg(1)')
  19. w.write('py_newnone(py_retval());')
  20. w.write('return true;')
  21. w.dedent()
  22. w.write('}')
  23. def gen_struct(w: Writer, pyi_w: Writer, struct: Struct):
  24. name = struct.name
  25. converters = [get_converter(field.type) for field in struct.fields]
  26. # default __new__
  27. w.write(f'static bool {name}__new__(int argc, py_Ref argv) {{')
  28. w.indent()
  29. w.write(f'py_Type cls = py_totype(argv);')
  30. w.write(f'py_newobject(py_retval(), cls, 0, sizeof({name}));')
  31. w.write('return true;')
  32. w.dedent()
  33. w.write('}')
  34. # default __init__
  35. w.write(f'static bool {name}__init__(int argc, py_Ref argv) {{')
  36. w.indent()
  37. w.write(f'{name}* self = py_touserdata(argv);')
  38. w.write(f'if(argc == 1) {{')
  39. w.indent()
  40. w.write(f'memset(self, 0, sizeof({name}));')
  41. w.dedent()
  42. w.write(f'}} else if(argc == 1 + {len(struct.fields)}) {{')
  43. w.indent()
  44. for i, field in enumerate(struct.fields):
  45. cvt = converters[i]
  46. if not cvt.is_const():
  47. cvt.py2c(w, f'self->{field.name}', f'py_arg({i+1})')
  48. else:
  49. w.write(f'// _{i} {field.name} is read-only')
  50. w.dedent()
  51. w.write('} else {')
  52. w.indent()
  53. w.write(f'return TypeError("expected 1 or {len(struct.fields)+1} arguments");')
  54. w.dedent()
  55. w.write('}')
  56. w.write('py_newnone(py_retval());')
  57. w.write('return true;')
  58. w.dedent()
  59. w.write('}')
  60. # default __copy__
  61. w.write(f'static bool {name}__copy__(int argc, py_Ref argv) {{')
  62. w.indent()
  63. w.write(f'PY_CHECK_ARGC(1);')
  64. w.write(f'{name}* self = py_touserdata(argv);')
  65. w.write(f'{name}* res = py_newobject(py_retval(), py_typeof(argv), 0, sizeof({name}));')
  66. w.write(f'*res = *self;')
  67. w.write('return true;')
  68. w.dedent()
  69. w.write('}')
  70. for field in struct.fields:
  71. cvt = get_converter(field.type)
  72. gen_getter(w, name, cvt, field)
  73. if not cvt.is_const():
  74. gen_setter(w, name, cvt, field)
  75. w.write(f'static py_Type register__{name}(py_GlobalRef mod) {{')
  76. w.indent()
  77. w.write(f'py_Type type = py_newtype("{name}", tp_object, mod, NULL);')
  78. w.write(f'py_bindmagic(type, __new__, {name}__new__);')
  79. w.write(f'py_bindmagic(type, __init__, {name}__init__);')
  80. w.write(f'py_bindmethod(type, "__address__", struct__address__);')
  81. w.write(f'py_bindmethod(type, "copy", {name}__copy__);')
  82. for field in struct.fields:
  83. cvt = get_converter(field.type)
  84. if cvt.is_const():
  85. setter = 'NULL'
  86. else:
  87. setter = f'{name}__set_{field.name}'
  88. w.write(f'py_bindproperty(type, "{field.name}", {name}__get_{field.name}, {setter});')
  89. w.write(f'return type;')
  90. w.dedent()
  91. w.write('}')
  92. # pyi
  93. pyi_w.write(f'class {name}:')
  94. pyi_w.indent()
  95. py_args = []
  96. for field in struct.fields:
  97. cvt = get_converter(field.type)
  98. desc = (field.desc or '') + f' ({field.type})'
  99. py_args.append(f"{field.name}: {cvt.py_T}")
  100. pyi_w.write(f"{py_args[-1]} # {desc}")
  101. pyi_w.write('')
  102. pyi_w.write(f'@overload')
  103. pyi_w.write(f'def __init__(self): ...')
  104. pyi_w.write(f'@overload')
  105. pyi_w.write(f'def __init__(self, {", ".join(py_args)}): ...')
  106. pyi_w.write(f'def __address__(self) -> int: ...')
  107. pyi_w.write(f"def copy(self) -> '{name}': ...")
  108. pyi_w.write('')
  109. pyi_w.dedent()
  110. w.write(f'static py_Type tp_user_{name};')
  111. return f'tp_user_{name} = register__{name}(mod);'