module Selenium::WebDriver::BiDi::Serialization::Record::Deserializer
def check_outbound_shape(field, value)
Outbound mirror of check_shape: a list-typed arg must be an array, a scalar-shaped one
def check_outbound_shape(field, value) return if field.list == value.is_a?(::Array) return unless field.list || field.enum || field.ref kind = field.list ? 'a list' : 'a single value' raise ::ArgumentError, "#{name}##{field.name} expected #{kind}, got #{value.inspect}" end
def check_primitive(field, raw)
def check_primitive(field, raw) expected = PRIMITIVE_TYPES[field.primitive] return if expected.nil? || expected.any? { |type| raw.is_a?(type) } raise Error::WebDriverError, "#{name}##{field.name} expected #{field.primitive}, got #{raw.inspect}" end
def check_shape(field, raw)
A declared list must arrive as an array; a scalar-shaped field (enum or ref, not a
def check_shape(field, raw) return if field.list == raw.is_a?(::Array) return unless field.list || field.enum || field.ref raise Error::WebDriverError, "#{name}##{field.name} expected #{field.list ? 'a list' : 'a single value'}, got #{raw.inspect}" end
def enum_hash(field)
def enum_hash(field) (@enums ||= {})[field.name] ||= Protocol.const_get(field.enum) end
def extra(json_payload)
def extra(json_payload) known = (@wire_keys ||= fields.map(&:wire_key)) json_payload.except(*known) end
def fixed?(field)
def fixed?(field) !UNSET.equal?(field.fixed) end
def from_json(json_payload)
enum tokens are mapped back to symbols and an unrecognized one raises (in +read+), and
Inbound: builds from the wire. A missing required field raises (in +wire_value+),
def from_json(json_payload) unless json_payload.is_a?(::Hash) raise Error::WebDriverError, "#{name} expected an object on the wire, got #{json_payload.inspect}" end attributes = fields.to_h do |f| [f.name, wire_value(f, json_payload)] end attributes[:extensions] = extra(json_payload) if extensible? construct(**attributes) end
def new(**kwargs)
def new(**kwargs) # Start from what was passed so ::Data's constructor rejects an unknown key, then fill # each field with its value or UNSET (omitted), forcing fixed discriminators. attributes = kwargs.dup fields.each { |f| attributes[f.name] = fixed?(f) ? f.fixed : attributes.fetch(f.name, UNSET) } attributes[:extensions] = kwargs.fetch(:extensions, {}) if extensible? validate_values(attributes) construct(**attributes) end
def read(field, raw)
def read(field, raw) if raw.nil? return raw if field.nullable raise Error::WebDriverError, "#{name}##{field.name} received null but is not nullable" end check_shape(field, raw) return Serialization.to_symbol("#{name}##{field.name}", raw, enum_hash(field)) if field.enum if field.ref.nil? check_primitive(field, raw) unless field.list return raw end klass = (@refs ||= {})[field.name] ||= Protocol.const_get(field.ref) field.list ? read_list(raw, klass) : klass.from_json(raw) end
def read_list(raw, klass)
Parses each element, recursing into nested lists (e.g. a map's [key, value] pairs)
def read_list(raw, klass) raw.map { |element| element.is_a?(::Array) ? read_list(element, klass) : klass.from_json(element) } end
def validate_values(attributes)
constant is resolved lazily so a cross-domain enum need not be loaded first. Outbound
silently dropped on the wire), and an enum field must be in its allowed set. The enum
field cannot be nil (nil is neither a value nor the UNSET omit-sentinel, so it would be
Checks each field's value: a required field cannot be omitted (UNSET), a non-nullable
def validate_values(attributes) fields.each do |f| value = attributes[f.name] raise ::ArgumentError, "#{name}##{f.name} is required" if UNSET.equal?(value) && f.required raise ::ArgumentError, "#{name}##{f.name} cannot be nil" if value.nil? && !f.nullable next if value.nil? || UNSET.equal?(value) check_outbound_shape(f, value) Serialization.validate!("#{name}##{f.name}", value, Protocol.const_get(f.enum)) if f.enum end end
def wire_value(field, json_payload)
def wire_value(field, json_payload) return field.fixed if fixed?(field) return read(field, json_payload[field.wire_key]) if json_payload.key?(field.wire_key) return UNSET unless field.required raise Error::WebDriverError, "#{name}##{field.name} is required but was missing from the response" end