obstruct 0.2.4__tar.gz → 0.2.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. {obstruct-0.2.4 → obstruct-0.2.6}/.idea/workspace.xml +23 -9
  2. {obstruct-0.2.4 → obstruct-0.2.6}/PKG-INFO +1 -1
  3. {obstruct-0.2.4 → obstruct-0.2.6}/src/obstruct/__init__.py +0 -1
  4. obstruct-0.2.6/src/obstruct/__version__.py +1 -0
  5. {obstruct-0.2.4 → obstruct-0.2.6}/src/obstruct/aot/base.py +4 -1
  6. {obstruct-0.2.4 → obstruct-0.2.6}/src/obstruct/aot/pack.py +5 -6
  7. {obstruct-0.2.4 → obstruct-0.2.6}/src/obstruct/aot/unpack.py +58 -24
  8. obstruct-0.2.6/src/obstruct/struct_type.py +132 -0
  9. {obstruct-0.2.4 → obstruct-0.2.6}/test/test_speed.py +12 -4
  10. obstruct-0.2.4/src/obstruct/__version__.py +0 -1
  11. obstruct-0.2.4/src/obstruct/decorator.py +0 -34
  12. obstruct-0.2.4/src/obstruct/struct_type.py +0 -52
  13. {obstruct-0.2.4 → obstruct-0.2.6}/.idea/.gitignore +0 -0
  14. {obstruct-0.2.4 → obstruct-0.2.6}/.idea/inspectionProfiles/Project_Default.xml +0 -0
  15. {obstruct-0.2.4 → obstruct-0.2.6}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
  16. {obstruct-0.2.4 → obstruct-0.2.6}/.idea/misc.xml +0 -0
  17. {obstruct-0.2.4 → obstruct-0.2.6}/.idea/modules.xml +0 -0
  18. {obstruct-0.2.4 → obstruct-0.2.6}/.idea/obstruct.iml +0 -0
  19. {obstruct-0.2.4 → obstruct-0.2.6}/.idea/vcs.xml +0 -0
  20. {obstruct-0.2.4 → obstruct-0.2.6}/README.md +0 -0
  21. {obstruct-0.2.4 → obstruct-0.2.6}/pyproject.toml +0 -0
  22. {obstruct-0.2.4 → obstruct-0.2.6}/src/obstruct/aot/__init__.py +0 -0
  23. {obstruct-0.2.4 → obstruct-0.2.6}/src/obstruct/aot/aot.py +0 -0
  24. {obstruct-0.2.4 → obstruct-0.2.6}/src/obstruct/methods.py +0 -0
  25. {obstruct-0.2.4 → obstruct-0.2.6}/src/obstruct/types/__init__.py +0 -0
  26. {obstruct-0.2.4 → obstruct-0.2.6}/src/obstruct/types/base.py +0 -0
  27. {obstruct-0.2.4 → obstruct-0.2.6}/src/obstruct/types/types.py +0 -0
  28. {obstruct-0.2.4 → obstruct-0.2.6}/src/obstruct/types/types.pyi +0 -0
  29. {obstruct-0.2.4 → obstruct-0.2.6}/test/test.py +0 -0
  30. {obstruct-0.2.4 → obstruct-0.2.6}/uv.lock +0 -0
@@ -4,13 +4,9 @@
4
4
  <option name="autoReloadType" value="SELECTIVE" />
5
5
  </component>
6
6
  <component name="ChangeListManager">
