leptris 1.9.307.0 → 1.9.309.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -0
- data/Rakefile +1 -1
- data/lib/leptris/vendor/aarch64-linux/libleptris.so +0 -0
- data/lib/leptris/vendor/aarch64-linux-musl/libleptris.so +0 -0
- data/lib/leptris/vendor/arm-linux/libleptris.so +0 -0
- data/lib/leptris/vendor/arm-linux-musl/libleptris.so +0 -0
- data/lib/leptris/vendor/arm64-darwin/libleptris.dylib +0 -0
- data/lib/leptris/vendor/ppc64le-linux/libleptris.so +0 -0
- data/lib/leptris/vendor/s390x-linux-musl/libleptris.so +0 -0
- data/lib/leptris/vendor/x86_64-darwin/libleptris.dylib +0 -0
- data/lib/leptris/vendor/x86_64-linux/libleptris.so +0 -0
- data/lib/leptris/vendor/x86_64-linux-musl/libleptris.so +0 -0
- data/lib/leptris/version.rb +1 -1
- data/vendor-src/README.md +1 -1
- data/vendor-src/libleptris/CHANGELOG.md +100 -0
- data/vendor-src/libleptris/CMakeLists.txt +1 -1
- data/vendor-src/libleptris/bindings/rust/Cargo.lock +7 -0
- data/vendor-src/libleptris/bindings/rust/Cargo.toml +4 -0
- data/vendor-src/libleptris/bindings/rust/README.md +19 -0
- data/vendor-src/libleptris/bindings/rust/build.rs +4 -0
- data/vendor-src/libleptris/bindings/rust/descriptor/Cargo.toml +16 -0
- data/vendor-src/libleptris/bindings/rust/descriptor/src/lib.rs +214 -0
- data/vendor-src/libleptris/bindings/rust/descriptor/tests/layout.rs +50 -0
- data/vendor-src/libleptris/bindings/rust/tests/descriptor_abi.rs +194 -0
- data/vendor-src/libleptris/src/leptris/xpath/evaluator.c +4 -0
- data/vendor-src/libleptris/src/leptris/xpath/evaluator_operators.c +225 -17
- data/vendor-src/libleptris/src/leptris/xpath/evaluator_types.c +6 -4
- data/vendor-src/libleptris/src/leptris/xpath/functions.c +75 -3
- data/vendor-src/libleptris/src/leptris/xpath/functions_ext31.c +551 -36
- data/vendor-src/libleptris/src/leptris/xpath/lexer.c +9 -0
- data/vendor-src/libleptris/src/leptris/xpath/parser.c +46 -1
- data/vendor-src/libleptris/src/leptris/xpath/xpath_public.c +1 -1
- data/vendor-src/libleptris/src/leptris/xquery/xquery.c +16 -1
- data/vendor-src/libleptris/test/xquery/test_qt3.cpp +64 -65
- data/vendor-src/libleptris/test/xquery/test_xquery.cpp +5 -1
- data/vendor-src/libleptris/vcpkg.json +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3cc7498cffb29da21d5b13691fd7ac8de3b4abdf89765699ecf79d03b186c1e1
|
|
4
|
+
data.tar.gz: 897683cbf8a8b510f733e51e3990e508d3d72ef45b1ef47985d8c601aecc68ff
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 481e075161468c9de96a2e6cdb66cb904b003f007aeb53188e5ad1919b059265b176c87ddcc944d43d3ef093431733a1d8525630f879d0e102888e02e895d51e
|
|
7
|
+
data.tar.gz: 0b31da872763118c3bad5f0b6fa1398e758fc6732863dbb27b3f25858eed3f5824073248ebacdd51332ba7fa406a62144933cd9e7cf9cd6e72a36fe8a4411325
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,34 @@
|
|
|
1
|
+
## [1.9.308.0] - 2026-10-05
|
|
2
|
+
|
|
3
|
+
### Engine sync (libleptris 1.9.308)
|
|
4
|
+
|
|
5
|
+
- **QT3 #1182 tail (leptris#1540)** — the 13 lever cases:
|
|
6
|
+
fn:avg's numeric promotion ladder with int64-exact decimal
|
|
7
|
+
division, the O(xs:double) carrier mark, typeswitch case `$v as
|
|
8
|
+
TYPE` binding arms, fn:apply function conversion (zero-arity,
|
|
9
|
+
atomization, sequence members), and fn:sum's per-type canonical
|
|
10
|
+
duration zero. Full QT3 61/61.
|
|
11
|
+
- **Per-engine crates, step 1 (leptris#1541)** — the shared
|
|
12
|
+
leptris-descriptor ABI crate in a new Cargo workspace, with the
|
|
13
|
+
runtime layout gate (Rust size_of vs engine introspection +
|
|
14
|
+
build/walk round trip) and the build.rs stale-link cache fix.
|
|
15
|
+
Ruby-side impact: none (Rust-side surface; zero header deltas,
|
|
16
|
+
audit unchanged 369/368, suite 866/0).
|
|
17
|
+
|
|
18
|
+
## [1.9.307.0] - 2026-10-05
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- **Cross-document LEAF adoption (libleptris 1.9.307, engine
|
|
23
|
+
#1534 — completing the #1528 fix)**: the #1528 adoption gate
|
|
24
|
+
covered ELEMENT splice arguments only — a TEXT/CDATA/COMMENT/PI
|
|
25
|
+
node from another document was still spliced raw, so appending
|
|
26
|
+
scratch-document leaves (the `add_child(String)` fragment path's
|
|
27
|
+
text children) and freeing the scratch left the tree pointing
|
|
28
|
+
into freed memory. The four splice seams now adopt non-element
|
|
29
|
+
arguments by copy too; same-document moves stay zero-copy.
|
|
30
|
+
Leaf-adoption specs pin the free-then-walk shape.
|
|
31
|
+
|
|
1
32
|
## 1.9.306.0 — 2026-10-05
|
|
2
33
|
|
|
3
34
|
Rides libleptris v1.9.306 (pin 1.9.304 -> 1.9.306): the Lane 18
|
data/Rakefile
CHANGED
|
@@ -8,7 +8,7 @@ RSpec::Core::RakeTask.new(:spec)
|
|
|
8
8
|
# Pin for `rake compile` and the platform-gem builds. Keep in lockstep
|
|
9
9
|
# with .github/workflows/build.yml (which calls `rake compile`) and the
|
|
10
10
|
# CHANGELOG when libleptris releases.
|
|
11
|
-
LIBLEPTRIS_VERSION = "1.9.
|
|
11
|
+
LIBLEPTRIS_VERSION = "1.9.309"
|
|
12
12
|
# Vendored alongside libleptris for fn:normalize-unicode (TODO
|
|
13
13
|
# .restructure/20): built per platform with a RELOCATABLE @rpath
|
|
14
14
|
# install name, loaded by ffi.rb before libleptris so the
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/lib/leptris/version.rb
CHANGED
data/vendor-src/README.md
CHANGED
|
@@ -1,5 +1,95 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.9.309] - 2026-10-05
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **XPath lexer: signed exponent literals truncated at the `E` —
|
|
8
|
+
`1E+1` evaluated to `2` and `3.567812E+3 eq 3567.812` was false.**
|
|
9
|
+
The number scanner consumed the exponent digits but not its sign,
|
|
10
|
+
so `1E+1` tokenized as `1E` followed by `+ 1`. The sign is now part
|
|
11
|
+
of the literal (also `5.2E-3` and friends).
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **XQuery numeric literal typing (XQuery 3.1 §3.13.1) with
|
|
16
|
+
end-to-end type discrimination — 17 more QT3 cases adopted
|
|
17
|
+
(abs +5, ceiling +3, floor +3, round-half-to-even +6), 32 with the
|
|
18
|
+
same-batch string-to-codepoints and min/max gates.**
|
|
19
|
+
- Exponent literals are `xs:double`, decimals with a point are
|
|
20
|
+
`xs:decimal`, plain integers `xs:integer`; `1.1 instance of
|
|
21
|
+
xs:double` is now `false` per spec.
|
|
22
|
+
- `instance of` / `typeswitch` match labeled numeric results by
|
|
23
|
+
XDM derivation (`xs:integer` <: `xs:decimal`); `case $v as TYPE`
|
|
24
|
+
arms bind their variable inside the arm. Unlabeled numerics keep
|
|
25
|
+
the historical any-numeric match — no XPath 1.0 surface change.
|
|
26
|
+
- `fn:abs` preserves its argument's numeric type (integer/decimal/
|
|
27
|
+
float/double, float through float32); `fn:ceiling`/`fn:floor`
|
|
28
|
+
label float results; `fn:round-half-to-even` computes its scale
|
|
29
|
+
in double (no `int` truncation UB at 2^32) and guards huge
|
|
30
|
+
scales; `fn:min`/`fn:max` label results by promoted input type;
|
|
31
|
+
FLWOR bindings preserve float/decimal/double marks.
|
|
32
|
+
- Vendor corpus: `fn/string-to-codepoints.xml` (+28), `fn/min`
|
|
33
|
+
and `fn/max` +1 each.
|
|
34
|
+
- Remaining pinned QT3 reds are documented by lever in the test
|
|
35
|
+
harness (HOF node-carrier, map iteration order, typed grouping).
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
## [1.9.308] - 2026-10-05
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- **XPath: `fn:avg` computes in the widest numeric type present
|
|
43
|
+
(F&O 15.2), 13 QT3 cases adopted (fn/avg 175→182, fn/sum 209→210,
|
|
44
|
+
fn/apply 5→10).** Every item converts to the common type before
|
|
45
|
+
summing: with `xs:float` present (no double) the result is
|
|
46
|
+
`xs:float` and every addend rounds through float32 — the lexical
|
|
47
|
+
of `xs:float("-3.4028235E38")` is *not* the float32's value
|
|
48
|
+
(fn-avg-mix-args-012..015); a new `O` typed-scalar mark
|
|
49
|
+
distinguishes `xs:double` from the N catch-all so float+double
|
|
50
|
+
promotes to `xs:double` (cbcl-avg-008); an all-integer sequence
|
|
51
|
+
sums exactly in int64 and divides by long division, spelling the
|
|
52
|
+
exact decimal where a double carrier loses digits past 2^53
|
|
53
|
+
(fn-avgintg2args-2/4: −84503251441487847.5). Untyped atomics
|
|
54
|
+
classify as double (K-SeqAVGFunc-26).
|
|
55
|
+
|
|
56
|
+
- **XQuery: `typeswitch` accepts the full `case $v as TYPE` arm
|
|
57
|
+
form**, binding the variable to the operand inside its arm
|
|
58
|
+
(entries encode `VAR\x02TYPE`). Previously only the type-only
|
|
59
|
+
form parsed — the binding form was a parse failure.
|
|
60
|
+
|
|
61
|
+
- **XQuery: `fn:apply` applies XDM function conversion.** An empty
|
|
62
|
+
array is a legal zero-arity argument list (`apply(true#0, array
|
|
63
|
+
{})`); node-valued members atomize to their string value
|
|
64
|
+
(`apply(lower-case#1, [<a>ABC</a>])` = `abc`, built-ins and
|
|
65
|
+
user-defined functions); a multi-item member of a literal square
|
|
66
|
+
array stays a SEQUENCE argument — fn:apply evaluates the member
|
|
67
|
+
expressions directly and the call paths expand the sub-carrier
|
|
68
|
+
(`fn-apply-03/07`).
|
|
69
|
+
|
|
70
|
+
- **Rust: the shared descriptor-ABI crate `leptris-descriptor`
|
|
71
|
+
(ruby#294 topology step 1).** `bindings/rust` is now a Cargo
|
|
72
|
+
workspace: the `leptris` crate keeps its name and shape, and the
|
|
73
|
+
new `no_std` `#[repr(C)]` mirror of the descriptor-plan ABI
|
|
74
|
+
(descriptor.h) is the one record layout the per-engine crate
|
|
75
|
+
family targets (leptris XML, yeptris YAML, teptris TOML/JSON).
|
|
76
|
+
The `link` feature declares the engine FFI; the authoritative
|
|
77
|
+
layout gate compares Rust `size_of` against the engine's own
|
|
78
|
+
row-size introspection plus a build/walk round trip. `build.rs`
|
|
79
|
+
now re-runs on `LEPTRIS_LIB_PATH` changes (the link directives
|
|
80
|
+
were cached, silently linking a stale library).
|
|
81
|
+
|
|
82
|
+
### Fixed
|
|
83
|
+
|
|
84
|
+
- `fn:sum`'s duration zero answers the empty sequence in the
|
|
85
|
+
TYPE's canonical spelling: `PT0S` for `xs:duration` (fn-sum-8),
|
|
86
|
+
`P0M` kept for `xs:yearMonthDuration` (fn-sum-5).
|
|
87
|
+
- MSVC link failure from `__builtin_add_overflow` (portable
|
|
88
|
+
int64 range check), and two LSan leaks in the new avg/apply
|
|
89
|
+
paths — both caught by CI legs that have no local equivalent.
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
3
93
|
## [1.9.307] - 2026-10-05
|
|
4
94
|
|
|
5
95
|
### Fixed
|
|
@@ -52,6 +142,16 @@
|
|
|
52
142
|
- (describe changes here)
|
|
53
143
|
|
|
54
144
|
|
|
145
|
+
## [1.9.305] - 2026-10-05
|
|
146
|
+
|
|
147
|
+
<!-- Edit this section with the actual release notes. -->
|
|
148
|
+
<!-- See https://keepachangelog.com for format guidance. -->
|
|
149
|
+
|
|
150
|
+
### Changed
|
|
151
|
+
|
|
152
|
+
- (describe changes here)
|
|
153
|
+
|
|
154
|
+
|
|
55
155
|
## [1.9.305] - 2026-10-05
|
|
56
156
|
|
|
57
157
|
### Performance
|
|
@@ -59,3 +59,22 @@ Mirrors the Ruby (`leptris-ruby`) and Python (`pyleptris`) bindings:
|
|
|
59
59
|
a hand-maintained FFI layer (`src/ffi.rs`) mirroring the public
|
|
60
60
|
headers, with safe wrappers above it. The FFI drift gate keeps the
|
|
61
61
|
mirror in sync with the C surface.
|
|
62
|
+
|
|
63
|
+
## Workspace: the shared descriptor-ABI crate
|
|
64
|
+
|
|
65
|
+
`bindings/rust` is a Cargo workspace. Besides the `leptris crate
|
|
66
|
+
(unchanged name and shape — links-only, resolved via
|
|
67
|
+
`LEPTRIS_LIB_PATH`), it contains the `descriptor` member, published
|
|
68
|
+
as **`leptris-descriptor`**: the `no_std` `#[repr(C)]` mirror of the
|
|
69
|
+
tree-shaped descriptor-plan ABI (`src/include/leptris/descriptor.h`).
|
|
70
|
+
It is the one record layout the whole engine family targets — the
|
|
71
|
+
per-engine crates (`leptris` XML, `yeptris` YAML, `teptris`
|
|
72
|
+
TOML/JSON — topology decided 2026-10-03, leptris-ruby#294) — so
|
|
73
|
+
hosts build plan rows once for every engine. The `link` feature
|
|
74
|
+
declares the engine FFI for the descriptor surface; enable it on
|
|
75
|
+
exactly one crate in the graph.
|
|
76
|
+
|
|
77
|
+
The authoritative layout gate is `tests/descriptor_abi.rs` in the
|
|
78
|
+
`leptris` crate: it compares Rust `size_of` against the engine's own
|
|
79
|
+
`leptris_plan_*_struct_size` introspection and walks a plan built
|
|
80
|
+
from the mirrored rows.
|
|
@@ -10,6 +10,10 @@ use std::path::{Path, PathBuf};
|
|
|
10
10
|
use std::{env, fs};
|
|
11
11
|
|
|
12
12
|
fn main() {
|
|
13
|
+
// The lib path changes the emitted link directives; without
|
|
14
|
+
// this the build script output is cached across LEPTRIS_LIB_PATH
|
|
15
|
+
// changes and tests link a stale library.
|
|
16
|
+
println!("cargo:rerun-if-env-changed=LEPTRIS_LIB_PATH");
|
|
13
17
|
// Windows: the DLL is libleptris.dll, so the import library is
|
|
14
18
|
// libleptris.lib — link.exe resolves `-l <name>` as <name>.lib.
|
|
15
19
|
// (TODO.concurrency/05 renamed the DLL from leptris.dll.)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "leptris-descriptor"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
description = "Shared descriptor-plan ABI for the leptris engine family (leptris, yeptris, teptris) — repr(C) mirrors of the tree-shaped descriptor plan records"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
repository = "https://github.com/leptris/leptris"
|
|
8
|
+
homepage = "https://www.leptris.org"
|
|
9
|
+
|
|
10
|
+
[features]
|
|
11
|
+
# Declares the engine FFI (extern "C") for the descriptor surface.
|
|
12
|
+
# Enable on exactly one binding crate in the dependency graph —
|
|
13
|
+
# the declarations carry no symbols of their own.
|
|
14
|
+
link = []
|
|
15
|
+
|
|
16
|
+
[dependencies]
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
//! Shared descriptor-plan ABI for the leptris engine family.
|
|
2
|
+
//!
|
|
3
|
+
//! One crate per engine (`leptris` XML, `yeptris` YAML, `teptris`
|
|
4
|
+
//! TOML/JSON) targets this record layout, so hosts build plan rows
|
|
5
|
+
//! once and every engine's compiled-descriptor walk speaks the same
|
|
6
|
+
//! shape. The types mirror `src/include/leptris/descriptor.h` in the
|
|
7
|
+
//! leptris engine — field order is the ABI; NEVER renumber or
|
|
8
|
+
//! reorder. Additive trailing fields only, guarded by an ABI version
|
|
9
|
+
//! bump.
|
|
10
|
+
//!
|
|
11
|
+
//! Layout is verified at runtime against the engine's own
|
|
12
|
+
//! introspection (`leptris_plan_*_struct_size`) by the linking
|
|
13
|
+
//! binding crate's tests.
|
|
14
|
+
//!
|
|
15
|
+
//! This crate is `no_std`: types and constants only, plus the FFI
|
|
16
|
+
//! declarations behind the `link` feature.
|
|
17
|
+
|
|
18
|
+
#![no_std]
|
|
19
|
+
#![allow(non_camel_case_types, non_snake_case)]
|
|
20
|
+
|
|
21
|
+
use core::ffi::c_char;
|
|
22
|
+
|
|
23
|
+
/// Must equal `leptris_plan_abi_version()` reported by the engine.
|
|
24
|
+
pub const PLAN_ABI_VERSION: u32 = 1;
|
|
25
|
+
|
|
26
|
+
/// Child / attribute plan kinds. Append-only.
|
|
27
|
+
pub type PlanKind = u8;
|
|
28
|
+
pub const PLAN_KIND_SCALAR: PlanKind = 1;
|
|
29
|
+
pub const PLAN_KIND_COLLECTION: PlanKind = 2;
|
|
30
|
+
pub const PLAN_KIND_NESTED: PlanKind = 3;
|
|
31
|
+
pub const PLAN_KIND_RAW: PlanKind = 4;
|
|
32
|
+
pub const PLAN_KIND_CONTENT: PlanKind = 5;
|
|
33
|
+
pub const PLAN_KIND_CALLBACK: PlanKind = 6;
|
|
34
|
+
|
|
35
|
+
/// Element plan flags.
|
|
36
|
+
pub const PLAN_FLAG_MIXED_CONTENT: u32 = 0x1;
|
|
37
|
+
pub const PLAN_FLAG_ORDERED: u32 = 0x2;
|
|
38
|
+
pub const PLAN_FLAG_CDATA: u32 = 0x4;
|
|
39
|
+
pub const PLAN_FLAG_NS_LENIENT: u32 = 0x8;
|
|
40
|
+
pub const PLAN_FLAG_EMIT_ORDER_SPINE: u32 = 0x10;
|
|
41
|
+
|
|
42
|
+
/// Namespace matching form for binding an element or attribute.
|
|
43
|
+
pub type PlanNsForm = u8;
|
|
44
|
+
pub const PLAN_NS_NONE: PlanNsForm = 0;
|
|
45
|
+
pub const PLAN_NS_EXACT: PlanNsForm = 1;
|
|
46
|
+
pub const PLAN_NS_ANY: PlanNsForm = 2;
|
|
47
|
+
|
|
48
|
+
/// Result node kinds (the value tree a walk returns).
|
|
49
|
+
pub type PlanValueKind = i32;
|
|
50
|
+
pub const PLAN_VALUE_ELEMENT: PlanValueKind = 0;
|
|
51
|
+
pub const PLAN_VALUE_SCALAR: PlanValueKind = 1;
|
|
52
|
+
pub const PLAN_VALUE_COLLECTION: PlanValueKind = 2;
|
|
53
|
+
pub const PLAN_VALUE_RAW: PlanValueKind = 3;
|
|
54
|
+
pub const PLAN_VALUE_CALLBACK: PlanValueKind = 4;
|
|
55
|
+
|
|
56
|
+
/// Attribute-match row: requires every (name, expected value) pair.
|
|
57
|
+
#[repr(C)]
|
|
58
|
+
#[derive(Clone, Copy)]
|
|
59
|
+
pub struct AttrPredicate {
|
|
60
|
+
/// XML attribute name as it appears on the wire.
|
|
61
|
+
pub wire_name: *const c_char,
|
|
62
|
+
/// String-equal match (non-null); host-owned.
|
|
63
|
+
pub expected_value: *const c_char,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/// Attribute binding row.
|
|
67
|
+
#[repr(C)]
|
|
68
|
+
#[derive(Clone, Copy)]
|
|
69
|
+
pub struct AttrPlan {
|
|
70
|
+
/// XML attribute name as it appears on the wire.
|
|
71
|
+
pub wire_name: *const c_char,
|
|
72
|
+
/// `PlanKind`: SCALAR | COLLECTION | CALLBACK.
|
|
73
|
+
pub kind: u8,
|
|
74
|
+
/// Host-defined; echoed back verbatim.
|
|
75
|
+
pub type_tag: u8,
|
|
76
|
+
/// Number of `predicates` rows (0 = historical behavior).
|
|
77
|
+
pub predicate_count: u16,
|
|
78
|
+
pub pad_pred: u16,
|
|
79
|
+
pub predicates: *const AttrPredicate,
|
|
80
|
+
/// Attribute-level namespace form; `wire_name` is the LOCAL
|
|
81
|
+
/// name when set. NONE (0) keeps wire-name lookup.
|
|
82
|
+
pub ns_form: u8,
|
|
83
|
+
pub pad_ns: u8,
|
|
84
|
+
/// `PLAN_NS_EXACT` only.
|
|
85
|
+
pub ns_uri: *const c_char,
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/// Child binding row.
|
|
89
|
+
#[repr(C)]
|
|
90
|
+
#[derive(Clone, Copy)]
|
|
91
|
+
pub struct ChildPlan {
|
|
92
|
+
/// XML element name as it appears on the wire: the prefixed
|
|
93
|
+
/// form ("w:b") binds that literal prefix+local pair; the bare
|
|
94
|
+
/// local form ("b") binds by local name and lets `ns_form` do
|
|
95
|
+
/// the namespace work.
|
|
96
|
+
pub wire_name: *const c_char,
|
|
97
|
+
pub kind: u8,
|
|
98
|
+
pub type_tag: u8,
|
|
99
|
+
/// NESTED: index into `PlanSpec::plans`; -1 otherwise.
|
|
100
|
+
pub child_plan_index: i32,
|
|
101
|
+
/// Rule-level namespace form, consulted at child-match time.
|
|
102
|
+
pub ns_form: u8,
|
|
103
|
+
pub pad0: u8,
|
|
104
|
+
/// `PLAN_NS_EXACT` only.
|
|
105
|
+
pub ns_uri: *const c_char,
|
|
106
|
+
/// Element-side predicates; same semantics as `AttrPredicate`.
|
|
107
|
+
pub predicate_count: u16,
|
|
108
|
+
pub pad_pred: u16,
|
|
109
|
+
pub predicates: *const AttrPredicate,
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/// One element plan: the attribute and child rows bound to a name.
|
|
113
|
+
#[repr(C)]
|
|
114
|
+
#[derive(Clone, Copy)]
|
|
115
|
+
pub struct ElementPlan {
|
|
116
|
+
/// Local name this plan binds; matching uses the CHILD row's
|
|
117
|
+
/// `wire_name`.
|
|
118
|
+
pub element_name: *const c_char,
|
|
119
|
+
pub ns_form: u8,
|
|
120
|
+
pub pad0: u8,
|
|
121
|
+
/// `PLAN_NS_EXACT` only.
|
|
122
|
+
pub ns_uri: *const c_char,
|
|
123
|
+
pub attribute_count: u32,
|
|
124
|
+
pub child_count: u32,
|
|
125
|
+
pub attribute_plans: *const AttrPlan,
|
|
126
|
+
pub child_plans: *const ChildPlan,
|
|
127
|
+
/// `PLAN_FLAG_*`.
|
|
128
|
+
pub flags: u16,
|
|
129
|
+
pub pad1: u16,
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/// Top-level plan specification handed to the engine.
|
|
133
|
+
#[repr(C)]
|
|
134
|
+
#[derive(Clone, Copy)]
|
|
135
|
+
pub struct PlanSpec {
|
|
136
|
+
/// Must equal the engine's `leptris_plan_abi_version()`.
|
|
137
|
+
pub abi_version: u32,
|
|
138
|
+
/// `plans[0]` is the root plan applied to the walk context.
|
|
139
|
+
pub plan_count: u32,
|
|
140
|
+
pub plans: *const ElementPlan,
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
#[cfg(feature = "link")]
|
|
144
|
+
pub mod ffi {
|
|
145
|
+
//! Engine FFI for the descriptor surface. Enable this feature on
|
|
146
|
+
//! exactly one crate in the graph (the binding that links an
|
|
147
|
+
//! engine).
|
|
148
|
+
|
|
149
|
+
use super::PlanSpec;
|
|
150
|
+
use core::ffi::{c_char, c_void};
|
|
151
|
+
|
|
152
|
+
/// Opaque engine document handle (leptris: `LeptrisDocument`).
|
|
153
|
+
pub type DocumentHandle = *mut c_void;
|
|
154
|
+
/// Opaque engine element handle (leptris: `LeptrisElement`).
|
|
155
|
+
pub type ElementHandle = *mut c_void;
|
|
156
|
+
/// Status out-parameter (leptris: `LeptrisStatus*`).
|
|
157
|
+
pub type StatusPtr = *mut i32;
|
|
158
|
+
/// Opaque compiled plan.
|
|
159
|
+
pub type Plan = *mut c_void;
|
|
160
|
+
/// Opaque walk result value.
|
|
161
|
+
pub type PlanResult = *const c_void;
|
|
162
|
+
|
|
163
|
+
extern "C" {
|
|
164
|
+
pub fn leptris_plan_abi_version() -> u32;
|
|
165
|
+
pub fn leptris_plan_spec_struct_size() -> usize;
|
|
166
|
+
pub fn leptris_plan_element_row_size() -> usize;
|
|
167
|
+
pub fn leptris_plan_child_row_size() -> usize;
|
|
168
|
+
pub fn leptris_plan_attr_row_size() -> usize;
|
|
169
|
+
pub fn leptris_plan_predicate_row_size() -> usize;
|
|
170
|
+
|
|
171
|
+
pub fn leptris_plan_build(spec: *const PlanSpec, status: StatusPtr) -> Plan;
|
|
172
|
+
pub fn leptris_plan_free(plan: Plan);
|
|
173
|
+
|
|
174
|
+
pub fn leptris_plan_walk(
|
|
175
|
+
doc: DocumentHandle,
|
|
176
|
+
ctx: ElementHandle,
|
|
177
|
+
plan: Plan,
|
|
178
|
+
status: StatusPtr,
|
|
179
|
+
) -> PlanResult;
|
|
180
|
+
pub fn leptris_plan_materialize(
|
|
181
|
+
source: *const c_char,
|
|
182
|
+
source_len: usize,
|
|
183
|
+
plan: Plan,
|
|
184
|
+
status: StatusPtr,
|
|
185
|
+
) -> PlanResult;
|
|
186
|
+
pub fn leptris_plan_result_free(result: PlanResult);
|
|
187
|
+
|
|
188
|
+
pub fn leptris_plan_value_kind(v: PlanResult) -> i32;
|
|
189
|
+
pub fn leptris_plan_value_name(v: PlanResult) -> *const c_char;
|
|
190
|
+
pub fn leptris_plan_value_type_tag(v: PlanResult) -> u8;
|
|
191
|
+
pub fn leptris_plan_value_string(v: PlanResult) -> *const c_char;
|
|
192
|
+
pub fn leptris_plan_value_length(v: PlanResult) -> usize;
|
|
193
|
+
pub fn leptris_plan_value_position(v: PlanResult) -> usize;
|
|
194
|
+
pub fn leptris_plan_value_node_kind(v: PlanResult) -> u8;
|
|
195
|
+
pub fn leptris_plan_value_order_index(v: PlanResult) -> u32;
|
|
196
|
+
pub fn leptris_plan_value_count(v: PlanResult) -> usize;
|
|
197
|
+
pub fn leptris_plan_value_at(v: PlanResult, i: usize) -> PlanResult;
|
|
198
|
+
pub fn leptris_plan_value_children_snapshot(
|
|
199
|
+
v: PlanResult,
|
|
200
|
+
names_blob: *mut c_char,
|
|
201
|
+
blob_cap: usize,
|
|
202
|
+
name_offsets: *mut usize,
|
|
203
|
+
type_tags: *mut u8,
|
|
204
|
+
child_handles: *mut PlanResult,
|
|
205
|
+
) -> usize;
|
|
206
|
+
pub fn leptris_plan_value_attribute(
|
|
207
|
+
v: PlanResult,
|
|
208
|
+
wire_name: *const c_char,
|
|
209
|
+
) -> *const c_char;
|
|
210
|
+
pub fn leptris_plan_value_int(v: PlanResult, out: *mut i64) -> i32;
|
|
211
|
+
pub fn leptris_plan_value_float(v: PlanResult, out: *mut f64) -> i32;
|
|
212
|
+
pub fn leptris_plan_value_bool(v: PlanResult, out: *mut i32) -> i32;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
//! Compile-time layout invariants for the descriptor ABI mirror.
|
|
2
|
+
//!
|
|
3
|
+
//! These check the crate's internal consistency (trailing-field
|
|
4
|
+
//! discipline, alignment) — the BINDING crate's integration test
|
|
5
|
+
//! verifies the sizes against the engine's own introspection, which
|
|
6
|
+
//! is the authoritative gate.
|
|
7
|
+
|
|
8
|
+
use leptris_descriptor::*;
|
|
9
|
+
use std::mem::{align_of, size_of};
|
|
10
|
+
|
|
11
|
+
#[test]
|
|
12
|
+
fn trailing_field_discipline() {
|
|
13
|
+
// Trailing additive fields must not change the size when zeroed:
|
|
14
|
+
// zero-extended aggregate initializers stay valid across ABI
|
|
15
|
+
// additions. repr(C) + these sizes are the contract.
|
|
16
|
+
assert_eq!(size_of::<PlanSpec>(), 4 + 4 + size_of::<*const u8>());
|
|
17
|
+
assert_eq!(align_of::<PlanSpec>(), align_of::<*const u8>());
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
#[test]
|
|
21
|
+
fn kind_and_flag_constants_match_engine_headers() {
|
|
22
|
+
assert_eq!(PLAN_ABI_VERSION, 1);
|
|
23
|
+
assert_eq!(PLAN_KIND_SCALAR, 1);
|
|
24
|
+
assert_eq!(PLAN_KIND_COLLECTION, 2);
|
|
25
|
+
assert_eq!(PLAN_KIND_NESTED, 3);
|
|
26
|
+
assert_eq!(PLAN_KIND_RAW, 4);
|
|
27
|
+
assert_eq!(PLAN_KIND_CONTENT, 5);
|
|
28
|
+
assert_eq!(PLAN_KIND_CALLBACK, 6);
|
|
29
|
+
assert_eq!(PLAN_FLAG_MIXED_CONTENT, 0x1);
|
|
30
|
+
assert_eq!(PLAN_FLAG_ORDERED, 0x2);
|
|
31
|
+
assert_eq!(PLAN_FLAG_CDATA, 0x4);
|
|
32
|
+
assert_eq!(PLAN_FLAG_NS_LENIENT, 0x8);
|
|
33
|
+
assert_eq!(PLAN_FLAG_EMIT_ORDER_SPINE, 0x10);
|
|
34
|
+
assert_eq!(PLAN_NS_NONE, 0);
|
|
35
|
+
assert_eq!(PLAN_NS_EXACT, 1);
|
|
36
|
+
assert_eq!(PLAN_NS_ANY, 2);
|
|
37
|
+
assert_eq!(PLAN_VALUE_ELEMENT, 0);
|
|
38
|
+
assert_eq!(PLAN_VALUE_SCALAR, 1);
|
|
39
|
+
assert_eq!(PLAN_VALUE_COLLECTION, 2);
|
|
40
|
+
assert_eq!(PLAN_VALUE_RAW, 3);
|
|
41
|
+
assert_eq!(PLAN_VALUE_CALLBACK, 4);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
#[test]
|
|
45
|
+
fn row_layouts_are_pointer_sized_aligned() {
|
|
46
|
+
assert_eq!(align_of::<AttrPredicate>(), align_of::<*const u8>());
|
|
47
|
+
assert_eq!(align_of::<AttrPlan>(), align_of::<*const u8>());
|
|
48
|
+
assert_eq!(align_of::<ChildPlan>(), align_of::<*const u8>());
|
|
49
|
+
assert_eq!(align_of::<ElementPlan>(), align_of::<*const u8>());
|
|
50
|
+
}
|