lutaml-model 0.8.51 → 0.8.52
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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 92e0193fa58094112522b5a7717aed2f568d77096eb0ae3bc1a246be28c05bf0
|
|
4
|
+
data.tar.gz: 20dcd124c22c695cc0a8fca65d04422ac84f468515ef153d909e5a6dcf5eac67
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0cc3e71dceb6ae87db00453efbd905de28dc10d528cd38426b29c2c0da1a67d64d41a59095e45a9da1daa97888a4d001c8211b0ad64a3a011ef46949e71206a6
|
|
7
|
+
data.tar.gz: c444800a986c0e34bc1502fd671f53d7ff4776377d89b62225b857c923f4b97058042094145caf0d0a54db37576bedd546a733e114a444118ff2e13241092d83
|
|
@@ -57,9 +57,31 @@ RUBY_YJIT_ENABLE=1 ruby app.rb
|
|
|
57
57
|
RubyVM::YJIT.enable
|
|
58
58
|
----
|
|
59
59
|
|
|
60
|
-
The
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
The XML plan fast path moves work out of Ruby and into the engine,
|
|
61
|
+
which shrinks the YJIT win — enabling both is still net faster than
|
|
62
|
+
either alone.
|
|
63
|
+
|
|
64
|
+
== The XML plan fast path (default on)
|
|
65
|
+
|
|
66
|
+
When the XML adapter resolves to leptris, XML (de)serialization
|
|
67
|
+
compiles the model's mapping into a leptris descriptor plan and runs
|
|
68
|
+
the whole document through one native pass — measured 6.7x parse and
|
|
69
|
+
4x serialize with -76% / -80% allocations on the plan-path corpus.
|
|
70
|
+
Models the plan cannot express exactly (same-name discriminator
|
|
71
|
+
partitions, namespace-qualified models with deferred-rule shapes) and
|
|
72
|
+
shapes with custom semantics (custom methods, polymorphism, unions,
|
|
73
|
+
ordered children) hydrate through the interpretive pipeline or a
|
|
74
|
+
per-subtree fragment of it, unchanged.
|
|
75
|
+
|
|
76
|
+
The path is on by default and is a no-op without leptris (standard
|
|
77
|
+
adapters keep the classic pipeline). Opt out for the whole process:
|
|
78
|
+
|
|
79
|
+
[source,ruby]
|
|
80
|
+
----
|
|
81
|
+
Lutaml::Model::Config.configure do |config|
|
|
82
|
+
config.xml_plan_fast_path = false
|
|
83
|
+
end
|
|
84
|
+
----
|
|
63
85
|
|
|
64
86
|
== Selecting adapters explicitly
|
|
65
87
|
|
data/lib/lutaml/model/version.rb
CHANGED
|
@@ -39,7 +39,21 @@ module Lutaml
|
|
|
39
39
|
key = [model_class, register]
|
|
40
40
|
return PLAN_CACHE[key] if PLAN_CACHE.key?(key)
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
# Cycle guard: a self-referential model (JATS sec-in-sec) must
|
|
43
|
+
# resolve to nil — the interpretive pipeline owns it. The guard
|
|
44
|
+
# is THREAD-LOCAL (a shared in-progress set races: a concurrent
|
|
45
|
+
# same-key compile would cache false permanently — the #828
|
|
46
|
+
# lesson); the nil at the cycle point is NOT cached — the
|
|
47
|
+
# outermost build completes and caches the real verdict.
|
|
48
|
+
stack = (Thread.current[:plan_compiler_stack] ||= [])
|
|
49
|
+
return nil if stack.include?(key)
|
|
50
|
+
|
|
51
|
+
stack.push(key)
|
|
52
|
+
begin
|
|
53
|
+
PLAN_CACHE[key] = build(model_class, register)
|
|
54
|
+
ensure
|
|
55
|
+
stack.pop
|
|
56
|
+
end
|
|
43
57
|
end
|
|
44
58
|
|
|
45
59
|
private
|
|
@@ -38,8 +38,42 @@ RSpec.describe "XML plan fast path" do
|
|
|
38
38
|
Lutaml::Model::Config.instance.xml_plan_fast_path = old
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
# Real-corpus crash (niso-jats): sec-in-sec nesting is a
|
|
42
|
+
# self-referential model — compile must resolve it to nil instead of
|
|
43
|
+
# recursing to SystemStackError.
|
|
44
|
+
it "opts self-referential models out instead of recursing" do
|
|
45
|
+
node = Class.new(Lutaml::Model::Serializable) do
|
|
46
|
+
attribute :text, :string
|
|
47
|
+
xml do
|
|
48
|
+
element "n"
|
|
49
|
+
map_content to: :text
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
node.attribute :child, node
|
|
53
|
+
node.xml do
|
|
54
|
+
element "n"
|
|
55
|
+
map_content to: :text
|
|
56
|
+
map_element "child", to: :child
|
|
57
|
+
end
|
|
58
|
+
stub_const("PlanFastPath::SelfRef", node)
|
|
59
|
+
|
|
60
|
+
expect(Lutaml::Xml::PlanCompiler.compile(node, :default)).to be_nil
|
|
61
|
+
|
|
62
|
+
xml = "<n>#{'<n>t</n>' * 200}</n>"
|
|
63
|
+
parsed = node.from_xml(xml)
|
|
64
|
+
expect(parsed).to be_a(node)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "is on by default and can be disabled" do
|
|
68
|
+
expect(Lutaml::Model::Configuration.new.xml_plan_fast_path).to be(true)
|
|
69
|
+
|
|
70
|
+
# Opt-out restores the interpretive pipeline for the whole process.
|
|
71
|
+
Lutaml::Model::Config.instance.xml_plan_fast_path = false
|
|
72
|
+
item = item_class.new(id: 1, name: "a", tags: %w[x])
|
|
73
|
+
parsed = root_class.from_xml(root_class.new(item: [item]).to_xml)
|
|
74
|
+
expect(parsed.item.first.id).to eq(1)
|
|
75
|
+
ensure
|
|
76
|
+
Lutaml::Model::Config.instance.xml_plan_fast_path = true
|
|
43
77
|
end
|
|
44
78
|
|
|
45
79
|
it "hydrates equal to the interpretive path" do
|