7
- <list default="true" id="b482b6b4-48ce-4be1-bf3c-a72ec254fa35" name="更改" comment="修正了一些命名">
8
- <change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
9
- <change beforePath="$PROJECT_DIR$/src/obstruct/aot/base.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/obstruct/aot/base.py" afterDir="false" />
10
- <change beforePath="$PROJECT_DIR$/src/obstruct/aot/pack.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/obstruct/aot/pack.py" afterDir="false" />
11
- <change beforePath="$PROJECT_DIR$/src/obstruct/aot/unpack.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/obstruct/aot/unpack.py" afterDir="false" />
12
- <change beforePath="$PROJECT_DIR$/src/obstruct/methods.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/obstruct/methods.py" afterDir="false" />
13
- <change beforePath="$PROJECT_DIR$/test/test_speed.py" beforeDir="false" afterPath="$PROJECT_DIR$/test/test_speed.py" afterDir="false" />
7
+ <list default="true" id="b482b6b4-48ce-4be1-bf3c-a72ec254fa35" name="更改" comment="增强 array 类型的支持 x2">
8
+ <change beforePath="$PROJECT_DIR$/src/obstruct/__version__.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/obstruct/__version__.py" afterDir="false" />
9
+ <change beforePath="$PROJECT_DIR$/src/obstruct/struct_type.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/obstruct/struct_type.py" afterDir="false" />
14
10
  </list>
15
11
  <option name="SHOW_DIALOG" value="false" />
16
12
  <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -171,7 +167,23 @@
171
167
  <option name="project" value="LOCAL" />
172
168
  <updated>1786870314349</updated>
173
169
  </task>
174
- <option name="localTasksCounter" value="5" />
170
+ <task id="LOCAL-00005" summary="增强 array 类型的支持">
171
+ <option name="closed" value="true" />
172
+ <created>1786875274813</created>
173
+ <option name="number" value="00005" />
174
+ <option name="presentableId" value="LOCAL-00005" />
175
+ <option name="project" value="LOCAL" />
176
+ <updated>1786875274813</updated>
177
+ </task>
178
+ <task id="LOCAL-00006" summary="增强 array 类型的支持 x2">
179
+ <option name="closed" value="true" />
180
+ <created>1786883898686</created>
181
+ <option name="number" value="00006" />
182
+ <option name="presentableId" value="LOCAL-00006" />
183
+ <option name="project" value="LOCAL" />
184
+ <updated>1786883898686</updated>
185
+ </task>
186
+ <option name="localTasksCounter" value="7" />
175
187
  <servers />
176
188
  </component>
177
189
  <component name="TypeScriptGeneratedFilesManager">
@@ -193,6 +205,8 @@
193
205
  <MESSAGE value="增强类型系统,撰写 README.md" />
194
206
  <MESSAGE value="补充:基准测试脚本" />
195
207
  <MESSAGE value="修正了一些命名" />
196
- <option name="LAST_COMMIT_MESSAGE" value="修正了一些命名" />
208
+ <MESSAGE value="增强 array 类型的支持" />
209
+ <MESSAGE value="增强 array 类型的支持 x2" />
210
+ <option name="LAST_COMMIT_MESSAGE" value="增强 array 类型的支持 x2" />
197
211
  </component>
198
212
  </project>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: obstruct
3
- Version: 0.2.4
3
+ Version: 0.2.6
4
4
  Author-email: LittleNightSong <LittleNightSongYO@outlook.com>
5
5
  Classifier: Development Status :: 3 - Alpha
6
6
  Classifier: Programming Language :: Python
@@ -1,4 +1,3 @@
1
1
  from .methods import pack, unpack
2
- from .decorator import struct
3
2
  from .struct_type import Struct
4
3
  from .types import *
@@ -0,0 +1 @@
1
+ version = "0.2.6"
@@ -5,7 +5,6 @@ import itertools
5
5
  import typing
6
6
  from typing import Any
7
7
 
8
- from obstruct.methods import get_ctype
9
8
 
10
9
 
11
10
  class _objective_node_operator:
@@ -31,6 +30,9 @@ class _objective_node_operator:
31
30
  self._node.body.append(tree)
32
31
  return tree
33
32
 
33
+ def add_codes(self, codes: typing.Iterable[str]):
34
+ [self.add_code(c) for c in codes]
35
+
34
36
  def insert_code(self, index, code: str):
35
37
  tree = ast.parse(code)
36
38
  if isinstance(tree, ast.Module):
@@ -135,6 +137,7 @@ def get_array_spec(tp):
135
137
 
136
138
 
137
139
  def get_array_ctype(tp) -> str | None | Any:
