obstruct 0.2.3__tar.gz → 0.2.5__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 (34) hide show
  1. obstruct-0.2.5/.idea/modules.xml +8 -0
  2. obstruct-0.2.3/.idea/Hydrogenlib-Objective-Struct.iml → obstruct-0.2.5/.idea/obstruct.iml +1 -4
  3. {obstruct-0.2.3 → obstruct-0.2.5}/.idea/workspace.xml +61 -24
  4. {obstruct-0.2.3 → obstruct-0.2.5}/PKG-INFO +21 -14
  5. {obstruct-0.2.3 → obstruct-0.2.5}/README.md +20 -13
  6. {obstruct-0.2.3 → obstruct-0.2.5}/src/obstruct/__init__.py +0 -1
  7. obstruct-0.2.5/src/obstruct/__version__.py +1 -0
  8. {obstruct-0.2.3 → obstruct-0.2.5}/src/obstruct/aot/base.py +21 -13
  9. obstruct-0.2.5/src/obstruct/aot/pack.py +79 -0
  10. obstruct-0.2.5/src/obstruct/aot/unpack.py +191 -0
  11. {obstruct-0.2.3 → obstruct-0.2.5}/src/obstruct/methods.py +1 -1
  12. obstruct-0.2.5/src/obstruct/struct_type.py +132 -0
  13. obstruct-0.2.5/test/test_speed.py +103 -0
  14. obstruct-0.2.3/.idea/modules.xml +0 -8
  15. obstruct-0.2.3/src/obstruct/__version__.py +0 -1
  16. obstruct-0.2.3/src/obstruct/aot/pack.py +0 -58
  17. obstruct-0.2.3/src/obstruct/aot/unpack.py +0 -141
  18. obstruct-0.2.3/src/obstruct/decorator.py +0 -34
  19. obstruct-0.2.3/src/obstruct/struct_type.py +0 -52
  20. obstruct-0.2.3/test/test_speed.py +0 -60
  21. {obstruct-0.2.3 → obstruct-0.2.5}/.idea/.gitignore +0 -0
  22. {obstruct-0.2.3 → obstruct-0.2.5}/.idea/inspectionProfiles/Project_Default.xml +0 -0
  23. {obstruct-0.2.3 → obstruct-0.2.5}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
  24. {obstruct-0.2.3 → obstruct-0.2.5}/.idea/misc.xml +0 -0
  25. {obstruct-0.2.3 → obstruct-0.2.5}/.idea/vcs.xml +0 -0
  26. {obstruct-0.2.3 → obstruct-0.2.5}/pyproject.toml +0 -0
  27. {obstruct-0.2.3 → obstruct-0.2.5}/src/obstruct/aot/__init__.py +0 -0
  28. {obstruct-0.2.3 → obstruct-0.2.5}/src/obstruct/aot/aot.py +0 -0
  29. {obstruct-0.2.3 → obstruct-0.2.5}/src/obstruct/types/__init__.py +0 -0
  30. {obstruct-0.2.3 → obstruct-0.2.5}/src/obstruct/types/base.py +0 -0
  31. {obstruct-0.2.3 → obstruct-0.2.5}/src/obstruct/types/types.py +0 -0
  32. {obstruct-0.2.3 → obstruct-0.2.5}/src/obstruct/types/types.pyi +0 -0
  33. {obstruct-0.2.3 → obstruct-0.2.5}/test/test.py +0 -0
  34. {obstruct-0.2.3 → obstruct-0.2.5}/uv.lock +0 -0
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/obstruct.iml" filepath="$PROJECT_DIR$/.idea/obstruct.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
@@ -2,16 +2,13 @@
2
2
  <module external.system.id="pyproject.toml" type="PYTHON_MODULE" version="4">
3
3
  <component name="NewModuleRootManager">
4
4
  <content url="file://$MODULE_DIR$">
5
- <sourceFolder url="file://$MODULE_DIR$/src" />
5
+ <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
6
6
  <excludeFolder url="file://$MODULE_DIR$/.venv" />
7
7
  </content>
8
8
  <orderEntry type="jdk" jdkName="E:\.projects\obstruct\.venv" jdkType="Python SDK" />
9
9
  <orderEntry type="sourceFolder" forTests="false" />
10
10
  </component>
11
- <component name="PackageRequirementsSettings" />
12
11
  <component name="PyDocumentationSettings">
13
12
  <option name="format" value="PLAIN" />
14
13
  </component>
15
- <component name="ReSTService" />
16
- <component name="TestRunnerService" />
17
14
  </module>
@@ -4,15 +4,15 @@
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="initial commit">
8
- <change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
7
+ <list default="true" id="b482b6b4-48ce-4be1-bf3c-a72ec254fa35" name="更改" comment="增强 array 类型的支持">
8
+ <change beforePath="$PROJECT_DIR$/src/obstruct/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/obstruct/__init__.py" afterDir="false" />
9
9
  <change beforePath="$PROJECT_DIR$/src/obstruct/__version__.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/obstruct/__version__.py" afterDir="false" />
10
10
  <change beforePath="$PROJECT_DIR$/src/obstruct/aot/base.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/obstruct/aot/base.py" afterDir="false" />
11
+ <change beforePath="$PROJECT_DIR$/src/obstruct/aot/pack.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/obstruct/aot/pack.py" afterDir="false" />
11
12
  <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/decorator.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/obstruct/decorator.py" afterDir="false" />
13
- <change beforePath="$PROJECT_DIR$/src/obstruct/methods.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/obstruct/methods.py" afterDir="false" />
14
- <change beforePath="$PROJECT_DIR$/src/obstruct/types/types.pyi" beforeDir="false" afterPath="$PROJECT_DIR$/src/obstruct/types/types.pyi" afterDir="false" />
15
- <change beforePath="$PROJECT_DIR$/uv.lock" beforeDir="false" afterPath="$PROJECT_DIR$/uv.lock" afterDir="false" />
13
+ <change beforePath="$PROJECT_DIR$/src/obstruct/decorator.py" beforeDir="false" />
14
+ <change beforePath="$PROJECT_DIR$/src/obstruct/struct_type.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/obstruct/struct_type.py" afterDir="false" />
15
+ <change beforePath="$PROJECT_DIR$/test/test_speed.py" beforeDir="false" afterPath="$PROJECT_DIR$/test/test_speed.py" afterDir="false" />
16
16
  </list>
17
17
  <option name="SHOW_DIALOG" value="false" />
18
18
  <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -29,22 +29,22 @@
29
29
  <component name="Git.Settings">
30
30
  <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
31
31
  </component>
32
- <component name="GitHubPullRequestSearchHistory"><![CDATA[{
33
- "lastFilter": {
34
- "state": "OPEN",
35
- "assignee": "LittleNightSong"
32
+ <component name="GitHubPullRequestSearchHistory">{
33
+ &quot;lastFilter&quot;: {
34
+ &quot;state&quot;: &quot;OPEN&quot;,
35
+ &quot;assignee&quot;: &quot;LittleNightSong&quot;
36
36
  }
37
- }]]></component>
38
- <component name="GithubPullRequestsUISettings"><![CDATA[{
39
- "selectedUrlAndAccountId": {
40
- "url": "https://github.com/LittleNightSong/obstruct.git",
41
- "accountId": "c74c50b1-2437-429b-b395-d763b566b8a2"
37
+ }</component>
38
+ <component name="GithubPullRequestsUISettings">{
39
+ &quot;selectedUrlAndAccountId&quot;: {
40
+ &quot;url&quot;: &quot;https://github.com/LittleNightSong/obstruct.git&quot;,
41
+ &quot;accountId&quot;: &quot;c74c50b1-2437-429b-b395-d763b566b8a2&quot;
42
42
  }
43
- }]]></component>
44
- <component name="ProjectColorInfo"><![CDATA[{
45
- "associatedIndex": 3,
46
- "fromUser": false
47
- }]]></component>
43
+ }</component>
44
+ <component name="ProjectColorInfo">{
45
+ &quot;associatedIndex&quot;: 3,
46
+ &quot;fromUser&quot;: false
47
+ }</component>
48
48
  <component name="ProjectId" id="3HzAgHvw3X1T2NidzBlYQSHnZow" />
49
49
  <component name="ProjectViewState">
50
50
  <option name="hideEmptyMiddlePackages" value="true" />
@@ -56,6 +56,7 @@
56
56
  "Python.test.executor": "Run",
57
57
  "Python.test_speed.executor": "Run",
58
58
  "RunOnceActivity.ShowReadmeOnStart": "true",
59
+ "RunOnceActivity.git.unshallow": "true",
59
60
  "RunOnceActivity.typescript.service.memoryLimit.init": "true",
60
61
  "codeWithMe.voiceChat.enabledByDefault": "false",
61
62
  "git-widget-placeholder": "main",
@@ -71,7 +72,7 @@
71
72
  }]]></component>
