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.
- obstruct-0.2.5/.idea/modules.xml +8 -0
- obstruct-0.2.3/.idea/Hydrogenlib-Objective-Struct.iml → obstruct-0.2.5/.idea/obstruct.iml +1 -4
- {obstruct-0.2.3 → obstruct-0.2.5}/.idea/workspace.xml +61 -24
- {obstruct-0.2.3 → obstruct-0.2.5}/PKG-INFO +21 -14
- {obstruct-0.2.3 → obstruct-0.2.5}/README.md +20 -13
- {obstruct-0.2.3 → obstruct-0.2.5}/src/obstruct/__init__.py +0 -1
- obstruct-0.2.5/src/obstruct/__version__.py +1 -0
- {obstruct-0.2.3 → obstruct-0.2.5}/src/obstruct/aot/base.py +21 -13
- obstruct-0.2.5/src/obstruct/aot/pack.py +79 -0
- obstruct-0.2.5/src/obstruct/aot/unpack.py +191 -0
- {obstruct-0.2.3 → obstruct-0.2.5}/src/obstruct/methods.py +1 -1
- obstruct-0.2.5/src/obstruct/struct_type.py +132 -0
- obstruct-0.2.5/test/test_speed.py +103 -0
- obstruct-0.2.3/.idea/modules.xml +0 -8
- obstruct-0.2.3/src/obstruct/__version__.py +0 -1
- obstruct-0.2.3/src/obstruct/aot/pack.py +0 -58
- obstruct-0.2.3/src/obstruct/aot/unpack.py +0 -141
- obstruct-0.2.3/src/obstruct/decorator.py +0 -34
- obstruct-0.2.3/src/obstruct/struct_type.py +0 -52
- obstruct-0.2.3/test/test_speed.py +0 -60
- {obstruct-0.2.3 → obstruct-0.2.5}/.idea/.gitignore +0 -0
- {obstruct-0.2.3 → obstruct-0.2.5}/.idea/inspectionProfiles/Project_Default.xml +0 -0
- {obstruct-0.2.3 → obstruct-0.2.5}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
- {obstruct-0.2.3 → obstruct-0.2.5}/.idea/misc.xml +0 -0
- {obstruct-0.2.3 → obstruct-0.2.5}/.idea/vcs.xml +0 -0
- {obstruct-0.2.3 → obstruct-0.2.5}/pyproject.toml +0 -0
- {obstruct-0.2.3 → obstruct-0.2.5}/src/obstruct/aot/__init__.py +0 -0
- {obstruct-0.2.3 → obstruct-0.2.5}/src/obstruct/aot/aot.py +0 -0
- {obstruct-0.2.3 → obstruct-0.2.5}/src/obstruct/types/__init__.py +0 -0
- {obstruct-0.2.3 → obstruct-0.2.5}/src/obstruct/types/base.py +0 -0
- {obstruct-0.2.3 → obstruct-0.2.5}/src/obstruct/types/types.py +0 -0
- {obstruct-0.2.3 → obstruct-0.2.5}/src/obstruct/types/types.pyi +0 -0
- {obstruct-0.2.3 → obstruct-0.2.5}/test/test.py +0 -0
- {obstruct-0.2.3 → obstruct-0.2.5}/uv.lock +0 -0
|
@@ -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="
|
|
8
|
-
<change beforePath="$PROJECT_DIR$/
|
|
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"
|
|
13
|
-
<change beforePath="$PROJECT_DIR$/src/obstruct/
|
|
14
|
-
<change beforePath="$PROJECT_DIR$/
|
|
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"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
<component name="GitHubPullRequestSearchHistory">{
|
|
33
|
+
"lastFilter": {
|
|
34
|
+
"state": "OPEN",
|
|
35
|
+
"assignee": "LittleNightSong"
|
|
36
36
|
}
|
|
37
|
-
}
|
|
38
|
-
<component name="GithubPullRequestsUISettings"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
}</component>
|
|
38
|
+
<component name="GithubPullRequestsUISettings">{
|
|
39
|
+
"selectedUrlAndAccountId": {
|
|
40
|
+
"url": "https://github.com/LittleNightSong/obstruct.git",
|
|
41
|
+
"accountId": "c74c50b1-2437-429b-b395-d763b566b8a2"
|
|
42
42
|
}
|
|
43
|
-
}
|
|
44
|
-
<component name="ProjectColorInfo"
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
43
|
+
}</component>
|
|
44
|
+
<component name="ProjectColorInfo">{
|
|
45
|
+
"associatedIndex": 3,
|
|
46
|
+
"fromUser": 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="
|
|
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="
|
|
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
|
-
<
|
|
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
|
-
<
|
|
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
|
+
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
|
-
|
|
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
|
-
|
|
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
|
- 通过存根文件强制表明类型似乎变得不再有效了
|
|
@@ -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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
+
)
|