140
+ from obstruct.methods import get_ctype
138
141
  return get_ctype(get_array_spec(tp)[0])
139
142
 
140
143
 
@@ -6,16 +6,16 @@ import typing
6
6
 
7
7
  from .base import unique_name_generator, is_struct, is_array, get_array_ctype, to_tuple_expression, function_def, \
8
8
  get_array_length
9
- from ..methods import get_ctype
10
9
 
11
10
  if typing.TYPE_CHECKING:
12
11
  from .. import struct_type
13
12
 
14
13
 
15
- def create_pack_methods(cls: struct_type.Struct):
14
+ def create_pack_methods(cls: type[struct_type.Struct]):
16
15
  """
17
16
  Generate `pack` and `pack_into` method
18
17
  """
18
+ from obstruct.methods import get_ctype
19
19
  with (
20
20
  function_def('pack(self)') as pack,
21
21
  function_def('pack_into(self, buffer, offset=0)') as pack_into,
@@ -24,8 +24,6 @@ def create_pack_methods(cls: struct_type.Struct):
24
24
  flat_fields = []
25
25
  array_fields = []
26
26
 
27
- pack_into.add_code('buffer = memoryview(buffer)')
28
-
29
27
  def add_code(code):
30
28
  pack.add_code(code)
31
29
  pack_into.add_code(code)
@@ -62,6 +60,7 @@ def create_pack_methods(cls: struct_type.Struct):
62
60
  expression = to_tuple_expression(flat_fields, prefix='')
63
61
 
64
62
  if array_fields: # 如果有数组字段,我们需要手动操作缓冲区
63
+ pack_into.insert_code(0, "buffer = memoryview(buffer)")
65
64
  pack.add_code(f"buffer = bytearray({cls.__cstruct__.size})") # 初始化缓冲区
66
65
  for array_name, offset, size in array_fields:
67
66
  add_code(f"buffer[{offset}:{offset + size}] = memoryview({array_name}).cast('B')")
@@ -72,8 +71,8 @@ def create_pack_methods(cls: struct_type.Struct):
72
71
  pack.add_return(f"_pack({expression})")
73
72
 
74
73
  pack_into.add_code(f"_pack_into(buffer, offset, {expression})")
75
- print(pack.generate_code()) # Debug
76
- print(pack_into.generate_code()) # Debug
74
+ # print(pack.generate_code()) # Debug
75
+ # print(pack_into.generate_code()) # Debug
77
76
  return (
78
77
  pack.exec({'_pack': cls.__cstruct__.pack, '_pack_into': cls.__cstruct__.pack_into, 'array': array.array}),
79
78
  pack_into.exec({'_pack_into': cls.__cstruct__.pack_into, 'array': array.array})
@@ -5,13 +5,14 @@ import struct
5
5
  import typing
6
6
 
7
7
  from .base import unique_name_generator, is_struct, is_array, get_array_ctype, function_def, for_stmt, get_array_length
8
- from ..methods import get_ctype
9
8
 
10
9
  if typing.TYPE_CHECKING:
11
10
  from .. import struct_type
12
11
 
13
12
 
14
13
  def create_unpack_methods(cls: type[struct_type.Struct]):
14
+ from ..methods import get_ctype
15
+
15
16
  with (
16
17
  function_def('unpack(cls, buffer)') as unpack,
17
18
  function_def('update(self, buffer)') as update,
@@ -32,7 +33,7 @@ def create_unpack_methods(cls: type[struct_type.Struct]):
32
33
  def update_add_code(code):
33
34
  update.add_code(code)
34
35
  update_from.add_code(code)
35
- iter_update_inner.add_code(code)
36
+ iter_update.insert_code(1, code)
36
37
 
37
38
  def unpack_add_code(code):
38
39
  unpack.add_code(code)
@@ -42,10 +43,10 @@ def create_unpack_methods(cls: type[struct_type.Struct]):
42
43
  assigns = [] # 赋值目标列表
43
44
  inner_classes = {} # 内嵌的结构体的类型映射(所有内嵌结构体的类型在生成代码时都会被代替为无意义的名称)
44
45
 
45
- iter_update.add_code("self = cls() if obj is None else obj")
46
+ iter_update.add_code("self = __new__(cls) if obj is None else obj")
46
47
 
47
- iter_unpack_inner = for_stmt("values in _iter_unpack(buffer)")
48
- iter_update_inner = for_stmt("values in _iter_unpack(buffer)")
48
+ iter_unpack_inner = for_stmt("i, values in enumerate(_iter_unpack(buffer))")
49
+ iter_update_inner = for_stmt("i, values in enumerate(_iter_unpack(buffer))")
49
50
 
50
51
  iter_unpack.add_node(iter_unpack_inner.node)
51
52
  iter_update.add_node(iter_update_inner.node)
@@ -55,7 +56,6 @@ def create_unpack_methods(cls: type[struct_type.Struct]):
55
56
  def walk(fields, path, parent_name=None, current_class_name='cls', offset=0):
56
57
  name = 'self'
57
58
 
58
-
59
59
  if len(path) > 1: # 在处理内嵌的结构体
60
60
  name = next(ung) # 临时变量的名称
61
61
  update_add_code(f"{name} = {parent_name}.{path[-1]}")
@@ -68,6 +68,9 @@ def create_unpack_methods(cls: type[struct_type.Struct]):
68
68
  for field in fields: # 遍历字段
69
69
  field_xpath = f'{name}.{field.name}'
70
70
 
71
+ # ctype = get_ctype(field.type)
72
+ # print(f"当前字段:{field_xpath},类型:{field.type} '{ctype}',偏移量:{offset}+{struct.calcsize(ctype)}")
73
+
71
74
  if is_struct(field.type): # 是个内嵌的结构体
72
75
  if field.type not in inner_classes: # 如果这个内嵌的结构体类型不在已知的结构体中(没有分配类名称)
73
76
  type_name = next(ung) # 生成一个唯一的类名
@@ -76,16 +79,16 @@ def create_unpack_methods(cls: type[struct_type.Struct]):
76
79
  type_name = inner_classes[field.type] # 如果在,那么提取
77
80
 
78
81
  walk(field.type.__cfields__, path + (field.name,), name, type_name, offset)
82
+ offset += field.type.__cstruct__.size
79
83
 
80
84
  elif is_array(field.type):
81
85
  dtype = get_array_ctype(field.type)
82
86
  nbytes = get_array_length(field.type) * struct.calcsize(dtype)
83
- array_fields.append((field_xpath, dtype, offset, nbytes))
84
-
87
+ array_fields.append((next(ung), field_xpath, dtype, offset, nbytes))
88
+ offset += nbytes
85
89
  else:
86
90
  assigns.append(field_xpath)
87
-
88
- offset += struct.calcsize(get_ctype(field.type))
91
+ offset += struct.calcsize(get_ctype(field.type))
89
92
 
90
93
  walk(cls.__cfields__, ('A',))
91
94
 
@@ -104,13 +107,40 @@ def create_unpack_methods(cls: type[struct_type.Struct]):
104
107
  unpack_from.add_code(assign_code)
105
108
  update_from.add_code(assign_code)
106
109
 
107
- for field_xpath, dtype, offset, nbytes in array_fields:
108
- codes = [
110
+ for n, field_xpath, dtype, offset, nbytes in array_fields:
111
+ size = cls.__cstruct__.size
112
+
113
+ update.add_codes([
114
+ f"{field_xpath}.clear()",
115
+ f"{field_xpath}.frombytes(buffer[{offset}:{offset + nbytes}])",
116
+ ])
117
+
118
+ update_from.add_codes([
119
+ f"{field_xpath}.clear()",
120
+ f"{field_xpath}.frombytes(buffer[{offset}+offset:{offset + nbytes}+offset])",
121
+ ])
122
+
123
+ unpack.add_codes([
124
+ f'{field_xpath} = _ = array({dtype!r})',
125
+ f'_.frombytes(buffer[{offset}:{offset + nbytes}])',
126
+ ])
127
+ unpack_from.add_codes([
109
128
  f'{field_xpath} = _ = array({dtype!r})',
110
- f'_.frombytes(buffer[{offset}:{offset+nbytes}])',
111
- ]
112
- for co in codes:
113
- unpack.add_code(co)
129
+ f'_.frombytes(buffer[{offset}+offset:{offset + nbytes}+offset])',
130
+ ])
131
+
132
+ iter_update_inner.add_codes([
133
+ f'offset = {size} * i',
134
+ f'{n}.frombytes(buffer[{offset}+offset:{offset + nbytes}+offset])'
135
+ ])
136
+
137
+ iter_unpack_inner.add_codes([
138
+ f"{field_xpath} = _ = array({dtype!r})",
139
+ f"offset = i*{size}",
140
+ f"_.frombytes(buffer[{offset}+offset:{offset + nbytes}+offset])"
141
+ ])
142
+
143
+ iter_update.insert_code(1, f"{n} = {field_xpath} = array({dtype!r})")
114
144
 
115
145
  if array_fields:
116
146
  unpack.insert_code(0, 'buffer = memoryview(buffer)')
@@ -120,15 +150,18 @@ def create_unpack_methods(cls: type[struct_type.Struct]):
120
150
  unpack_from.add_return('self')
121
151
  update_from.add_return('self')
122
152
 
123
- iter_unpack_inner.add_code('yield self') # iter 方法是 yield,而非 return
153
+ iter_unpack_inner.add_code('yield self')
124
154
  iter_update_inner.add_code('yield self')
125
155
 
126
- print(unpack.generate_code())
127
- # print(update.generate_code())
128
- # print(unpack_from.generate_code())
129
- # print(update_from.generate_code())
130
- # print(iter_unpack.generate_code())
131
- # print(iter_update.generate_code())
156
+ for n, *_ in array_fields:
157
+ iter_update_inner.add_code(f'{n}.clear()')
158
+
159
+ # print(unpack.generate_code())
160
+ print(update.generate_code())
161
+ print(unpack_from.generate_code())
162
+ print(update_from.generate_code())
163
+ print(iter_unpack.generate_code())
164
+ print(iter_update.generate_code())
132
165
 
133
166
  globals = {
134
167
  v: k for k, v in inner_classes.items() # 翻转字典
@@ -139,7 +172,8 @@ def create_unpack_methods(cls: type[struct_type.Struct]):
139
172
  _unpack=cls.__cstruct__.unpack,
140
173
  _unpack_from=cls.__cstruct__.unpack_from,
141
174
  _iter_unpack=cls.__cstruct__.iter_unpack,
142
- array=array.array
175
+ array=array.array,
176
+ enumerate=enumerate
143
177
  ))
144
178
 
145
179
  return unpack.exec(
@@ -0,0 +1,132 @@
1
+ import dataclasses
2
+ import struct
3
+ import typing
4
+ from collections.abc import Buffer
5
+ from typing import Self, Generator, Any, ClassVar
6
+
7
+ from obstruct.aot import create_pack_methods, create_unpack_methods
8
+
9
+
10
+ class CType(typing.Protocol):
11
+ __ctype__: str
12
+
13
+
14
+ class StructMeta(type):
15
+ __struct_methods__ = {
16
+ 'pack',
17
+ 'pack_into',
18
+
19
+ 'unpack',
20
+ 'unpack_from',
21
+ 'iter_unpack',
22
+
23
+ 'update',
24
+ 'update_from',
25
+ 'iter_update',
26
+
27
+ '__cstruct__',
28
+ '__ctype__',
29
+ '__cfields__',
30
+ }
31
+
32
+ def __new__(cls, name, bases, attrs, *, endian='little'):
33
+ slots = set(attrs.get('__slots__', ()))
34
+
35
+ annotations = attrs.get('__annotations__')
36
+
37
+ if annotations is None:
38
+ import annotationlib
39
+ annotate = annotationlib.get_annotate_from_class_namespace(attrs)
40
+ assert annotate is not None
41
+
42
+ annotations = annotationlib.call_annotate_function(
43
+ annotate,
44
+ format=annotationlib.Format.STRING
45
+ )
46
+
47
+ slots |= {k for k in annotations.keys() if not k.startswith('_')}
48
+
49
+ attrs['__slots__'] = slots
50
+ attrs['__cendian__'] = endian
51
+
52
+ return super().__new__(cls, name, bases, attrs)
53
+
54
+ def __compile_struct__(cls):
55
+ from obstruct.methods import to_format_string
56
+ fields = [i for i in dataclasses.fields(cls) if i.init]
57
+ real_annotations = typing.get_type_hints(cls)
58
+
59
+ for field in fields:
60
+ # print(cls, field.name, repr(field.type))
61
+ if isinstance(field.type, str):
62
+ field.type = real_annotations[field.name]
63
+
64
+ cls.__ctype__ = to_format_string([field.type for field in fields])
65
+ cls.__cfields__ = tuple(fields) # type: tuple[dataclasses.Field, ...]
66
+ cls.__cstruct__ = struct.Struct(
67
+ endian_mapping.get(cls.__cendian__, cls.__cendian__) + cls.__ctype__) # 构造 Struct 类型
68
+
69
+ cls.pack, cls.pack_into = create_pack_methods(cls)
70
+ cls.unpack, cls.update, cls.unpack_from, cls.update_from, cls.iter_unpack, cls.iter_update = (
71
+ create_unpack_methods(cls)
72
+ )
73
+
74
+
75
+ endian_mapping = {
76
+ 'little': '<',
77
+ 'big': '>',
78
+ 'machine': '=',
79
+ 'network': '!'
80
+ }
81
+
82
+
83
+ class Struct(metaclass=StructMeta):
84
+ """
85
+ 代表C语言结构体的Python类。
86
+ 提供了将结构体对象与字节序列之间互相转换的功能,
87
+ 包括打包、解包、更新等操作。
88
+ """
89
+
90
+ __cfields__: ClassVar[tuple[dataclasses.Field]]
91
+ __cstruct__: ClassVar[struct.Struct]
92
+ __cendian__: ClassVar[str]
93
+
94
+ if typing.TYPE_CHECKING:
95
+ def pack(self) -> bytes:
96
+ ...
97
+
98
+ def pack_into(self, buffer: Buffer, offset=0) -> None:
99
+ ...
100
+
101
+ @classmethod
102
+ def unpack(cls, buffer) -> Self:
103
+ ...
104
+
105
+ @classmethod
106
+ def unpack_from(cls, buffer, offset=0) -> Self:
107
+ ...
108
+
109
+ @classmethod
110
+ def iter_unpack(cls, buffer) -> Generator[Self, None, None]:
111
+ ...
112
+
113
+ @classmethod
114
+ def iter_update(cls, buffer) -> Generator[Self, None, None]:
115
+ ...
116
+
117
+ def update(self, buffer: Buffer) -> None:
118
+ ...
119
+
120
+ def update_from(self, buffer: Buffer, offset=0) -> None:
121
+ ...
122
+
123
+ def to_dict(self) -> dict[str, Any]:
124
+ return dataclasses.asdict(self)
125
+
126
+ def __getattr__(self, item):
127
+ ty = type(self)
128
+ if item in ty.__struct_methods__:
129
+ ty.__compile_struct__()
130
+ return getattr(self, item)
131
+
132
+ raise AttributeError(item)
@@ -6,8 +6,7 @@ from typing import Annotated
6
6
  import obstruct as obs
7
7
 
8
8
 
9
- @obs.struct()
10
- @dataclasses.dataclass(slots=True)
9
+ @dataclasses.dataclass()
11
10
  class MyStruct(obs.Struct):
12
11
  a: int
13
12
  b: int
@@ -23,17 +22,26 @@ class MyStruct(obs.Struct):
23
22
  l: obs.long_long
24
23
 
25
24
 
26
- @obs.struct()
27
- @dataclasses.dataclass(slots=True)
25
+ @dataclasses.dataclass()
28
26
  class AnotherStruct(obs.Struct):
29
27
  x: MyStruct
30
28
  y: Annotated[array[int], 100]
31
29
  z: MyStruct
32
30
 
33
31
 
32
+ MyStruct.__compile_struct__()
33
+ AnotherStruct.__compile_struct__()
34
+
35
+ print('MyStruct size', MyStruct.__cstruct__.size)
36
+ print('AnotherStruct size', AnotherStruct.__cstruct__.size)
37
+
38
+
39
+ exit()
40
+
34
41
  data = MyStruct(
35
42
  1,2,1.0,4,5,6,7,8,9,b'8',1,2
36
43
  )
44
+
37
45
  packed_data = data.pack()
38
46
 
39
47
 
@@ -1 +0,0 @@
1
- version = "0.2.4"
@@ -1,34 +0,0 @@
1
- import dataclasses
2
- import typing
3
-
4
- from . import struct_type
5
- from .aot import pack, unpack
6
- from .methods import to_format_string
7
-
8
- endian_control_characters = tuple('<@=!>')
9
-
10
-
11
- def struct(maybe_cls=None, *, endian='@'):
12
- def decorator[T](cls: T) -> T:
13
- import struct
14
- fields = dataclasses.fields(cls)
15
- real_annotations = typing.get_type_hints(cls)
16
-
17
- for field in fields:
18
- # print(cls, field.name, repr(field.type))
19
- if isinstance(field.type, str):
20
- field.type = real_annotations[field.name]
21
-
22
- cls.__ctype__ = to_format_string([field.type for field in fields])
23
- cls.__cfields__ = tuple(fields) # type: tuple[dataclasses.Field, ...]
24
- cls.__cstruct__ = struct.Struct(endian + cls.__ctype__) # 构造 Struct 类型
25
- cls.__cendian__ = endian
26
-
27
- cls.pack, cls.pack_into = pack.create_pack_methods(cls)
28
- cls.unpack, cls.update, cls.unpack_from, cls.update_from, cls.iter_unpack, cls.iter_update = (
29
- unpack.create_unpack_methods(cls)
30
- )
31
-
32
- return cls
33
-
34
- return decorator(maybe_cls) if maybe_cls is not None else decorator
@@ -1,52 +0,0 @@
1
- import dataclasses
2
- import struct
3
- import typing
4
- from collections.abc import Buffer
5
- from typing import Self, Generator, Any, ClassVar
6
-
7
-
8
- class CType(typing.Protocol):
9
- __ctype__: str
10
-
11
-
12
- class Struct(CType):
13
- """
14
- 代表C语言结构体的Python类。
15
- 提供了将结构体对象与字节序列之间互相转换的功能,
16
- 包括打包、解包、更新等操作。
17
- """
18
-
19
- __cfields__: ClassVar[tuple[dataclasses.Field]]
20
- __cstruct__: ClassVar[struct.Struct]
21
- __cendian__: ClassVar[str]
22
-
23
- def pack(self) -> bytes:
24
- ...
25
-
26
- def pack_into(self, buffer: Buffer, offset=0) -> None:
27
- ...
28
-
29
- @classmethod
30
- def unpack(cls, buffer) -> Self:
31
- ...
32
-
33
- @classmethod
34
- def unpack_from(cls, buffer, offset=0) -> Self:
35
- ...
36
-
37
- @classmethod
38
- def iter_unpack(cls, buffer) -> Generator[Self, None, None]:
39
- ...
40
-
41
- @classmethod
42
- def iter_update(cls, buffer) -> Generator[Self, None, None]:
43
- ...
44
-
45
- def update(self, buffer: Buffer) -> None:
46
- ...
47
-
48
- def update_from(self, buffer: Buffer, offset=0) -> None:
49
- ...
50
-
51
- def to_dict(self) -> dict[str, Any]:
52
- return dataclasses.asdict(self)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes