lutaml-model 0.8.69 → 0.8.70

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: f8ea7edf1c5b0a9d5e208fb6a83df7f40eba0a83e9ac78797130269e1a3cba7c
4
- data.tar.gz: 7f2d97eac672eae74a1a192db0196305d62c45d3bd1f34855fb30a79475d6f88
3
+ metadata.gz: 2e3d309f15ab3866bd793f01385378fc7294127de341e8914a27838bfd6b956c
4
+ data.tar.gz: ac90f885dd393c008adb09187586ec2698d9e1f40a8f3fd9bb579ad12e776fe3
5
5
  SHA512:
6
- metadata.gz: e202fb8a65018521903d42867ecd434df1f84c8568eab99f0f4e737651b6ecb51e91fc60c9b188aecc8e65f645bb10f9103a73b70617356a05c9d7ba566c8c8a
7
- data.tar.gz: cabf97f1c9aaf7432a4831d3c5b5fec4d54306a073f9deb4e1e2cb4bf7ad97b608b52775cfef0b73294c51fd794368531c521386bb55a84ac2c1c23ad4004e56
6
+ metadata.gz: 5911aff11ba087c00b6854ee18106df409516688b093e28149f6dbff8c31ea00d15cc82ff67cfe85fbb0c61d34d0d14849d43d1c4e2a114be41e244d293f5b1c
7
+ data.tar.gz: 91b861ce8a517ee382284684f2516493d96f5aef6a1588e9a01eefb1108e9fb86a37a91dbbda39cf02a0b38f32ce8f9603dc5498f2e7b4fec647d21bfaca6587
@@ -177,18 +177,21 @@ module Lutaml
177
177
  .substitution_for(type).any?
178
178
 
179
179
  if type.is_a?(Class) && type.include?(Lutaml::Model::Serialize)
180
- child_rows = kv_group_plan(type, format,
181
- Lutaml::Model::Register
182
- .resolve_for_child(type, register))
180
+ child_register = Lutaml::Model::Register
181
+ .resolve_for_child(type, register)
182
+ child_rows = kv_group_plan(type, format, child_register)
183
183
  return false unless child_rows
184
184
 
185
185
  rows ||= []
186
- rows << [rule, attr, :model, type, child_rows]
186
+ # child_register rides the row: the plan was BUILT under it,
187
+ # and rebuilding the resolution per model row per document
188
+ # cost a Concurrent::Map hop each time (TODO.perf 14).
189
+ rows << [rule, attr, :model, type, child_rows, child_register]
187
190
  elsif type.is_a?(Class) && type < Lutaml::Model::Type::Value &&
188
191
  !attr.value_policy.whole_value?(type) &&
189
192
  !Lutaml::Model::Attribute.custom_from_probe?(type)
190
193
  rows ||= []
191
- rows << [rule, attr, :scalar, nil, nil]
194
+ rows << [rule, attr, :scalar, nil, nil, nil]
192
195
  else
193
196
  return false
194
197
  end
@@ -208,7 +211,7 @@ module Lutaml
208
211
  setters = []
209
212
  children = []
210
213
  absent = []
211
- rows.each do |rule, attr, kind, type, child_rows|
214
+ rows.each do |rule, attr, kind, type, child_rows, child_register|
212
215
  # One hash pass per row: fetch with a sentinel distinguishes
213
216
  # absent keys from present-nil values (both read as nil), so
214
217
  # the separate string_or_symbol_key? probe goes away.
@@ -223,8 +226,6 @@ module Lutaml
223
226
  next
224
227
  end
225
228
 
226
- child_register = Lutaml::Model::Register.resolve_for_child(type,
227
- register)
228
229
  if attr.collection?
229
230
  # A present-but-nil collection reaches the per-rule walk,
230
231
  # which owns the sentinel interplay for that edge
@@ -197,8 +197,11 @@ module Lutaml
197
197
  end
198
198
 
199
199
  def attr_value(attrs, name, attribute)
200
- value = Utils.fetch_str_or_sym(attrs, name,
201
- attribute.default(lutaml_register, self))
200
+ # The default is computed only on absence: it used to be
201
+ # evaluated eagerly as the fetch fallback on EVERY value,
202
+ # paying proc/static default dispatch per present attribute.
203
+ value = Utils.fetch_str_or_sym(attrs, name, Utils::MISSING)
204
+ value = attribute.default(lutaml_register, self) if value.equal?(Utils::MISSING)
202
205
  attribute.cast_value(value, lutaml_register)
203
206
  end
204
207
 
@@ -368,15 +371,20 @@ module Lutaml
368
371
  value = self.class.apply_value_map(value, vmap, attr)
369
372
  # Performance: Only call ensure_utf8 for string values
370
373
  value = self.class.ensure_utf8(value) if value.is_a?(::String)
371
- public_send(:"#{name}=", value)
374
+ # Interpolating the writer symbol allocated a String per
375
+ # attribute per instance; the per-register writer table is
376
+ # interned once per class.
377
+ public_send(self.class.instantiate_writers(lutaml_register)[name], value)
372
378
  using_default_for(name) if default
373
379
  end
374
380
  end
375
381
 
376
382
  def determine_value(attrs, name, attr)
377
- if attrs.key?(name) || attrs.key?(name.to_s)
378
- return attr_value(attrs, name, attr)
379
- end
383
+ # One hash pass: a sentinel fetch distinguishes absent keys
384
+ # from present-nil values, replacing two key probes plus the
385
+ # re-fetch inside attr_value (four hash ops per attribute).
386
+ value = Utils.fetch_str_or_sym(attrs, name, Utils::MISSING)
387
+ return attr.cast_value(value, lutaml_register) unless value.equal?(Utils::MISSING)
380
388
 
381
389
  resolved = attr.default_value(lutaml_register, self)
382
390
  return Lutaml::Model::UninitializedClass.instance if Lutaml::Model::Utils.uninitialized?(resolved)
@@ -3,6 +3,10 @@
3
3
  module Lutaml
4
4
  module Model
5
5
  module Utils
6
+ # Fetch sentinel distinguishing absent keys from present-nil
7
+ # values; shared by the deserialization fast paths.
8
+ MISSING = Object.new.freeze
9
+
6
10
  class << self
7
11
  UNINITIALIZED = Lutaml::Model::UninitializedClass.instance
8
12
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Lutaml
4
4
  module Model
5
- VERSION = "0.8.69"
5
+ VERSION = "0.8.70"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lutaml-model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.69
4
+ version: 0.8.70
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.