obstruct 0.2.1__tar.gz → 0.2.2__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.1 → obstruct-0.2.2}/.idea/Hydrogenlib-Objective-Struct.iml +1 -1
- obstruct-0.2.2/.idea/misc.xml +4 -0
- obstruct-0.2.2/.idea/vcs.xml +6 -0
- obstruct-0.2.2/.idea/workspace.xml +170 -0
- obstruct-0.2.2/PKG-INFO +76 -0
- obstruct-0.2.2/README.md +62 -0
- obstruct-0.2.2/src/obstruct/__version__.py +1 -0
- {obstruct-0.2.1 → obstruct-0.2.2}/src/obstruct/aot/base.py +1 -5
- {obstruct-0.2.1 → obstruct-0.2.2}/src/obstruct/aot/unpack.py +1 -1
- {obstruct-0.2.1 → obstruct-0.2.2}/src/obstruct/decorator.py +2 -9
- {obstruct-0.2.1 → obstruct-0.2.2}/src/obstruct/methods.py +4 -6
- obstruct-0.2.2/src/obstruct/types/types.pyi +33 -0
- obstruct-0.2.2/test/test.py +28 -0
- obstruct-0.2.2/test/test_speed.py +59 -0
- {obstruct-0.2.1 → obstruct-0.2.2}/uv.lock +14 -14
- obstruct-0.2.1/.hydro-ignore +0 -0
- obstruct-0.2.1/.idea/workspace.xml +0 -4
- obstruct-0.2.1/PKG-INFO +0 -12
- obstruct-0.2.1/README.md +0 -0
- obstruct-0.2.1/src/obstruct/__version__.py +0 -1
- obstruct-0.2.1/src/obstruct/types/types.pyi +0 -67
- {obstruct-0.2.1 → obstruct-0.2.2}/.idea/.gitignore +0 -0
- {obstruct-0.2.1 → obstruct-0.2.2}/.idea/inspectionProfiles/Project_Default.xml +0 -0
- {obstruct-0.2.1 → obstruct-0.2.2}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
- {obstruct-0.2.1 → obstruct-0.2.2}/.idea/modules.xml +0 -0
- {obstruct-0.2.1 → obstruct-0.2.2}/pyproject.toml +0 -0
- {obstruct-0.2.1 → obstruct-0.2.2}/src/obstruct/__init__.py +0 -0
- {obstruct-0.2.1 → obstruct-0.2.2}/src/obstruct/aot/__init__.py +0 -0
- {obstruct-0.2.1 → obstruct-0.2.2}/src/obstruct/aot/aot.py +0 -0
- {obstruct-0.2.1 → obstruct-0.2.2}/src/obstruct/aot/pack.py +0 -0
- {obstruct-0.2.1 → obstruct-0.2.2}/src/obstruct/struct_type.py +0 -0
- {obstruct-0.2.1 → obstruct-0.2.2}/src/obstruct/types/__init__.py +0 -0
- {obstruct-0.2.1 → obstruct-0.2.2}/src/obstruct/types/base.py +0 -0
- {obstruct-0.2.1 → obstruct-0.2.2}/src/obstruct/types/types.py +0 -0
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<sourceFolder url="file://$MODULE_DIR$/src" />
|
|
6
6
|
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
|
7
7
|
</content>
|
|
8
|
-
<orderEntry type="
|
|
8
|
+
<orderEntry type="jdk" jdkName="E:\.projects\obstruct\.venv" jdkType="Python SDK" />
|
|
9
9
|
<orderEntry type="sourceFolder" forTests="false" />
|
|
10
10
|
</component>
|
|
11
11
|
<component name="PackageRequirementsSettings" />
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="AutoImportSettings">
|
|
4
|
+
<option name="autoReloadType" value="SELECTIVE" />
|
|
5
|
+
</component>
|
|
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" />
|
|
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/unpack.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/obstruct/aot/unpack.py" afterDir="false" />
|
|
11
|
+
<change beforePath="$PROJECT_DIR$/src/obstruct/decorator.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/obstruct/decorator.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$/uv.lock" beforeDir="false" afterPath="$PROJECT_DIR$/uv.lock" afterDir="false" />
|
|
14
|
+
</list>
|
|
15
|
+
<option name="SHOW_DIALOG" value="false" />
|
|
16
|
+
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
17
|
+
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
18
|
+
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
19
|
+
</component>
|
|
20
|
+
<component name="FileTemplateManagerImpl">
|
|
21
|
+
<option name="RECENT_TEMPLATES">
|
|
22
|
+
<list>
|
|
23
|
+
<option value="Python Script" />
|
|
24
|
+
</list>
|
|
25
|
+
</option>
|
|
26
|
+
</component>
|
|
27
|
+
<component name="Git.Settings">
|
|
28
|
+
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
|
29
|
+
</component>
|
|
30
|
+
<component name="GitHubPullRequestSearchHistory"><![CDATA[{
|
|
31
|
+
"lastFilter": {
|
|
32
|
+
"state": "OPEN",
|
|
33
|
+
"assignee": "LittleNightSong"
|
|
34
|
+
}
|
|
35
|
+
}]]></component>
|
|
36
|
+
<component name="GithubPullRequestsUISettings"><![CDATA[{
|
|
37
|
+
"selectedUrlAndAccountId": {
|
|
38
|
+
"url": "https://github.com/LittleNightSong/obstruct.git",
|
|
39
|
+
"accountId": "c74c50b1-2437-429b-b395-d763b566b8a2"
|
|
40
|
+
}
|
|
41
|
+
}]]></component>
|
|
42
|
+
<component name="ProjectColorInfo"><![CDATA[{
|
|
43
|
+
"associatedIndex": 3,
|
|
44
|
+
"fromUser": false
|
|
45
|
+
}]]></component>
|
|
46
|
+
<component name="ProjectId" id="3HzAgHvw3X1T2NidzBlYQSHnZow" />
|
|
47
|
+
<component name="ProjectViewState">
|
|
48
|
+
<option name="hideEmptyMiddlePackages" value="true" />
|
|
49
|
+
<option name="showLibraryContents" value="true" />
|
|
50
|
+
</component>
|
|
51
|
+
<component name="PropertiesComponent"><![CDATA[{
|
|
52
|
+
"keyToString": {
|
|
53
|
+
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
|
54
|
+
"Python.test.executor": "Run",
|
|
55
|
+
"Python.test_speed.executor": "Run",
|
|
56
|
+
"RunOnceActivity.ShowReadmeOnStart": "true",
|
|
57
|
+
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
|
|
58
|
+
"codeWithMe.voiceChat.enabledByDefault": "false",
|
|
59
|
+
"git-widget-placeholder": "main",
|
|
60
|
+
"last_opened_file_path": "E:/.projects/obstruct",
|
|
61
|
+
"node.js.detected.package.eslint": "true",
|
|
62
|
+
"node.js.detected.package.jshint": "true",
|
|
63
|
+
"node.js.detected.package.tslint": "true",
|
|
64
|
+
"node.js.selected.package.eslint": "(autodetect)",
|
|
65
|
+
"node.js.selected.package.jshint": "",
|
|
66
|
+
"node.js.selected.package.tslint": "(autodetect)",
|
|
67
|
+
"nodejs_package_manager_path": "npm"
|
|
68
|
+
}
|
|
69
|
+
}]]></component>
|
|
70
|
+
<component name="RunManager" selected="Python.test_speed">
|
|
71
|
+
<configuration name="test" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
|
72
|
+
<module name="Hydrogenlib-Objective-Struct" />
|
|
73
|
+
<option name="ENV_FILES" value="" />
|
|
74
|
+
<option name="INTERPRETER_OPTIONS" value="" />
|
|
75
|
+
<option name="PARENT_ENVS" value="true" />
|
|
76
|
+
<envs>
|
|
77
|
+
<env name="PYTHONUNBUFFERED" value="1" />
|
|
78
|
+
</envs>
|
|
79
|
+
<option name="SDK_HOME" value="" />
|
|
80
|
+
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/test" />
|
|
81
|
+
<option name="IS_MODULE_SDK" value="true" />
|
|
82
|
+
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
83
|
+
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
84
|
+
<option name="DEBUG_JUST_MY_CODE" value="false" />
|
|
85
|
+
<option name="RUN_TOOL" value="" />
|
|
86
|
+
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/test/test.py" />
|
|
87
|
+
<option name="PARAMETERS" value="" />
|
|
88
|
+
<option name="SHOW_COMMAND_LINE" value="false" />
|
|
89
|
+
<option name="EMULATE_TERMINAL" value="false" />
|
|
90
|
+
<option name="MODULE_MODE" value="false" />
|
|
91
|
+
<option name="REDIRECT_INPUT" value="false" />
|
|
92
|
+
<option name="INPUT_FILE" value="" />
|
|
93
|
+
<method v="2" />
|
|
94
|
+
</configuration>
|
|
95
|
+
<configuration name="test_speed" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
|
96
|
+
<module name="Hydrogenlib-Objective-Struct" />
|
|
97
|
+
<option name="ENV_FILES" value="" />
|
|
98
|
+
<option name="INTERPRETER_OPTIONS" value="" />
|
|
99
|
+
<option name="PARENT_ENVS" value="true" />
|
|
100
|
+
<envs>
|
|
101
|
+
<env name="PYTHONUNBUFFERED" value="1" />
|
|
102
|
+
</envs>
|
|
103
|
+
<option name="SDK_HOME" value="" />
|
|
104
|
+
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/test" />
|
|
105
|
+
<option name="IS_MODULE_SDK" value="true" />
|
|
106
|
+
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
107
|
+
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
108
|
+
<option name="DEBUG_JUST_MY_CODE" value="false" />
|
|
109
|
+
<option name="RUN_TOOL" value="" />
|
|
110
|
+
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/test/test_speed.py" />
|
|
111
|
+
<option name="PARAMETERS" value="" />
|
|
112
|
+
<option name="SHOW_COMMAND_LINE" value="false" />
|
|
113
|
+
<option name="EMULATE_TERMINAL" value="false" />
|
|
114
|
+
<option name="MODULE_MODE" value="false" />
|
|
115
|
+
<option name="REDIRECT_INPUT" value="false" />
|
|
116
|
+
<option name="INPUT_FILE" value="" />
|
|
117
|
+
<method v="2" />
|
|
118
|
+
</configuration>
|
|
119
|
+
<recent_temporary>
|
|
120
|
+
<list>
|
|
121
|
+
<item itemvalue="Python.test_speed" />
|
|
122
|
+
<item itemvalue="Python.test" />
|
|
123
|
+
</list>
|
|
124
|
+
</recent_temporary>
|
|
125
|
+
</component>
|
|
126
|
+
<component name="SharedIndexes">
|
|
127
|
+
<attachedChunks>
|
|
128
|
+
<set>
|
|
129
|
+
<option value="bundled-python-sdk-821f704e66d9-5bd6d13a2a75-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-262.9437.214" />
|
|
130
|
+
</set>
|
|
131
|
+
</attachedChunks>
|
|
132
|
+
</component>
|
|
133
|
+
<component name="TaskManager">
|
|
134
|
+
<task active="true" id="Default" summary="默认任务">
|
|
135
|
+
<changelist id="b482b6b4-48ce-4be1-bf3c-a72ec254fa35" name="更改" comment="" />
|
|
136
|
+
<created>1786860632989</created>
|
|
137
|
+
<option name="number" value="Default" />
|
|
138
|
+
<option name="presentableId" value="Default" />
|
|
139
|
+
<updated>1786860632989</updated>
|
|
140
|
+
</task>
|
|
141
|
+
<task id="LOCAL-00001" summary="initial commit">
|
|
142
|
+
<option name="closed" value="true" />
|
|
143
|
+
<created>1786865208583</created>
|
|
144
|
+
<option name="number" value="00001" />
|
|
145
|
+
<option name="presentableId" value="LOCAL-00001" />
|
|
146
|
+
<option name="project" value="LOCAL" />
|
|
147
|
+
<updated>1786865208583</updated>
|
|
148
|
+
</task>
|
|
149
|
+
<option name="localTasksCounter" value="2" />
|
|
150
|
+
<servers />
|
|
151
|
+
</component>
|
|
152
|
+
<component name="TypeScriptGeneratedFilesManager">
|
|
153
|
+
<option name="version" value="3" />
|
|
154
|
+
</component>
|
|
155
|
+
<component name="Vcs.Log.Tabs.Properties">
|
|
156
|
+
<option name="TAB_STATES">
|
|
157
|
+
<map>
|
|
158
|
+
<entry key="MAIN">
|
|
159
|
+
<value>
|
|
160
|
+
<State />
|
|
161
|
+
</value>
|
|
162
|
+
</entry>
|
|
163
|
+
</map>
|
|
164
|
+
</option>
|
|
165
|
+
</component>
|
|
166
|
+
<component name="VcsManagerConfiguration">
|
|
167
|
+
<MESSAGE value="initial commit" />
|
|
168
|
+
<option name="LAST_COMMIT_MESSAGE" value="initial commit" />
|
|
169
|
+
</component>
|
|
170
|
+
</project>
|
obstruct-0.2.2/PKG-INFO
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: obstruct
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Author-email: LittleNightSong <LittleNightSongYO@outlook.com>
|
|
5
|
+
Classifier: Development Status :: 3 - Alpha
|
|
6
|
+
Classifier: Programming Language :: Python
|
|
7
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
10
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
11
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
12
|
+
Requires-Python: >=3.12
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
_来自已弃坑的 `Hydrogenlib`,重拾起当初的决心_
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
>[!TIP]
|
|
19
|
+
> 这个项目来自 [`HydrogenLib`](https://github.com/LittleNightSong/HydrogenLib)的 `Objective-Struct` 模块,脱离大项目的版本
|
|
20
|
+
>
|
|
21
|
+
> 同时,`HydrogenLib`中的 `Objective-Struct` 不再会更新
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# OBStruct
|
|
25
|
+
_一个简单、纯粹、极速的二进制解析库_
|
|
26
|
+
|
|
27
|
+
## 亮点
|
|
28
|
+
- 基于类型注解的字段声明方式
|
|
29
|
+
- 支持 `struct` 标准库中的所有格式,并额外支持 array 类型
|
|
30
|
+
- 基于 AOT 的加速
|
|
31
|
+
- 完整的操作支持(打包、解包、流式处理)
|
|
32
|
+
|
|
33
|
+
## 安装
|
|
34
|
+
```commandline
|
|
35
|
+
pip install obstruct
|
|
36
|
+
```
|
|
37
|
+
如果使用 `uv` 等包管理器,则按照工具的方法安装即可
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
## 用法
|
|
41
|
+
|
|
42
|
+
首先声明一个 `Struct` 类型,它是一个 `dataclass`,也是一个 `struct`
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
import obstruct as obs
|
|
46
|
+
from dataclasses import dataclass
|
|
47
|
+
|
|
48
|
+
@obs.struct()
|
|
49
|
+
@dataclass()
|
|
50
|
+
class MyStruct(obs.Struct):
|
|
51
|
+
a: int
|
|
52
|
+
b: float
|
|
53
|
+
c: obs.long
|
|
54
|
+
d: obs.unsigned_short
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
if __name__ == '__main__':
|
|
58
|
+
data = MyStruct(a=0, b=2.0, c=10000, d=14545)
|
|
59
|
+
|
|
60
|
+
packed_data = data.pack()
|
|
61
|
+
print(packed_data)
|
|
62
|
+
|
|
63
|
+
restored = MyStruct.unpack(packed_data)
|
|
64
|
+
print(restored)
|
|
65
|
+
|
|
66
|
+
print(data == restored)
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
在上述示例中,你可能发现 `data != restored`,这是浮点数的精度限制导致的
|
|
71
|
+
一般来说,我们不建议使用浮点数类型
|
|
72
|
+
|
|
73
|
+
## 计划
|
|
74
|
+
- 展平装饰器,目前的 API 较为繁琐,需要简化为唯一的 `Struct` 基类
|
|
75
|
+
- 继续优化性能
|
|
76
|
+
- 通过存根文件强制表明类型似乎变得不再有效了
|
obstruct-0.2.2/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
_来自已弃坑的 `Hydrogenlib`,重拾起当初的决心_
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
>[!TIP]
|
|
5
|
+
> 这个项目来自 [`HydrogenLib`](https://github.com/LittleNightSong/HydrogenLib)的 `Objective-Struct` 模块,脱离大项目的版本
|
|
6
|
+
>
|
|
7
|
+
> 同时,`HydrogenLib`中的 `Objective-Struct` 不再会更新
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# OBStruct
|
|
11
|
+
_一个简单、纯粹、极速的二进制解析库_
|
|
12
|
+
|
|
13
|
+
## 亮点
|
|
14
|
+
- 基于类型注解的字段声明方式
|
|
15
|
+
- 支持 `struct` 标准库中的所有格式,并额外支持 array 类型
|
|
16
|
+
- 基于 AOT 的加速
|
|
17
|
+
- 完整的操作支持(打包、解包、流式处理)
|
|
18
|
+
|
|
19
|
+
## 安装
|
|
20
|
+
```commandline
|
|
21
|
+
pip install obstruct
|
|
22
|
+
```
|
|
23
|
+
如果使用 `uv` 等包管理器,则按照工具的方法安装即可
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
## 用法
|
|
27
|
+
|
|
28
|
+
首先声明一个 `Struct` 类型,它是一个 `dataclass`,也是一个 `struct`
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
import obstruct as obs
|
|
32
|
+
from dataclasses import dataclass
|
|
33
|
+
|
|
34
|
+
@obs.struct()
|
|
35
|
+
@dataclass()
|
|
36
|
+
class MyStruct(obs.Struct):
|
|
37
|
+
a: int
|
|
38
|
+
b: float
|
|
39
|
+
c: obs.long
|
|
40
|
+
d: obs.unsigned_short
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if __name__ == '__main__':
|
|
44
|
+
data = MyStruct(a=0, b=2.0, c=10000, d=14545)
|
|
45
|
+
|
|
46
|
+
packed_data = data.pack()
|
|
47
|
+
print(packed_data)
|
|
48
|
+
|
|
49
|
+
restored = MyStruct.unpack(packed_data)
|
|
50
|
+
print(restored)
|
|
51
|
+
|
|
52
|
+
print(data == restored)
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
在上述示例中,你可能发现 `data != restored`,这是浮点数的精度限制导致的
|
|
57
|
+
一般来说,我们不建议使用浮点数类型
|
|
58
|
+
|
|
59
|
+
## 计划
|
|
60
|
+
- 展平装饰器,目前的 API 较为繁琐,需要简化为唯一的 `Struct` 基类
|
|
61
|
+
- 继续优化性能
|
|
62
|
+
- 通过存根文件强制表明类型似乎变得不再有效了
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
version = "0.2.2"
|
|
@@ -5,9 +5,6 @@ import itertools
|
|
|
5
5
|
import typing
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
|
-
import typing_inspection.typing_objects
|
|
9
|
-
|
|
10
|
-
from _hydrogenlib_core.typefunc import enhanced_generator
|
|
11
8
|
from obstruct.methods import get_ctype
|
|
12
9
|
|
|
13
10
|
|
|
@@ -113,7 +110,6 @@ available_characters = tuple(
|
|
|
113
110
|
)
|
|
114
111
|
|
|
115
112
|
|
|
116
|
-
@enhanced_generator(history=True)
|
|
117
113
|
def unique_name_generator():
|
|
118
114
|
cnt = 0
|
|
119
115
|
while True:
|
|
@@ -127,7 +123,7 @@ def is_struct(tp):
|
|
|
127
123
|
|
|
128
124
|
|
|
129
125
|
def is_array(tp):
|
|
130
|
-
if
|
|
126
|
+
if typing.get_origin(tp) is typing.Annotated:
|
|
131
127
|
return True
|
|
132
128
|
return False
|
|
133
129
|
|
|
@@ -112,7 +112,7 @@ def create_unpack_methods(cls: type[struct_type.Struct]):
|
|
|
112
112
|
# print(unpack_from.generate_code())
|
|
113
113
|
# print(update_from.generate_code())
|
|
114
114
|
# print(iter_unpack.generate_code())
|
|
115
|
-
print(iter_update.generate_code())
|
|
115
|
+
# print(iter_update.generate_code())
|
|
116
116
|
|
|
117
117
|
globals = {
|
|
118
118
|
v: k for k, v in inner_classes.items() # 翻转字典
|
|
@@ -9,24 +9,17 @@ endian_control_characters = tuple('<@=!>')
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def struct(maybe_cls=None, *, endian='@'):
|
|
12
|
-
def decorator[T](cls: T) ->
|
|
12
|
+
def decorator[T](cls: T) -> T:
|
|
13
13
|
import struct
|
|
14
|
-
|
|
15
|
-
# module = sys.modules[cls.__module__]
|
|
16
|
-
|
|
17
14
|
fields = dataclasses.fields(cls)
|
|
18
|
-
# namesp = module.__dict__
|
|
19
|
-
# print(namesp)
|
|
20
15
|
real_annotations = typing.get_type_hints(cls)
|
|
21
|
-
# print(cls, real_annotations)
|
|
22
16
|
|
|
23
17
|
for field in fields:
|
|
24
|
-
print(cls, field.name, repr(field.type))
|
|
18
|
+
# print(cls, field.name, repr(field.type))
|
|
25
19
|
if isinstance(field.type, str):
|
|
26
20
|
field.type = real_annotations[field.name]
|
|
27
21
|
|
|
28
22
|
cls.__ctype__ = to_format_string([field.type for field in fields])
|
|
29
|
-
# print(cls.__ctype__)
|
|
30
23
|
cls.__cfields__ = tuple(fields) # type: tuple[dataclasses.Field, ...]
|
|
31
24
|
cls.__cstruct__ = struct.Struct(endian + cls.__ctype__) # 构造 Struct 类型
|
|
32
25
|
cls.__cendian__ = endian
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import struct
|
|
2
2
|
from collections.abc import Buffer
|
|
3
|
-
from typing import Any, Sequence, Iterator, get_args, get_origin
|
|
4
|
-
|
|
5
|
-
from typing_inspection.typing_objects import is_annotated
|
|
3
|
+
from typing import Any, Sequence, Iterator, get_args, get_origin, Annotated, cast
|
|
6
4
|
|
|
7
5
|
from .struct_type import CType
|
|
8
6
|
|
|
@@ -13,14 +11,14 @@ mapping = {
|
|
|
13
11
|
CTypesFields = Sequence[str | CType | type] | Iterator[str | CType | type]
|
|
14
12
|
|
|
15
13
|
|
|
16
|
-
def get_ctype(tp):
|
|
14
|
+
def get_ctype(tp) -> str:
|
|
17
15
|
if isinstance(tp, str):
|
|
18
16
|
return tp
|
|
19
17
|
elif _ := getattr(tp, '__ctype__', None):
|
|
20
|
-
return _
|
|
18
|
+
return cast(str, _)
|
|
21
19
|
elif _ := mapping.get(tp):
|
|
22
20
|
return _
|
|
23
|
-
elif
|
|
21
|
+
elif get_origin(tp) is Annotated:
|
|
24
22
|
# 目前需要 Annotated 的类型只有 array
|
|
25
23
|
tp_args = get_args(tp)
|
|
26
24
|
dtype = get_args(tp_args[0])[0]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def pad(size: int) -> type: ...
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
char = bytes
|
|
8
|
+
signed_char = int
|
|
9
|
+
unsigned_char = int
|
|
10
|
+
long = int
|
|
11
|
+
unsigned_long = int
|
|
12
|
+
short = int
|
|
13
|
+
unsigned_short = int
|
|
14
|
+
unsigned_int = int
|
|
15
|
+
long_long = int
|
|
16
|
+
unsigned_long_long = int
|
|
17
|
+
double = float
|
|
18
|
+
short_float = float
|
|
19
|
+
size_t = int
|
|
20
|
+
ssize_t = int
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def string(length: int) -> type[bytes]: ...
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def pascal_string(length: int) -> type[bytes]: ...
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
pointer = int
|
|
30
|
+
|
|
31
|
+
if sys.version_info >= (3, 14, 0):
|
|
32
|
+
float_complex = complex
|
|
33
|
+
double_complex = complex
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
|
|
3
|
+
import obstruct as obs
|
|
4
|
+
from obstruct import Struct
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@obs.struct()
|
|
8
|
+
@dataclasses.dataclass(slots=True)
|
|
9
|
+
class MyStruct(Struct):
|
|
10
|
+
a: int
|
|
11
|
+
b: int
|
|
12
|
+
c: float
|
|
13
|
+
d: obs.double_complex
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
if __name__ == '__main__':
|
|
18
|
+
data = MyStruct(15, 20, 1.2, 8 + 7j)
|
|
19
|
+
print(data)
|
|
20
|
+
|
|
21
|
+
packed_data = data.pack()
|
|
22
|
+
|
|
23
|
+
print(packed_data)
|
|
24
|
+
|
|
25
|
+
restored = MyStruct.unpack(packed_data)
|
|
26
|
+
print(restored)
|
|
27
|
+
|
|
28
|
+
print(data == restored)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
import time
|
|
3
|
+
|
|
4
|
+
import obstruct as obs
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@obs.struct()
|
|
8
|
+
@dataclasses.dataclass(slots=True)
|
|
9
|
+
class MyStruct(obs.Struct):
|
|
10
|
+
a: int
|
|
11
|
+
b: int
|
|
12
|
+
c: float
|
|
13
|
+
d: int
|
|
14
|
+
e: obs.short
|
|
15
|
+
f: obs.unsigned_short
|
|
16
|
+
g: obs.long
|
|
17
|
+
h: obs.unsigned_long
|
|
18
|
+
i: obs.unsigned_long
|
|
19
|
+
j: obs.char
|
|
20
|
+
k: obs.unsigned_char
|
|
21
|
+
l: obs.long_long
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
data = MyStruct(
|
|
26
|
+
1,2,1.0,4,5,6,7,8,9,b'8',1,2
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
packed_data = data.pack()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_timeit(name, code):
|
|
34
|
+
import timeit
|
|
35
|
+
|
|
36
|
+
print("Test: ", name)
|
|
37
|
+
res = timeit.timeit(
|
|
38
|
+
code,
|
|
39
|
+
number=NUMBER,
|
|
40
|
+
timer=time.perf_counter_ns,
|
|
41
|
+
globals=globals()
|
|
42
|
+
)
|
|
43
|
+
print(f'{NUMBER} steps finished in {res:.3f} ns')
|
|
44
|
+
print(f'Average: {res/NUMBER:.3f} ns per step', '\n\n')
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
NUMBER = 10000
|
|
48
|
+
|
|
49
|
+
test_timeit(
|
|
50
|
+
name='Pack',
|
|
51
|
+
code="""data.pack()""",
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
test_timeit(
|
|
55
|
+
name='Unpack',
|
|
56
|
+
code="""MyStruct.unpack(packed_data)""",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
@@ -303,20 +303,6 @@ wheels = [
|
|
|
303
303
|
{ url = "https://mirrors.aliyun.com/pypi/packages/9b/43/832f631d32e4f1211caa2ba368317739fe71f0b8530e4c9d15dc454bac2a/httpx2_jsfetch-1.0-py3-none-any.whl", hash = "sha256:cb916b707601e69a07721aabc8f3f6659be3a6893bc1ff5c6f9e02241df2da32" },
|
|
304
304
|
]
|
|
305
305
|
|
|
306
|
-
[[package]]
|
|
307
|
-
name = "hydrogenlib-objective-struct"
|
|
308
|
-
source = { editable = "." }
|
|
309
|
-
|
|
310
|
-
[package.dev-dependencies]
|
|
311
|
-
dev = [
|
|
312
|
-
{ name = "hatch" },
|
|
313
|
-
]
|
|
314
|
-
|
|
315
|
-
[package.metadata]
|
|
316
|
-
|
|
317
|
-
[package.metadata.requires-dev]
|
|
318
|
-
dev = [{ name = "hatch", specifier = ">=1.18.0" }]
|
|
319
|
-
|
|
320
306
|
[[package]]
|
|
321
307
|
name = "hyperlink"
|
|
322
308
|
version = "21.0.0"
|
|
@@ -427,6 +413,20 @@ wheels = [
|
|
|
427
413
|
{ url = "https://mirrors.aliyun.com/pypi/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl", hash = "sha256:4b65538ae22f6fed0ce4874efd317463a7489796a0939fa66824dd542125a192" },
|
|
428
414
|
]
|
|
429
415
|
|
|
416
|
+
[[package]]
|
|
417
|
+
name = "obstruct"
|
|
418
|
+
source = { editable = "." }
|
|
419
|
+
|
|
420
|
+
[package.dev-dependencies]
|
|
421
|
+
dev = [
|
|
422
|
+
{ name = "hatch" },
|
|
423
|
+
]
|
|
424
|
+
|
|
425
|
+
[package.metadata]
|
|
426
|
+
|
|
427
|
+
[package.metadata.requires-dev]
|
|
428
|
+
dev = [{ name = "hatch", specifier = ">=1.18.0" }]
|
|
429
|
+
|
|
430
430
|
[[package]]
|
|
431
431
|
name = "packaging"
|
|
432
432
|
version = "26.3"
|
obstruct-0.2.1/.hydro-ignore
DELETED
|
File without changes
|
obstruct-0.2.1/PKG-INFO
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.5
|
|
2
|
-
Name: obstruct
|
|
3
|
-
Version: 0.2.1
|
|
4
|
-
Author-email: LittleNightSong <LittleNightSongYO@outlook.com>
|
|
5
|
-
Classifier: Development Status :: 3 - Alpha
|
|
6
|
-
Classifier: Programming Language :: Python
|
|
7
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
8
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
9
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
10
|
-
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
11
|
-
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
12
|
-
Requires-Python: >=3.12
|
obstruct-0.2.1/README.md
DELETED
|
File without changes
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
version = "0.2.1"
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import sys
|
|
2
|
-
from typing import Literal, Sequence
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class _ctype:
|
|
6
|
-
__ctype__: str
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def pad(size: int) -> type: ...
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class char(bytes, _ctype): ...
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class signed_char(int, _ctype): ...
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class unsigned_char(int, _ctype): ...
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class long(int, _ctype): ...
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class unsigned_long(int, _ctype): ...
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class short(int, _ctype): ...
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class unsigned_short(int, _ctype): ...
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class unsigned_int(int, _ctype): ...
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class long_long(int, _ctype): ...
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
class unsigned_long_long(int, _ctype): ...
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
class double(float, _ctype): ...
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class short_float(float, _ctype): ...
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
class size_t(int, _ctype): ...
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class ssize_t(int, _ctype): ...
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def string(length: int) -> type[bytes]: ...
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def pascal_string(length: int) -> type[bytes]: ...
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
class pointer(int, _ctype): ...
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if sys.version_info >= (3, 14, 0):
|
|
64
|
-
class float_complex(complex, _ctype): ...
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
class double_complex(complex, _ctype): ...
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|