pymergetic-common 0.0.1__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.
- pymergetic_common-0.0.1/.github/workflows/publish.yml +39 -0
- pymergetic_common-0.0.1/.gitignore +207 -0
- pymergetic_common-0.0.1/.old/examples/pydataobject_roundtrip.py +36 -0
- pymergetic_common-0.0.1/.old/examples/pyobject_pydantic.py +29 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/__cpp__.cpp +3 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/base/__init__.cpp +9 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/base/__init__.hpp +6 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/base/base.hpp +14 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/base/defs.hpp +14 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/codec/__init__.cpp +9 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/codec/__init__.hpp +163 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/exceptions/__init__.cpp +17 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/exceptions/__init__.hpp +28 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/header/__init__.cpp +9 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/header/__init__.hpp +5 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/nb/__init__.cpp +9 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/nb/__init__.hpp +7 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/nb/asyncio_bridge.hpp +32 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/nb/base.hpp +26 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/nb/data.hpp +34 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/net/__init__.cpp +328 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/net/__init__.hpp +10 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/net/acceptor.hpp +93 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/net/peer_info.hpp +63 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/net/pmdg_channel.hpp +109 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/net/stream.hpp +28 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/net/tcp.hpp +112 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/net/uds.hpp +119 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/objects/__init__.cpp +9 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/objects/__init__.hpp +5 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/objects/data.hpp +27 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/runtime/__init__.cpp +9 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/runtime/__init__.hpp +5 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/runtime/asio_runtime.hpp +60 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/session/__init__.cpp +41 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/session/__init__.hpp +4 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/session/session.hpp +78 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/test/__init__.cpp +346 -0
- pymergetic_common-0.0.1/.old/src_cpp/pymergetic/common/test/__init__.hpp +5 -0
- pymergetic_common-0.0.1/.old/src_py/pymergetic/common/__init__.py +11 -0
- pymergetic_common-0.0.1/.old/src_py/pymergetic/common/__project__.py +19 -0
- pymergetic_common-0.0.1/.old/src_py/pymergetic/common/base/__init__.py +0 -0
- pymergetic_common-0.0.1/.old/src_py/pymergetic/common/codec/__init__.py +74 -0
- pymergetic_common-0.0.1/.old/src_py/pymergetic/common/exceptions/__init__.py +29 -0
- pymergetic_common-0.0.1/.old/src_py/pymergetic/common/header/__init__.py +20 -0
- pymergetic_common-0.0.1/.old/src_py/pymergetic/common/header/decorators.py +17 -0
- pymergetic_common-0.0.1/.old/src_py/pymergetic/common/header/exceptions.py +42 -0
- pymergetic_common-0.0.1/.old/src_py/pymergetic/common/header/resolve.py +66 -0
- pymergetic_common-0.0.1/.old/src_py/pymergetic/common/header/types.py +127 -0
- pymergetic_common-0.0.1/.old/src_py/pymergetic/common/net/__init__.py +46 -0
- pymergetic_common-0.0.1/.old/src_py/pymergetic/common/net/peer_info.py +21 -0
- pymergetic_common-0.0.1/.old/src_py/pymergetic/common/objects/__init__.py +6 -0
- pymergetic_common-0.0.1/.old/src_py/pymergetic/common/objects/pydataobject.py +145 -0
- pymergetic_common-0.0.1/.old/src_py/pymergetic/common/objects/pyobject.py +77 -0
- pymergetic_common-0.0.1/.old/src_py/pymergetic/common/runtime/__init__.py +0 -0
- pymergetic_common-0.0.1/.old/src_py/pymergetic/common/session/__init__.py +58 -0
- pymergetic_common-0.0.1/.old/src_py/pymergetic/common/test/__init__.py +3 -0
- pymergetic_common-0.0.1/.old/tests/fixtures/hdrpkg/__header__.py +13 -0
- pymergetic_common-0.0.1/.old/tests/fixtures/hdrpkg/__impl__.py +8 -0
- pymergetic_common-0.0.1/.old/tests/fixtures/hdrpkg/__init__.py +5 -0
- pymergetic_common-0.0.1/.old/tests/test_asyncio_bridge.py +31 -0
- pymergetic_common-0.0.1/.old/tests/test_codec_python_mirror.py +19 -0
- pymergetic_common-0.0.1/.old/tests/test_cpp_extension.py +50 -0
- pymergetic_common-0.0.1/.old/tests/test_header_resolution.py +20 -0
- pymergetic_common-0.0.1/.old/tests/test_net_pmdg_channel.py +56 -0
- pymergetic_common-0.0.1/.old/tests/test_pydataobject.py +84 -0
- pymergetic_common-0.0.1/.old/tests/test_pyobject.py +53 -0
- pymergetic_common-0.0.1/.old/tests/test_session_policy.py +81 -0
- pymergetic_common-0.0.1/PKG-INFO +127 -0
- pymergetic_common-0.0.1/README.md +75 -0
- pymergetic_common-0.0.1/RELEASING.md +93 -0
- pymergetic_common-0.0.1/pyproject.toml +98 -0
- pymergetic_common-0.0.1/pytest.ini +5 -0
- pymergetic_common-0.0.1/setup.cfg +4 -0
- pymergetic_common-0.0.1/src_py/pymergetic/__init__.py +3 -0
- pymergetic_common-0.0.1/src_py/pymergetic/common/__init__.py +5 -0
- pymergetic_common-0.0.1/src_py/pymergetic/common/__project__.py +18 -0
- pymergetic_common-0.0.1/src_py/pymergetic/common/devtools/__init__.py +75 -0
- pymergetic_common-0.0.1/src_py/pymergetic/common/devtools/pin_pyproject.py +511 -0
- pymergetic_common-0.0.1/src_py/pymergetic/common/devtools/project_paths.py +102 -0
- pymergetic_common-0.0.1/src_py/pymergetic/common/devtools/release_helpers.py +154 -0
- pymergetic_common-0.0.1/src_py/pymergetic/common/devtools/release_tag.py +152 -0
- pymergetic_common-0.0.1/src_py/pymergetic/common/devtools/wait_pypi.py +85 -0
- pymergetic_common-0.0.1/src_py/pymergetic/common/header/__init__.py +20 -0
- pymergetic_common-0.0.1/src_py/pymergetic/common/header/decorators.py +17 -0
- pymergetic_common-0.0.1/src_py/pymergetic/common/header/exceptions.py +42 -0
- pymergetic_common-0.0.1/src_py/pymergetic/common/header/resolve.py +66 -0
- pymergetic_common-0.0.1/src_py/pymergetic/common/header/types.py +127 -0
- pymergetic_common-0.0.1/src_py/pymergetic/common/sysinfo/__init__.py +21 -0
- pymergetic_common-0.0.1/src_py/pymergetic_common.egg-info/PKG-INFO +127 -0
- pymergetic_common-0.0.1/src_py/pymergetic_common.egg-info/SOURCES.txt +93 -0
- pymergetic_common-0.0.1/src_py/pymergetic_common.egg-info/dependency_links.txt +1 -0
- pymergetic_common-0.0.1/src_py/pymergetic_common.egg-info/entry_points.txt +4 -0
- pymergetic_common-0.0.1/src_py/pymergetic_common.egg-info/requires.txt +47 -0
- pymergetic_common-0.0.1/src_py/pymergetic_common.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Publish sdist + pure-Python wheel to PyPI on tag v*.
|
|
2
|
+
# Requires repository secret: PYPI_API_TOKEN
|
|
3
|
+
|
|
4
|
+
name: Publish to PyPI
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
tags:
|
|
9
|
+
- "v*"
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
publish:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
with:
|
|
20
|
+
fetch-depth: 0
|
|
21
|
+
|
|
22
|
+
- uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.12"
|
|
25
|
+
|
|
26
|
+
- name: Install build tools
|
|
27
|
+
run: pip install --upgrade build twine
|
|
28
|
+
|
|
29
|
+
- name: Build sdist and wheel
|
|
30
|
+
run: python -m build
|
|
31
|
+
|
|
32
|
+
- name: Check distributions
|
|
33
|
+
run: twine check dist/*
|
|
34
|
+
|
|
35
|
+
- name: Publish to PyPI
|
|
36
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
37
|
+
with:
|
|
38
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
39
|
+
skip-existing: true
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
#Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# UV
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
#uv.lock
|
|
102
|
+
|
|
103
|
+
# poetry
|
|
104
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
105
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
106
|
+
# commonly ignored for libraries.
|
|
107
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
108
|
+
#poetry.lock
|
|
109
|
+
#poetry.toml
|
|
110
|
+
|
|
111
|
+
# pdm
|
|
112
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
113
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
114
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
115
|
+
#pdm.lock
|
|
116
|
+
#pdm.toml
|
|
117
|
+
.pdm-python
|
|
118
|
+
.pdm-build/
|
|
119
|
+
|
|
120
|
+
# pixi
|
|
121
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
122
|
+
#pixi.lock
|
|
123
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
124
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
125
|
+
.pixi
|
|
126
|
+
|
|
127
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
128
|
+
__pypackages__/
|
|
129
|
+
|
|
130
|
+
# Celery stuff
|
|
131
|
+
celerybeat-schedule
|
|
132
|
+
celerybeat.pid
|
|
133
|
+
|
|
134
|
+
# SageMath parsed files
|
|
135
|
+
*.sage.py
|
|
136
|
+
|
|
137
|
+
# Environments
|
|
138
|
+
.env
|
|
139
|
+
.envrc
|
|
140
|
+
.venv
|
|
141
|
+
env/
|
|
142
|
+
venv/
|
|
143
|
+
ENV/
|
|
144
|
+
env.bak/
|
|
145
|
+
venv.bak/
|
|
146
|
+
|
|
147
|
+
# Spyder project settings
|
|
148
|
+
.spyderproject
|
|
149
|
+
.spyproject
|
|
150
|
+
|
|
151
|
+
# Rope project settings
|
|
152
|
+
.ropeproject
|
|
153
|
+
|
|
154
|
+
# mkdocs documentation
|
|
155
|
+
/site
|
|
156
|
+
|
|
157
|
+
# mypy
|
|
158
|
+
.mypy_cache/
|
|
159
|
+
.dmypy.json
|
|
160
|
+
dmypy.json
|
|
161
|
+
|
|
162
|
+
# Pyre type checker
|
|
163
|
+
.pyre/
|
|
164
|
+
|
|
165
|
+
# pytype static type analyzer
|
|
166
|
+
.pytype/
|
|
167
|
+
|
|
168
|
+
# Cython debug symbols
|
|
169
|
+
cython_debug/
|
|
170
|
+
|
|
171
|
+
# PyCharm
|
|
172
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
173
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
174
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
175
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
176
|
+
#.idea/
|
|
177
|
+
|
|
178
|
+
# Abstra
|
|
179
|
+
# Abstra is an AI-powered process automation framework.
|
|
180
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
181
|
+
# Learn more at https://abstra.io/docs
|
|
182
|
+
.abstra/
|
|
183
|
+
|
|
184
|
+
# Visual Studio Code
|
|
185
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
186
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
187
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
188
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
189
|
+
# .vscode/
|
|
190
|
+
|
|
191
|
+
# Ruff stuff:
|
|
192
|
+
.ruff_cache/
|
|
193
|
+
|
|
194
|
+
# PyPI configuration file
|
|
195
|
+
.pypirc
|
|
196
|
+
|
|
197
|
+
# Cursor
|
|
198
|
+
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
|
|
199
|
+
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
|
|
200
|
+
# refer to https://docs.cursor.com/context/ignore-files
|
|
201
|
+
.cursorignore
|
|
202
|
+
.cursorindexingignore
|
|
203
|
+
|
|
204
|
+
# Marimo
|
|
205
|
+
marimo/_static/
|
|
206
|
+
marimo/_lsp/
|
|
207
|
+
__marimo__/
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel
|
|
4
|
+
|
|
5
|
+
from pymergetic.common import PyDataObject
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def main() -> None:
|
|
9
|
+
# This sample uses the common package's test extension to demonstrate the API.
|
|
10
|
+
from pymergetic.common import __cpp_test__ as ext # type: ignore
|
|
11
|
+
|
|
12
|
+
DataPoint = PyDataObject.native(ext.DataPoint)
|
|
13
|
+
|
|
14
|
+
dp = DataPoint(ext.make_datapoint(7, "hello"))
|
|
15
|
+
blob = dp.to_bytes()
|
|
16
|
+
dp2 = DataPoint.from_bytes(blob)
|
|
17
|
+
|
|
18
|
+
print("native snapshot:", dp2.to_dict())
|
|
19
|
+
print("bytes length:", len(blob))
|
|
20
|
+
|
|
21
|
+
class Packet(BaseModel):
|
|
22
|
+
dp: DataPoint
|
|
23
|
+
|
|
24
|
+
pkt = Packet(dp=dp)
|
|
25
|
+
s = pkt.model_dump_json()
|
|
26
|
+
pkt2 = Packet.model_validate_json(s)
|
|
27
|
+
|
|
28
|
+
print("json (base64 bytes payload):")
|
|
29
|
+
print(s)
|
|
30
|
+
print("roundtrip snapshot:", pkt2.dp.to_dict())
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
if __name__ == "__main__":
|
|
34
|
+
main()
|
|
35
|
+
|
|
36
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel
|
|
4
|
+
|
|
5
|
+
from pymergetic.common import PyObject
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def main() -> None:
|
|
9
|
+
# This sample uses the common package's test extension to demonstrate the API.
|
|
10
|
+
from pymergetic.common import __cpp_test__ as ext # type: ignore
|
|
11
|
+
|
|
12
|
+
svc = ext.make_network_service()
|
|
13
|
+
svc.connect("http://example")
|
|
14
|
+
|
|
15
|
+
class StatusResponse(BaseModel):
|
|
16
|
+
service: PyObject[object]
|
|
17
|
+
|
|
18
|
+
payload = StatusResponse(service=PyObject(svc))
|
|
19
|
+
|
|
20
|
+
print("python repr:", payload.service)
|
|
21
|
+
print("python dict snapshot:", payload.service.to_dict())
|
|
22
|
+
print("json (via pydantic -> calls C++ to_dict):")
|
|
23
|
+
print(payload.model_dump_json())
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
if __name__ == "__main__":
|
|
27
|
+
main()
|
|
28
|
+
|
|
29
|
+
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#include <pymergetic/easybind/prelude.hpp>
|
|
2
|
+
|
|
3
|
+
namespace pymergetic::common::bindings {
|
|
4
|
+
|
|
5
|
+
void bind_base(::nanobind::module_& /*m*/) {}
|
|
6
|
+
|
|
7
|
+
EASYBIND_REGISTER_PACKAGE("pymergetic.common", [](::nanobind::module_& m) { bind_base(m); });
|
|
8
|
+
|
|
9
|
+
} // namespace pymergetic::common::bindings
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
namespace pymergetic::common {
|
|
4
|
+
|
|
5
|
+
// Placeholder for future C++ registration base types.
|
|
6
|
+
// (Keep stable; used as an ABI anchor across pymergetic extensions.)
|
|
7
|
+
|
|
8
|
+
struct RegistryBase {
|
|
9
|
+
virtual ~RegistryBase() = default;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
} // namespace pymergetic::common
|
|
13
|
+
|
|
14
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <string>
|
|
4
|
+
|
|
5
|
+
namespace pymergetic::common {
|
|
6
|
+
|
|
7
|
+
// Minimal shared definitions to anchor ABI expectations across extensions.
|
|
8
|
+
// Extend carefully: prefer additive changes.
|
|
9
|
+
|
|
10
|
+
using PeerId = std::string;
|
|
11
|
+
|
|
12
|
+
} // namespace pymergetic::common
|
|
13
|
+
|
|
14
|
+
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#include <pymergetic/easybind/prelude.hpp>
|
|
2
|
+
|
|
3
|
+
namespace pymergetic::common::bindings {
|
|
4
|
+
|
|
5
|
+
void bind_codec(::nanobind::module_& /*m*/) {}
|
|
6
|
+
|
|
7
|
+
EASYBIND_REGISTER_PACKAGE("pymergetic.common", [](::nanobind::module_& m) { bind_codec(m); });
|
|
8
|
+
|
|
9
|
+
} // namespace pymergetic::common::bindings
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <cstddef>
|
|
4
|
+
#include <cstdint>
|
|
5
|
+
#include <string>
|
|
6
|
+
#include <string_view>
|
|
7
|
+
|
|
8
|
+
#include <pymergetic/common/exceptions/__init__.hpp>
|
|
9
|
+
|
|
10
|
+
namespace pymergetic::common::codec {
|
|
11
|
+
|
|
12
|
+
// Canonical binary header for CppDataObject payloads.
|
|
13
|
+
//
|
|
14
|
+
// Layout (all little-endian):
|
|
15
|
+
// magic[4] = "PMDG"
|
|
16
|
+
// u8 version = 1
|
|
17
|
+
// u8 flags = 0 (reserved for compression/encryption)
|
|
18
|
+
// u16 schema = 0 (reserved schema version for payload encoding)
|
|
19
|
+
// u32 type_id = stable type id for the concrete data object
|
|
20
|
+
// u32 len = payload length in bytes
|
|
21
|
+
// payload[len]
|
|
22
|
+
//
|
|
23
|
+
// This makes payloads self-describing and forward-compatible.
|
|
24
|
+
inline constexpr char k_magic[4] = {'P', 'M', 'D', 'G'};
|
|
25
|
+
inline constexpr std::uint8_t k_header_version = 1;
|
|
26
|
+
|
|
27
|
+
// Stable type-id hash (FNV-1a 32-bit) for avoiding collisions across modules.
|
|
28
|
+
// Use fully-qualified names like "pymergetic.axon.PeerInfo".
|
|
29
|
+
inline constexpr std::uint32_t fnv1a32(std::string_view s) {
|
|
30
|
+
std::uint32_t h = 2166136261u;
|
|
31
|
+
for (char c : s) {
|
|
32
|
+
h ^= static_cast<std::uint8_t>(c);
|
|
33
|
+
h *= 16777619u;
|
|
34
|
+
}
|
|
35
|
+
return h;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
inline constexpr std::uint32_t type_id(std::string_view fully_qualified_name) {
|
|
39
|
+
return fnv1a32(fully_qualified_name);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
inline void append_u8(std::string& out, std::uint8_t v) { out.push_back(static_cast<char>(v)); }
|
|
43
|
+
|
|
44
|
+
inline void append_u16_le(std::string& out, std::uint16_t v) {
|
|
45
|
+
out.push_back(static_cast<char>(v & 0xFF));
|
|
46
|
+
out.push_back(static_cast<char>((v >> 8) & 0xFF));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
inline void append_u32_le(std::string& out, std::uint32_t v) {
|
|
50
|
+
out.push_back(static_cast<char>(v & 0xFF));
|
|
51
|
+
out.push_back(static_cast<char>((v >> 8) & 0xFF));
|
|
52
|
+
out.push_back(static_cast<char>((v >> 16) & 0xFF));
|
|
53
|
+
out.push_back(static_cast<char>((v >> 24) & 0xFF));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
inline void append_i32_le(std::string& out, std::int32_t v) {
|
|
57
|
+
append_u32_le(out, static_cast<std::uint32_t>(v));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
inline std::uint16_t read_u16_le(const char* p, std::size_t n, std::size_t off) {
|
|
61
|
+
if (off + 2 > n) {
|
|
62
|
+
throw pymergetic::common::EndOfStreamError("codec: read_u16_le out of bounds");
|
|
63
|
+
}
|
|
64
|
+
return (static_cast<std::uint16_t>(static_cast<unsigned char>(p[off])) |
|
|
65
|
+
(static_cast<std::uint16_t>(static_cast<unsigned char>(p[off + 1])) << 8));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
inline std::uint32_t read_u32_le(const char* p, std::size_t n, std::size_t off) {
|
|
69
|
+
if (off + 4 > n) {
|
|
70
|
+
throw pymergetic::common::EndOfStreamError("codec: read_u32_le out of bounds");
|
|
71
|
+
}
|
|
72
|
+
return (static_cast<std::uint32_t>(static_cast<unsigned char>(p[off])) |
|
|
73
|
+
(static_cast<std::uint32_t>(static_cast<unsigned char>(p[off + 1])) << 8) |
|
|
74
|
+
(static_cast<std::uint32_t>(static_cast<unsigned char>(p[off + 2])) << 16) |
|
|
75
|
+
(static_cast<std::uint32_t>(static_cast<unsigned char>(p[off + 3])) << 24));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
inline std::int32_t read_i32_le(const char* p, std::size_t n, std::size_t off) {
|
|
79
|
+
return static_cast<std::int32_t>(read_u32_le(p, n, off));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
inline void append_u32_len_prefixed(std::string& out, const std::string& bytes) {
|
|
83
|
+
append_u32_le(out, static_cast<std::uint32_t>(bytes.size()));
|
|
84
|
+
out.append(bytes);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
inline std::string read_u32_len_prefixed_bytes(const char* p, std::size_t n, std::size_t off, std::size_t* next_off) {
|
|
88
|
+
const std::uint32_t len = read_u32_le(p, n, off);
|
|
89
|
+
const std::size_t start = off + 4;
|
|
90
|
+
const std::size_t end = start + static_cast<std::size_t>(len);
|
|
91
|
+
if (end > n) {
|
|
92
|
+
throw pymergetic::common::EndOfStreamError("codec: length-prefixed read out of bounds");
|
|
93
|
+
}
|
|
94
|
+
if (next_off) {
|
|
95
|
+
*next_off = end;
|
|
96
|
+
}
|
|
97
|
+
return std::string(p + start, p + end);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
struct Header {
|
|
101
|
+
// NOTE: magic is implied/checked and not stored here.
|
|
102
|
+
std::uint8_t version{};
|
|
103
|
+
std::uint8_t flags{}; // reserved
|
|
104
|
+
std::uint16_t schema_ver{}; // reserved
|
|
105
|
+
std::uint32_t type_id{};
|
|
106
|
+
std::uint32_t payload_len{};
|
|
107
|
+
std::size_t payload_off{};
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
inline void append_header(std::string& out,
|
|
111
|
+
std::uint32_t type_id,
|
|
112
|
+
std::uint32_t payload_len,
|
|
113
|
+
std::uint8_t flags = 0,
|
|
114
|
+
std::uint16_t schema_ver = 0) {
|
|
115
|
+
// Reserve enough for header + payload to minimize reallocations.
|
|
116
|
+
out.reserve(out.size() + 16 + static_cast<std::size_t>(payload_len));
|
|
117
|
+
out.append(k_magic, k_magic + 4);
|
|
118
|
+
append_u8(out, k_header_version);
|
|
119
|
+
append_u8(out, flags);
|
|
120
|
+
append_u16_le(out, schema_ver);
|
|
121
|
+
append_u32_le(out, type_id);
|
|
122
|
+
append_u32_le(out, payload_len);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
inline Header read_header(const char* p, std::size_t n) {
|
|
126
|
+
// Header is always exactly 16 bytes.
|
|
127
|
+
if (n < 16) {
|
|
128
|
+
throw pymergetic::common::EndOfStreamError("codec: buffer too small for header");
|
|
129
|
+
}
|
|
130
|
+
if (p[0] != k_magic[0] || p[1] != k_magic[1] || p[2] != k_magic[2] || p[3] != k_magic[3]) {
|
|
131
|
+
throw pymergetic::common::MagicMismatchError("codec: bad magic");
|
|
132
|
+
}
|
|
133
|
+
Header h;
|
|
134
|
+
h.version = static_cast<std::uint8_t>(p[4]);
|
|
135
|
+
h.flags = static_cast<std::uint8_t>(p[5]);
|
|
136
|
+
h.schema_ver = read_u16_le(p, n, 6);
|
|
137
|
+
if (h.version != k_header_version) {
|
|
138
|
+
throw pymergetic::common::CodecError("codec: unsupported header version");
|
|
139
|
+
}
|
|
140
|
+
// Offsets:
|
|
141
|
+
// version @ 4, flags @ 5, schema @ 6, type_id @ 8, len @ 12
|
|
142
|
+
h.type_id = read_u32_le(p, n, 8);
|
|
143
|
+
h.payload_len = read_u32_le(p, n, 12);
|
|
144
|
+
h.payload_off = 16;
|
|
145
|
+
|
|
146
|
+
// Validate the 16-byte aligned header layout.
|
|
147
|
+
if ((h.payload_off % 16) != 0) {
|
|
148
|
+
throw pymergetic::common::CodecError("codec: header is not 16-byte aligned");
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const std::size_t expected_n = h.payload_off + static_cast<std::size_t>(h.payload_len);
|
|
152
|
+
if (n < expected_n) {
|
|
153
|
+
throw pymergetic::common::EndOfStreamError("codec: payload length mismatch");
|
|
154
|
+
}
|
|
155
|
+
if (n != expected_n) {
|
|
156
|
+
throw pymergetic::common::CodecError("codec: payload length mismatch");
|
|
157
|
+
}
|
|
158
|
+
return h;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
} // namespace pymergetic::common::codec
|
|
162
|
+
|
|
163
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#include <pymergetic/easybind/prelude.hpp>
|
|
2
|
+
|
|
3
|
+
#include <pymergetic/common/exceptions/__init__.hpp>
|
|
4
|
+
|
|
5
|
+
namespace pymergetic::common::bindings {
|
|
6
|
+
|
|
7
|
+
namespace nb = ::nanobind;
|
|
8
|
+
|
|
9
|
+
void bind_exceptions(::nanobind::module_& m) {
|
|
10
|
+
nb::exception<pymergetic::common::CodecError>(m, "CodecError");
|
|
11
|
+
nb::exception<pymergetic::common::EndOfStreamError>(m, "EndOfStreamError");
|
|
12
|
+
nb::exception<pymergetic::common::MagicMismatchError>(m, "MagicMismatchError");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
EASYBIND_REGISTER_PACKAGE("pymergetic.common", [](::nanobind::module_& m) { bind_exceptions(m); });
|
|
16
|
+
|
|
17
|
+
} // namespace pymergetic::common::bindings
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <stdexcept>
|
|
4
|
+
#include <string>
|
|
5
|
+
|
|
6
|
+
namespace pymergetic::common {
|
|
7
|
+
|
|
8
|
+
/// Base error for codec/serialization failures.
|
|
9
|
+
class CodecError : public std::runtime_error {
|
|
10
|
+
public:
|
|
11
|
+
using std::runtime_error::runtime_error;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/// Thrown when a buffer ends before the requested bytes are available.
|
|
15
|
+
class EndOfStreamError : public CodecError {
|
|
16
|
+
public:
|
|
17
|
+
using CodecError::CodecError;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/// Thrown when the PMDG magic does not match.
|
|
21
|
+
class MagicMismatchError : public CodecError {
|
|
22
|
+
public:
|
|
23
|
+
using CodecError::CodecError;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
} // namespace pymergetic::common
|
|
27
|
+
|
|
28
|
+
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#include <pymergetic/easybind/prelude.hpp>
|
|
2
|
+
|
|
3
|
+
namespace pymergetic::common::bindings {
|
|
4
|
+
|
|
5
|
+
void bind_header(::nanobind::module_& /*m*/) {}
|
|
6
|
+
|
|
7
|
+
EASYBIND_REGISTER_PACKAGE("pymergetic.common", [](::nanobind::module_& m) { bind_header(m); });
|
|
8
|
+
|
|
9
|
+
} // namespace pymergetic::common::bindings
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#include <pymergetic/easybind/prelude.hpp>
|
|
2
|
+
|
|
3
|
+
namespace pymergetic::common::bindings {
|
|
4
|
+
|
|
5
|
+
void bind_nb(::nanobind::module_& /*m*/) {}
|
|
6
|
+
|
|
7
|
+
EASYBIND_REGISTER_PACKAGE("pymergetic.common", [](::nanobind::module_& m) { bind_nb(m); });
|
|
8
|
+
|
|
9
|
+
} // namespace pymergetic::common::bindings
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <nanobind/nanobind.h>
|
|
4
|
+
|
|
5
|
+
namespace pymergetic::nb::asyncio_bridge {
|
|
6
|
+
|
|
7
|
+
namespace nb = nanobind;
|
|
8
|
+
|
|
9
|
+
// Thread-safe completion helpers for asyncio.Future from non-Python threads
|
|
10
|
+
// (e.g. Boost.Asio io_context thread).
|
|
11
|
+
inline void future_set_result(nb::object loop, nb::object future, nb::object value) {
|
|
12
|
+
nb::gil_scoped_acquire _gil;
|
|
13
|
+
loop.attr("call_soon_threadsafe")(future.attr("set_result"), value);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
inline void future_set_exception(nb::object loop, nb::object future, nb::object exc) {
|
|
17
|
+
nb::gil_scoped_acquire _gil;
|
|
18
|
+
loop.attr("call_soon_threadsafe")(future.attr("set_exception"), exc);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
inline nb::object get_running_loop() {
|
|
22
|
+
nb::module_ asyncio = nb::module_::import_("asyncio");
|
|
23
|
+
return asyncio.attr("get_running_loop")();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
inline nb::object create_future(nb::object loop) {
|
|
27
|
+
return loop.attr("create_future")();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
} // namespace pymergetic::nb::asyncio_bridge
|
|
31
|
+
|
|
32
|
+
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <nanobind/nanobind.h>
|
|
4
|
+
#include <string>
|
|
5
|
+
|
|
6
|
+
namespace pymergetic::nb {
|
|
7
|
+
|
|
8
|
+
/// Binding-layer base class for native objects exposed to Python.
|
|
9
|
+
///
|
|
10
|
+
/// IMPORTANT:
|
|
11
|
+
/// - This is a Level-2 (bindings) concept (it depends on nanobind).
|
|
12
|
+
/// - Do not use this in Level-1 engine code (EP-0006: Level 1 must not depend on Python).
|
|
13
|
+
class CppObject {
|
|
14
|
+
public:
|
|
15
|
+
virtual ~CppObject() = default;
|
|
16
|
+
|
|
17
|
+
/// Debug representation.
|
|
18
|
+
virtual std::string repr() const { return "<CppObject>"; }
|
|
19
|
+
|
|
20
|
+
/// Fast serialization to a Python dict (zero extra Python-side validation/ORM work).
|
|
21
|
+
virtual ::nanobind::dict to_dict() const { return ::nanobind::dict(); }
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
} // namespace pymergetic::nb
|
|
25
|
+
|
|
26
|
+
|