marshmallow-core 0.1.0__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.
@@ -0,0 +1,44 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ concurrency:
9
+ group: ci-${{ github.ref }}
10
+ cancel-in-progress: true
11
+
12
+ jobs:
13
+ test:
14
+ name: test (py${{ matrix.python-version }})
15
+ runs-on: ubuntu-latest
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - uses: actions/setup-python@v5
24
+ with:
25
+ python-version: ${{ matrix.python-version }}
26
+
27
+ - uses: dtolnay/rust-toolchain@stable
28
+
29
+ - name: Build the wheel (Rust core + Python) and install it
30
+ run: |
31
+ python -m pip install --upgrade pip maturin pytest
32
+ maturin build --release --out dist
33
+ # Pulls stock marshmallow from PyPI as a declared dependency.
34
+ python -m pip install dist/*.whl
35
+
36
+ - name: Run the suite (core active)
37
+ run: pytest -q
38
+
39
+ - name: Run the suite with the core disabled
40
+ env:
41
+ MARSHMALLOW_NO_ACCEL: "1"
42
+ # The handshake tests assert the core is active, so exclude them here;
43
+ # everything else must still pass on the pure-Python fallback.
44
+ run: pytest -q -k "not core_active and not protocol"
@@ -0,0 +1,78 @@
1
+ name: Release
2
+
3
+ # Builds abi3 wheels + sdist on a version tag and publishes them to PyPI via
4
+ # trusted publishing. Setup required once before the first release:
5
+ # 1. Create the PyPI project's trusted publisher pointing at this repo +
6
+ # workflow (https://docs.pypi.org/trusted-publishers/).
7
+ # 2. Create a GitHub Environment named "pypi" (Settings > Environments).
8
+ # Then push a tag like `v0.1.0` (or run manually for a dry run that only builds).
9
+
10
+ on:
11
+ push:
12
+ tags: ["v*"]
13
+ workflow_dispatch:
14
+
15
+ permissions:
16
+ contents: read
17
+
18
+ jobs:
19
+ wheels:
20
+ name: wheels-${{ matrix.platform.runner }}-${{ matrix.platform.target }}
21
+ runs-on: ${{ matrix.platform.runner }}
22
+ strategy:
23
+ fail-fast: false
24
+ matrix:
25
+ platform:
26
+ - { runner: ubuntu-latest, target: x86_64, manylinux: auto }
27
+ - { runner: ubuntu-latest, target: aarch64, manylinux: auto }
28
+ # No Intel macOS wheel: the scarce macos-13 (Intel) runners queue for a
29
+ # long time and are being wound down, so they blocked the release. Only
30
+ # Apple-Silicon (arm64) macOS wheels are built; Intel-Mac users install
31
+ # from the sdist (which compiles the Rust core locally).
32
+ - { runner: macos-14, target: aarch64, manylinux: "" }
33
+ - { runner: windows-latest, target: x64, manylinux: "" }
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+ - uses: actions/setup-python@v5
37
+ with:
38
+ python-version: "3.12"
39
+ - name: Build abi3 wheel
40
+ uses: PyO3/maturin-action@v1
41
+ with:
42
+ target: ${{ matrix.platform.target }}
43
+ args: --release --out dist
44
+ manylinux: ${{ matrix.platform.manylinux }}
45
+ - uses: actions/upload-artifact@v4
46
+ with:
47
+ name: wheels-${{ matrix.platform.runner }}-${{ matrix.platform.target }}
48
+ path: dist
49
+
50
+ sdist:
51
+ runs-on: ubuntu-latest
52
+ steps:
53
+ - uses: actions/checkout@v4
54
+ - name: Build sdist
55
+ uses: PyO3/maturin-action@v1
56
+ with:
57
+ command: sdist
58
+ args: --out dist
59
+ - uses: actions/upload-artifact@v4
60
+ with:
61
+ name: wheels-sdist
62
+ path: dist
63
+
64
+ publish:
65
+ name: Publish to PyPI
66
+ runs-on: ubuntu-latest
67
+ needs: [wheels, sdist]
68
+ if: startsWith(github.ref, 'refs/tags/')
69
+ environment: pypi
70
+ permissions:
71
+ id-token: write # trusted publishing; no API token needed
72
+ steps:
73
+ - uses: actions/download-artifact@v4
74
+ with:
75
+ pattern: wheels-*
76
+ path: dist
77
+ merge-multiple: true
78
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,16 @@
1
+ # Rust
2
+ /target
3
+ **/*.rs.bk
4
+
5
+ # Python
6
+ __pycache__/
7
+ *.py[cod]
8
+ *.so
9
+ *.pyd
10
+ .venv/
11
+ dist/
12
+ build/
13
+ *.egg-info/
14
+ .pytest_cache/
15
+ .mypy_cache/
16
+ .ruff_cache/
@@ -0,0 +1,81 @@
1
+ # Backlog
2
+
3
+ Flat, actionable todo list derived from [ROADMAP.md](ROADMAP.md). Work top to
4
+ bottom within a phase.
5
+
6
+ ## Phase 0 — Measurement
7
+
8
+ - [x] Create `performance/` directory
9
+ - [x] Port `benchmark.py` from the fork; drive it via `install()`/`uninstall()`
10
+ - [x] Add flat-scalar schema benchmark case
11
+ - [x] Add nested schema benchmark case
12
+ - [x] Add list-heavy schema benchmark case
13
+ - [x] Add validator-heavy schema benchmark case
14
+ - [x] Benchmark `dump`, `load`, `dumps`, `loads` for each case
15
+ - [x] Print a stock-vs-core comparison table
16
+ - [x] Write a coverage probe: report per-field native vs callback for a schema
17
+ - [x] Document how to run the benchmark in README
18
+
19
+ ## Phase 1 — Coverage gaps
20
+
21
+ ### Hook-bearing load schemas
22
+ - [x] Map out marshmallow 4.x `_do_load` body (pre_load → deserialize → validators → post_load)
23
+ - [x] In `_patched_do_load`, run `pre_load` in Python before the core step
24
+ - [x] Call the core for the per-field deserialize when hooks are present
25
+ - [x] Run field validators in Python after the core step
26
+ - [x] Run schema validators (`validates_schema`) in Python
27
+ - [x] Run `post_load` in Python after the core step
28
+ - [x] Remove the `not _has_load_hooks(self)` guard once the split works
29
+ - [x] Add equivalence tests for pre_load + post_load + validates schemas
30
+
31
+ ### Native validators
32
+ - [x] Add a validator tag space (compiler + lib.rs)
33
+ - [x] Native `Range` validator
34
+ - [x] Native `Length` validator
35
+ - [x] Native `OneOf` validator
36
+ - [x] Compile only recognized validators; fall back on any other
37
+ - [x] Equivalence tests: pass + fail inputs for each validator
38
+
39
+ ### New field types
40
+ - [x] Native `Decimal` (dump + load)
41
+ - [x] Native `Dict`/`Mapping` (dump + load) — plain dict-copy case
42
+ - [x] Native `Constant`
43
+ - [x] Share `Number` base coercion with Integer/Float — Decimal reuses the
44
+ field's own (`Number`-based) `_serialize`/`_deserialize` rather than
45
+ duplicating coercion in Rust
46
+ - [x] Equivalence tests for each new field type (valid + error)
47
+
48
+ ## Phase 2 — Fused JSON path
49
+
50
+ - [x] Add a dump→JSON-bytes core object in `lib.rs` (`DumpSerializer.run_json`)
51
+ - [x] Build the JSON-dump payload in `_compiler.py` (`build_dump_json_serializer`)
52
+ - [x] Wrap `Schema.dumps` in `_patch.py`
53
+ - [x] Equivalence tests: `dumps` output matches stock
54
+ - [~] Add a JSON→loaded core object in `lib.rs` — **implemented + benchmarked,
55
+ not shipped.** A `serde_json`-backed single-pass `LoadDeserializer.run_json`
56
+ was prototyped, but it is consistently *slower* than CPython's C `json.loads`
57
+ followed by the already-accelerated `_do_load` (e.g. nested 2.12µs vs 1.96µs;
58
+ 100-record list 60µs vs 37µs). `loads` already benefits from the `_do_load`
59
+ patch, so fusing it only adds a heavy dependency and a regression. Reverted
60
+ per the roadmap's "confirm a real gain, not a regression" rule.
61
+ - [~] Build the JSON-load payload in `_compiler.py` — see above (reverted)
62
+ - [~] Wrap `Schema.loads` in `_patch.py` with `AccelFallback` — see above (reverted)
63
+ - [~] Equivalence tests: `loads` result + errors match stock — verified during the
64
+ prototype (big-int/error/unknown-key parity held); dropped with the revert
65
+
66
+ ## Phase 3 — Remaining deferrals + micro-opts
67
+
68
+ - [x] Support `unknown=INCLUDE`
69
+ - [x] Support collection/dotted `partial`
70
+ - [x] Support dotted attribute writes (`set_value`)
71
+ - [x] Cache `_has_load_hooks` on the class (per-class `WeakKeyDictionary`)
72
+ - [x] Precompute the known-keys frozenset once (built per compile, held by the
73
+ Rust `LoadSerializer`)
74
+
75
+ ## Per-change checklist (every code item)
76
+
77
+ - [x] Implemented in **both** `_compiler.py` and `lib.rs`
78
+ - [x] Dump/load tags kept in sync
79
+ - [x] Bumped `PROTOCOL_VERSION` + `_EXPECTED_PROTOCOL` if payload/tags changed
80
+ - [x] Equivalence test added (valid + error inputs)
81
+ - [x] Re-ran benchmark to confirm a real gain
@@ -0,0 +1,145 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## What this is
6
+
7
+ **marshmallow_core** is a standalone, opt-in Rust acceleration core for the
8
+ published [marshmallow](https://github.com/marshmallow-code/marshmallow) library.
9
+ It installs *alongside* an unmodified `pip install marshmallow` and, when
10
+ activated, monkey-patches `Schema._serialize` / `Schema._do_load` to run a PyO3
11
+ extension instead of marshmallow's per-object Python loops. It is **strictly a
12
+ speedup**: with the core installed, `dump`/`load` produce results identical to
13
+ stock marshmallow, falling back to pure Python for anything not modelled
14
+ natively (and, on load, for *every* error/edge case).
15
+
16
+ Activation is explicit and process-wide:
17
+
18
+ ```python
19
+ import marshmallow_core
20
+ marshmallow_core.install() # patch marshmallow.Schema
21
+ ... # use marshmallow as usual
22
+ marshmallow_core.uninstall() # restore the stock methods
23
+ ```
24
+
25
+ This is a mixed Python/Rust project built with **maturin** (`flit`-style src
26
+ layout under `python/`, Rust under `src/`). Python 3.10+ ; the extension is
27
+ `abi3` so one wheel covers all supported versions.
28
+
29
+ ## Provenance
30
+
31
+ The Rust core (`src/lib.rs`) and the compiler (`python/marshmallow_core/_compiler.py`)
32
+ were lifted from marshmallow's own `rust-core` branch — `crates/marshmallow-core/src/lib.rs`
33
+ and `src/marshmallow/_accel.py` respectively. The crucial difference: in that
34
+ branch the core is wired *into* `schema.py`; here it lives outside marshmallow
35
+ and patches in from the outside via `_patch.py`. When fixing core logic, the
36
+ upstream branch is the reference implementation to diff against.
37
+
38
+ ## Commands
39
+
40
+ Requires `cargo` (rustup) and [`maturin`](https://www.maturin.rs/) (run via `uvx`).
41
+
42
+ ```bash
43
+ # Build the Rust core + install the package into the current venv (iterating):
44
+ uvx maturin develop --release
45
+
46
+ # Build a wheel without installing (verifies Rust compiles + maturin metadata):
47
+ uvx maturin build --release # -> target/wheels/marshmallow_core-*.whl
48
+
49
+ # Run the suite. IMPORTANT: test against STOCK marshmallow, not a checkout of
50
+ # the fork (the fork has its own baked-in accel and would double-patch). Use a
51
+ # throwaway venv with marshmallow from PyPI:
52
+ WHEEL=$(ls -t target/wheels/*.whl | head -1)
53
+ uv venv /tmp/mc && uv pip install --python /tmp/mc/bin/python marshmallow pytest "$WHEEL"
54
+ /tmp/mc/bin/python -m pytest -q # whole suite
55
+ /tmp/mc/bin/python -m pytest tests/test_equivalence.py::test_load_equivalence -q # one test
56
+ MARSHMALLOW_NO_ACCEL=1 /tmp/mc/bin/python -m pytest -q -k "not core_active and not protocol" # pure-Python path
57
+ ```
58
+
59
+ `MARSHMALLOW_NO_ACCEL=1` disables the core even after `install()` (the
60
+ pure-Python path is always correct). CI (`.github/workflows/ci.yml`) runs the
61
+ suite on py3.10–3.13 both with the core active and disabled.
62
+
63
+ ## Architecture
64
+
65
+ Three Python modules plus one Rust file. Read `_patch.py`, then `_compiler.py`,
66
+ then `src/lib.rs`.
67
+
68
+ ### `_patch.py` — the install() shim (replaces the fork's `schema.py` edits)
69
+
70
+ `install()` saves and overwrites `Schema._serialize` and `Schema._do_load`.
71
+ The wrappers try the compiled core and otherwise call the saved originals:
72
+
73
+ - The compiled serializer/deserializer is **cached per Schema instance** on
74
+ `vars(schema)["_mc_dump_serializer"]` / `["_mc_load_deserializer"]` — `_UNSET`
75
+ (not built), `None` (not compilable → always pure Python), or a core object.
76
+ - `_do_load` only attempts the core when the call uses the schema's own
77
+ `unknown`, `partial` is `True`-or-falsy, and the schema has **no load hooks**
78
+ (`_has_load_hooks` checks `pre_load`/`post_load`/`validates`/`validates_schema`).
79
+ On `AccelFallback` from the core it falls through to the original `_do_load`.
80
+
81
+ **Key divergence from the upstream branch:** there, a *root* schema with load
82
+ hooks still uses the core for the per-field step with Python running the hooks
83
+ *around* it. That split lives *inside* `_do_load` and cannot be reproduced by
84
+ wrapping the method from outside, so here **hook-bearing schemas use the
85
+ pure-Python load path entirely**. Correct, just not accelerated. Dump is fully
86
+ accelerated regardless of dump hooks (they run via `dump`, not `_serialize`).
87
+
88
+ ### `_compiler.py` — Schema → payload (the "compiler")
89
+
90
+ Inspects a *bound* Schema and compiles it into a recursive tuple "payload"
91
+ describing each field as either **native** (formatted/parsed entirely in Rust)
92
+ or a **callback** (defers to the Python `Field.serialize`/`deserialize`).
93
+ `build_dump_serializer` / `build_load_deserializer` return `None` to mean "use
94
+ pure Python". `is_available()` gates everything (extension importable + protocol
95
+ match + not `MARSHMALLOW_NO_ACCEL`). It reads only attributes present in stock
96
+ marshmallow 4.x.
97
+
98
+ ### `src/lib.rs` — the PyO3 core
99
+
100
+ Parses payloads into `DumpSerializer` / `LoadDeserializer`, built as the
101
+ extension `marshmallow_core._core` (`[lib] name = "_core"`, `module-name =
102
+ "marshmallow_core._core"`). The **load** core handles only the happy path: the
103
+ instant it hits any error/edge case it raises `AccelFallback` and Python re-runs
104
+ the unchanged pure-Python load, so every message/value matches exactly.
105
+ `KeyboardInterrupt`/`SystemExit` from a callback propagate unchanged (never
106
+ converted to `AccelFallback`). The **dump core has no `AccelFallback`** — it
107
+ can't defer mid-serialization — so every native dump element must be provably
108
+ identical to `Field._serialize`.
109
+
110
+ ### Invariants when changing the core
111
+
112
+ - **Dump and load tag spaces are distinct integers** and must stay in sync
113
+ between `_compiler.py` and `lib.rs`. When adding a native field type, add it
114
+ in *both* (build the element tuple in `_compiler.py`, parse + apply in
115
+ `lib.rs`), keep tags aligned, and verify accel-on output equals accel-off
116
+ output across **valid and error** inputs (`tests/test_equivalence.py`).
117
+ - The extension exports `PROTOCOL_VERSION`; `_compiler._EXPECTED_PROTOCOL` must
118
+ match it. Bump both together when payload shapes/tags change.
119
+ - **What stays pure-Python:** custom `dict_class`/`get_attribute`,
120
+ self-referential schemas, custom strptime temporal formats,
121
+ `NaiveDateTime`/`AwareDateTime` on load, callable defaults, unrecognized field
122
+ validators (anything but `Range`/`Length`/`OneOf`), field-level
123
+ `pre_load`/`post_load`, a `Dict` with key/value fields, and any field type
124
+ without a native element. **Now accelerated** (Phase 1/3): `unknown=INCLUDE`,
125
+ collection/dotted `partial`, dotted attribute writes (`set_value`),
126
+ `Range`/`Length`/`OneOf` validators, `Decimal`/`Dict`/`Constant` fields,
127
+ schema-level load hooks (`pre_load`/`post_load`/`validates`/`validates_schema`
128
+ run in Python around the core's per-field step), and `dumps` (fused to JSON in
129
+ Rust). `loads` is accelerated via the patched load path (a fused JSON *parser*
130
+ was prototyped but did not beat C `json.loads`, so it ships unfused).
131
+
132
+ ## Testing conventions
133
+
134
+ `tests/test_equivalence.py` is the source of truth: an autouse fixture calls
135
+ `install()`, and each `_dump_both`/`_load_both` helper runs once accelerated,
136
+ then `monkeypatch`es `_compiler.build_*` to `None` to force the pure path, and
137
+ asserts the two are equal. `tests/test_smoke.py` is a quick install/uninstall +
138
+ equivalence sanity check. New native fields need a case in `test_equivalence.py`.
139
+
140
+ ## Development
141
+
142
+ - commit only after passing tests
143
+ - for every big part create a new branch
144
+ - for every small task(feature) make a commit
145
+ - do not commit thing that i'nt make functionality
@@ -0,0 +1,172 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "autocfg"
7
+ version = "1.5.1"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
10
+
11
+ [[package]]
12
+ name = "heck"
13
+ version = "0.5.0"
14
+ source = "registry+https://github.com/rust-lang/crates.io-index"
15
+ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
16
+
17
+ [[package]]
18
+ name = "indoc"
19
+ version = "2.0.7"
20
+ source = "registry+https://github.com/rust-lang/crates.io-index"
21
+ checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
22
+ dependencies = [
23
+ "rustversion",
24
+ ]
25
+
26
+ [[package]]
27
+ name = "libc"
28
+ version = "0.2.186"
29
+ source = "registry+https://github.com/rust-lang/crates.io-index"
30
+ checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
31
+
32
+ [[package]]
33
+ name = "marshmallow_core"
34
+ version = "0.1.0"
35
+ dependencies = [
36
+ "pyo3",
37
+ ]
38
+
39
+ [[package]]
40
+ name = "memoffset"
41
+ version = "0.9.1"
42
+ source = "registry+https://github.com/rust-lang/crates.io-index"
43
+ checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
44
+ dependencies = [
45
+ "autocfg",
46
+ ]
47
+
48
+ [[package]]
49
+ name = "once_cell"
50
+ version = "1.21.4"
51
+ source = "registry+https://github.com/rust-lang/crates.io-index"
52
+ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
53
+
54
+ [[package]]
55
+ name = "portable-atomic"
56
+ version = "1.13.1"
57
+ source = "registry+https://github.com/rust-lang/crates.io-index"
58
+ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
59
+
60
+ [[package]]
61
+ name = "proc-macro2"
62
+ version = "1.0.106"
63
+ source = "registry+https://github.com/rust-lang/crates.io-index"
64
+ checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
65
+ dependencies = [
66
+ "unicode-ident",
67
+ ]
68
+
69
+ [[package]]
70
+ name = "pyo3"
71
+ version = "0.27.2"
72
+ source = "registry+https://github.com/rust-lang/crates.io-index"
73
+ checksum = "ab53c047fcd1a1d2a8820fe84f05d6be69e9526be40cb03b73f86b6b03e6d87d"
74
+ dependencies = [
75
+ "indoc",
76
+ "libc",
77
+ "memoffset",
78
+ "once_cell",
79
+ "portable-atomic",
80
+ "pyo3-build-config",
81
+ "pyo3-ffi",
82
+ "pyo3-macros",
83
+ "unindent",
84
+ ]
85
+
86
+ [[package]]
87
+ name = "pyo3-build-config"
88
+ version = "0.27.2"
89
+ source = "registry+https://github.com/rust-lang/crates.io-index"
90
+ checksum = "b455933107de8642b4487ed26d912c2d899dec6114884214a0b3bb3be9261ea6"
91
+ dependencies = [
92
+ "target-lexicon",
93
+ ]
94
+
95
+ [[package]]
96
+ name = "pyo3-ffi"
97
+ version = "0.27.2"
98
+ source = "registry+https://github.com/rust-lang/crates.io-index"
99
+ checksum = "1c85c9cbfaddf651b1221594209aed57e9e5cff63c4d11d1feead529b872a089"
100
+ dependencies = [
101
+ "libc",
102
+ "pyo3-build-config",
103
+ ]
104
+
105
+ [[package]]
106
+ name = "pyo3-macros"
107
+ version = "0.27.2"
108
+ source = "registry+https://github.com/rust-lang/crates.io-index"
109
+ checksum = "0a5b10c9bf9888125d917fb4d2ca2d25c8df94c7ab5a52e13313a07e050a3b02"
110
+ dependencies = [
111
+ "proc-macro2",
112
+ "pyo3-macros-backend",
113
+ "quote",
114
+ "syn",
115
+ ]
116
+
117
+ [[package]]
118
+ name = "pyo3-macros-backend"
119
+ version = "0.27.2"
120
+ source = "registry+https://github.com/rust-lang/crates.io-index"
121
+ checksum = "03b51720d314836e53327f5871d4c0cfb4fb37cc2c4a11cc71907a86342c40f9"
122
+ dependencies = [
123
+ "heck",
124
+ "proc-macro2",
125
+ "pyo3-build-config",
126
+ "quote",
127
+ "syn",
128
+ ]
129
+
130
+ [[package]]
131
+ name = "quote"
132
+ version = "1.0.45"
133
+ source = "registry+https://github.com/rust-lang/crates.io-index"
134
+ checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
135
+ dependencies = [
136
+ "proc-macro2",
137
+ ]
138
+
139
+ [[package]]
140
+ name = "rustversion"
141
+ version = "1.0.22"
142
+ source = "registry+https://github.com/rust-lang/crates.io-index"
143
+ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
144
+
145
+ [[package]]
146
+ name = "syn"
147
+ version = "2.0.117"
148
+ source = "registry+https://github.com/rust-lang/crates.io-index"
149
+ checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
150
+ dependencies = [
151
+ "proc-macro2",
152
+ "quote",
153
+ "unicode-ident",
154
+ ]
155
+
156
+ [[package]]
157
+ name = "target-lexicon"
158
+ version = "0.13.5"
159
+ source = "registry+https://github.com/rust-lang/crates.io-index"
160
+ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
161
+
162
+ [[package]]
163
+ name = "unicode-ident"
164
+ version = "1.0.24"
165
+ source = "registry+https://github.com/rust-lang/crates.io-index"
166
+ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
167
+
168
+ [[package]]
169
+ name = "unindent"
170
+ version = "0.2.4"
171
+ source = "registry+https://github.com/rust-lang/crates.io-index"
172
+ checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
@@ -0,0 +1,18 @@
1
+ [package]
2
+ name = "marshmallow_core"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+ description = "Rust acceleration core for marshmallow serialization (separate, opt-in package)"
6
+ license = "MIT"
7
+ repository = "https://github.com/gunlinux/marshmallow_core"
8
+ readme = "README.md"
9
+
10
+ [lib]
11
+ name = "_core"
12
+ crate-type = ["cdylib"]
13
+
14
+ [dependencies]
15
+ pyo3 = { version = "0.27", features = ["extension-module", "abi3-py310"] }
16
+
17
+ [profile.release]
18
+ lto = "thin"