72
73
  <component name="RunManager" selected="Python.test_speed">
73
74
  <configuration name="test" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
74
- <module name="Hydrogenlib-Objective-Struct" />
75
+ <module name="obstruct" />
75
76
  <option name="ENV_FILES" value="" />
76
77
  <option name="INTERPRETER_OPTIONS" value="" />
77
78
  <option name="PARENT_ENVS" value="true" />
@@ -95,7 +96,7 @@
95
96
  <method v="2" />
96
97
  </configuration>
97
98
  <configuration name="test_speed" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
98
- <module name="Hydrogenlib-Objective-Struct" />
99
+ <module name="obstruct" />
99
100
  <option name="ENV_FILES" value="" />
100
101
  <option name="INTERPRETER_OPTIONS" value="" />
101
102
  <option name="PARENT_ENVS" value="true" />
@@ -148,7 +149,39 @@
148
149
  <option name="project" value="LOCAL" />
149
150
  <updated>1786865208583</updated>
150
151
  </task>
151
- <option name="localTasksCounter" value="2" />
152
+ <task id="LOCAL-00002" summary="增强类型系统,撰写 README.md">
153
+ <option name="closed" value="true" />
154
+ <created>1786868730474</created>
155
+ <option name="number" value="00002" />
156
+ <option name="presentableId" value="LOCAL-00002" />
157
+ <option name="project" value="LOCAL" />
158
+ <updated>1786868730474</updated>
159
+ </task>
160
+ <task id="LOCAL-00003" summary="补充:基准测试脚本">
161
+ <option name="closed" value="true" />
162
+ <created>1786868746817</created>
163
+ <option name="number" value="00003" />
164
+ <option name="presentableId" value="LOCAL-00003" />
165
+ <option name="project" value="LOCAL" />
166
+ <updated>1786868746817</updated>
167
+ </task>
168
+ <task id="LOCAL-00004" summary="修正了一些命名">
169
+ <option name="closed" value="true" />
170
+ <created>1786870314349</created>
171
+ <option name="number" value="00004" />
172
+ <option name="presentableId" value="LOCAL-00004" />
173
+ <option name="project" value="LOCAL" />
174
+ <updated>1786870314349</updated>
175
+ </task>
176
+ <task id="LOCAL-00005" summary="增强 array 类型的支持">
177
+ <option name="closed" value="true" />
178
+ <created>1786875274813</created>
179
+ <option name="number" value="00005" />
180
+ <option name="presentableId" value="LOCAL-00005" />
181
+ <option name="project" value="LOCAL" />
182
+ <updated>1786875274813</updated>
183
+ </task>
184
+ <option name="localTasksCounter" value="6" />
152
185
  <servers />
153
186
  </component>
154
187
  <component name="TypeScriptGeneratedFilesManager">
@@ -167,6 +200,10 @@
167
200
  </component>
168
201
  <component name="VcsManagerConfiguration">
169
202
  <MESSAGE value="initial commit" />
170
- <option name="LAST_COMMIT_MESSAGE" value="initial commit" />
203
+ <MESSAGE value="增强类型系统,撰写 README.md" />
204
+ <MESSAGE value="补充:基准测试脚本" />
205
+ <MESSAGE value="修正了一些命名" />
206
+ <MESSAGE value="增强 array 类型的支持" />
207
+ <option name="LAST_COMMIT_MESSAGE" value="增强 array 类型的支持" />
171
208
  </component>
172
209
  </project>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: obstruct
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Author-email: LittleNightSong <LittleNightSongYO@outlook.com>
5
5
  Classifier: Development Status :: 3 - Alpha
6
6
  Classifier: Programming Language :: Python
@@ -15,42 +15,48 @@ Description-Content-Type: text/markdown
15
15
  _来自已弃坑的 `Hydrogenlib`,重拾起当初的决心_
16
16
 
17
17
 
18
- >[!TIP]
18
+ > [!TIP]
19
19
  > 这个项目来自 [`HydrogenLib`](https://github.com/LittleNightSong/HydrogenLib)的 `Objective-Struct` 模块,脱离大项目的版本
20
20
  >
21
21
  > 同时,`HydrogenLib`中的 `Objective-Struct` 不再会更新
22
22
 
23
- >[!TIP]
23
+ > [!TIP]
24
24
  > 作者的主要开发精力放在了另一些项目上,也许很长时间这个项目都不会再更新
25
25
 
26
26
  # OBStruct
27
+
27
28
  _一个简单、纯粹、极速的二进制解析库_
28
29
 
29
30
  ## 亮点
31
+
30
32
  - 纯 Python
31
33
  - 基于类型注解的字段声明方式
32
34
  - 支持 `struct` 标准库中的所有格式,并额外支持 array 类型
33
35
  - 基于 AOT 的加速
34
36
  - 完整的操作支持(打包、解包、流式处理)
35
37
 
36
- >[!WARNING]
37
- >使用 `array` 类型将带来严重的性能损失,谨慎使用
38
+ > [!WARNING]
39
+ >使用 `array` 类型时,建议不要传入 list 类型或其它 Python 序列,
40
+ > 可能会带来极大的性能影响
38
41
 
39
42
  ## 基准测试
43
+
40
44
  ### 系统环境
41
- - 12th Gen Intel® Core(TM) i7-12700H
45
+
46
+ - 12th Gen Intel® Core (TM) i7-12700H
42
47
 
43
48
  在 12个字段,10000 次操作,8轮取平均值的条件下:
49
+
44
50
  - 打包:269.639ns 一次操作
45
51
  - 解包:582.185ns 一次操作
46
52
 
47
-
48
53
  ## 安装
54
+
49
55
  ```commandline
50
56
  pip install obstruct
51
57
  ```
52
- 如果使用 `uv` 等包管理器,则按照工具的方法安装即可
53
58
 
59
+ 如果使用 `uv` 等包管理器,则按照工具的方法安装即可
54
60
 
55
61
  ## 用法
56
62
 
@@ -60,6 +66,7 @@ pip install obstruct
60
66
  import obstruct as obs
61
67
  from dataclasses import dataclass
62
68
 
69
+
63
70
  @obs.struct()
64
71
  @dataclass()
65
72
  class MyStruct(obs.Struct):
@@ -68,24 +75,24 @@ class MyStruct(obs.Struct):
68
75
  c: obs.long
69
76
  d: obs.unsigned_short
70
77
 
71
-
78
+
72
79
  if __name__ == '__main__':
73
80
  data = MyStruct(a=0, b=2.0, c=10000, d=14545)
74
-
81
+
75
82
  packed_data = data.pack()
76
83
  print(packed_data)
77
-
84
+
78
85
  restored = MyStruct.unpack(packed_data)
79
86
  print(restored)
80
-
87
+
81
88
  print(data == restored)
82
89
 
83
90
  ```
84
91
 
85
- 在上述示例中,你可能发现 `data != restored`,这是浮点数的精度限制导致的。
86
- 因此,我们不建议使用浮点数类型,浮点数在二进制传输中也不常见。
92
+ 在上述示例中,你可能发现 `data != restored`,这是浮点数的精度限制导致的。 因此,我们不建议使用浮点数类型,浮点数在二进制传输中也不常见。
87
93
 
88
94
  ## 计划
95
+
89
96
  - 展平装饰器,目前的 API 较为繁琐,需要简化为唯一的 `Struct` 基类
90
97
  - 继续优化性能
91
98
  - 通过存根文件强制表明类型似乎变得不再有效了
@@ -1,42 +1,48 @@
1
1
  _来自已弃坑的 `Hydrogenlib`,重拾起当初的决心_
2
2
 
3
3
 
4
- >[!TIP]
4
+ > [!TIP]
5
5
  > 这个项目来自 [`HydrogenLib`](https://github.com/LittleNightSong/HydrogenLib)的 `Objective-Struct` 模块,脱离大项目的版本
6
6
  >
7
7
  > 同时,`HydrogenLib`中的 `Objective-Struct` 不再会更新
8
8
 
9
- >[!TIP]
9
+ > [!TIP]
10
10
  > 作者的主要开发精力放在了另一些项目上,也许很长时间这个项目都不会再更新
11
11
 
12
12
  # OBStruct
13
+
13
14
  _一个简单、纯粹、极速的二进制解析库_
14
15
 
15
16
  ## 亮点
17
+
16
18
  - 纯 Python
17
19
  - 基于类型注解的字段声明方式
18
20
  - 支持 `struct` 标准库中的所有格式,并额外支持 array 类型
19
21
  - 基于 AOT 的加速
20
22
  - 完整的操作支持(打包、解包、流式处理)
21
23
 
22
- >[!WARNING]
23
- >使用 `array` 类型将带来严重的性能损失,谨慎使用
24
+ > [!WARNING]
25
+ >使用 `array` 类型时,建议不要传入 list 类型或其它 Python 序列,
26
+ > 可能会带来极大的性能影响
24
27
 
25
28
  ## 基准测试
29
+
26
30
  ### 系统环境
27
- - 12th Gen Intel® Core(TM) i7-12700H
31
+
32
+ - 12th Gen Intel® Core (TM) i7-12700H
28
33
 
29
34
  在 12个字段,10000 次操作,8轮取平均值的条件下:
35
+
30
36
  - 打包:269.639ns 一次操作
31
37
  - 解包:582.185ns 一次操作
32
38
 
33
-
34
39
  ## 安装
40
+
35
41
  ```commandline
36
42
  pip install obstruct
37
43
  ```
38
- 如果使用 `uv` 等包管理器,则按照工具的方法安装即可
39
44
 
45
+ 如果使用 `uv` 等包管理器,则按照工具的方法安装即可
40
46
 
41
47
  ## 用法
42
48
 
@@ -46,6 +52,7 @@ pip install obstruct
46
52
  import obstruct as obs
47
53
  from dataclasses import dataclass
48
54
 
55
+
49
56
  @obs.struct()
50
57
  @dataclass()
51
58
  class MyStruct(obs.Struct):
@@ -54,24 +61,24 @@ class MyStruct(obs.Struct):
54
61
  c: obs.long
55
62
  d: obs.unsigned_short
56
63
 
57
-
64
+
58
65
  if __name__ == '__main__':
59
66
  data = MyStruct(a=0, b=2.0, c=10000, d=14545)
60
-
67
+
61
68
  packed_data = data.pack()
62
69
  print(packed_data)
63
-
70
+
64
71
  restored = MyStruct.unpack(packed_data)
65
72
  print(restored)
66
-
73
+
67
74
  print(data == restored)
68
75
 
69
76
  ```
70
77
 
71
- 在上述示例中,你可能发现 `data != restored`,这是浮点数的精度限制导致的。
72
- 因此,我们不建议使用浮点数类型,浮点数在二进制传输中也不常见。
78
+ 在上述示例中,你可能发现 `data != restored`,这是浮点数的精度限制导致的。 因此,我们不建议使用浮点数类型,浮点数在二进制传输中也不常见。
73
79
 
74
80
  ## 计划
81
+
75
82
  - 展平装饰器,目前的 API 较为繁琐,需要简化为唯一的 `Struct` 基类
76
83
  - 继续优化性能
77
84
  - 通过存根文件强制表明类型似乎变得不再有效了
@@ -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.5"
@@ -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,18 +30,21 @@ class _objective_node_operator:
31
30
  self._node.body.append(tree)
32
31
  return tree
33
32
 
34
- # def insert_code(self, index, code: str):
35
- # tree = ast.parse(code)
36
- # if isinstance(tree, ast.Module):
37
- # for node in reversed(tree.body):
38
- # self._node.body.insert(index, node)
39
- # return tree
40
- # elif isinstance(tree, ast.Expr):
41
- # self._node.body.insert(index, tree.value)
42
- # return tree.value
43
- # else:
44
- # self._node.body.insert(index, tree)
45
- # return tree
33
+ def add_codes(self, codes: typing.Iterable[str]):
34
+ [self.add_code(c) for c in codes]
35
+
36
+ def insert_code(self, index, code: str):
37
+ tree = ast.parse(code)
38
+ if isinstance(tree, ast.Module):
39
+ for node in reversed(tree.body):
40
+ self._node.body.insert(index, node)
41
+ return tree
42
+ elif isinstance(tree, ast.Expr):
43
+ self._node.body.insert(index, tree.value)
44
+ return tree.value
45
+ else:
46
+ self._node.body.insert(index, tree)
47
+ return tree
46
48
 
47
49
  def compile(self):
48
50
  module = ast.Module([self._node])
@@ -54,6 +56,7 @@ class _objective_node_operator:
54
56
  def exec(self, globals=None, locals=None, closure=None):
55
57
  globals = globals or {}
56
58
  exec(self.compile(), globals, locals, closure=closure)
59
+ # print(repr(globals))
57
60
  return globals[self._node.name]
58
61
 
59
62
  def generate_code(self):
@@ -134,8 +137,13 @@ def get_array_spec(tp):
134
137
 
135
138
 
136
139
  def get_array_ctype(tp) -> str | None | Any:
140
+ from obstruct.methods import get_ctype
137
141
  return get_ctype(get_array_spec(tp)[0])
138
142
 
139
143
 
144
+ def get_array_length(tp):
145
+ return get_array_spec(tp)[1]
146
+
147
+
140
148
  def to_tuple_expression(names, prefix='self.'):
141
149
  return ', '.join(f'{prefix}{name}' for name in names)
@@ -0,0 +1,79 @@
1
+ from __future__ import annotations
2
+
3
+ import array
4
+ import struct
5
+ import typing
6
+
7
+ from .base import unique_name_generator, is_struct, is_array, get_array_ctype, to_tuple_expression, function_def, \
8
+ get_array_length
9
+
10
+ if typing.TYPE_CHECKING:
11
+ from .. import struct_type
12
+
13
+
14
+ def create_pack_methods(cls: type[struct_type.Struct]):
15
+ """
16
+ Generate `pack` and `pack_into` method
17
+ """
18
+ from obstruct.methods import get_ctype
19
+ with (
20
+ function_def('pack(self)') as pack,
21
+ function_def('pack_into(self, buffer, offset=0)') as pack_into,
22
+ ):
23
+ ung = unique_name_generator()
24
+ flat_fields = []
25
+ array_fields = []
26
+
27
+ def add_code(code):
28
+ pack.add_code(code)
29
+ pack_into.add_code(code)
30
+
31
+ def walk(fields, path, parent_name=None, offset=0):
32
+ # parent name 标识了这个字段的父字段被赋值给了哪个临时变量,这样可以复用已有的临时变量,减少结构体属性访问次数
33
+ name = path[-1] # 这里的 name 是默认的 self,如果当前处理的是内嵌的结构体,那么 name 会被替换成临时变量
34
+
35
+ if len(path) > 1: # 当前处理的是内嵌结构体
36
+ name = next(ung) # 生成一个临时变量缓存其值
37
+ add_code(f'{name} = {parent_name}.{path[-1]}')
38
+
39
+ for field in fields: # 遍历结构体的所有字段
40
+ if is_struct(field.type): # 又是一个内嵌的结构体字段
41
+ walk(field.type.__cfields__, path + (field.name,), name, offset) # 递归
42
+
43
+ elif is_array(field.type): # 一个数组类型
44
+ dtype = get_array_ctype(field.type)
45
+ nbytes = struct.calcsize(dtype) * get_array_length(field.type)
46
+
47
+ _ = next(ung)
48
+ add_code(f'{_} = array({dtype!r}, {name}.{field.name})')
49
+ # flat_fields.append(f'{_}.tobytes()')
50
+ array_fields.append((_, offset, nbytes))
51
+
52
+ else:
53
+ flat_fields.append(f'{name}.{field.name}') # 普通的字段,添加到传递目标列表中
54
+
55
+ offset += struct.calcsize(get_ctype(field.type))
56
+
57
+ walk(cls.__cfields__, ('self',)) # 启动递归函数
58
+ # names = [field.name for field in fields]
59
+
60
+ expression = to_tuple_expression(flat_fields, prefix='')
61
+
62
+ if array_fields: # 如果有数组字段,我们需要手动操作缓冲区
63
+ pack_into.insert_code(0, "buffer = memoryview(buffer)")
64
+ pack.add_code(f"buffer = bytearray({cls.__cstruct__.size})") # 初始化缓冲区
65
+ for array_name, offset, size in array_fields:
66
+ add_code(f"buffer[{offset}:{offset + size}] = memoryview({array_name}).cast('B')")
67
+
68
+ pack.add_code(f"_pack_into(buffer, 0, {expression})") # 返回打包的结果,将所有字段参数展开传递
69
+ pack.add_return("buffer")
70
+ else:
71
+ pack.add_return(f"_pack({expression})")
72
+
73
+ pack_into.add_code(f"_pack_into(buffer, offset, {expression})")
74
+ # print(pack.generate_code()) # Debug
75
+ # print(pack_into.generate_code()) # Debug
76
+ return (
77
+ pack.exec({'_pack': cls.__cstruct__.pack, '_pack_into': cls.__cstruct__.pack_into, 'array': array.array}),
78
+ pack_into.exec({'_pack_into': cls.__cstruct__.pack_into, 'array': array.array})
79
+ )