Decoding: use_cbor_discriminator
parent
b0c62f89c8
commit
4d200998c1
|
@ -2,6 +2,19 @@ class CBOR::Decoder
|
||||||
@lexer : Lexer
|
@lexer : Lexer
|
||||||
getter current_token : Token::T?
|
getter current_token : Token::T?
|
||||||
|
|
||||||
|
# Decode until a certain point in the history (use_cbor_discriminator helper).
|
||||||
|
def reset(value : Int32 | Int64 = 0)
|
||||||
|
@lexer.reset
|
||||||
|
while pos < value
|
||||||
|
@current_token = @lexer.next_token
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Give the current position in the decoder (use_cbor_discriminator helper).
|
||||||
|
def pos
|
||||||
|
@lexer.io.pos
|
||||||
|
end
|
||||||
|
|
||||||
def initialize(input)
|
def initialize(input)
|
||||||
@lexer = Lexer.new(input)
|
@lexer = Lexer.new(input)
|
||||||
@current_token = @lexer.next_token
|
@current_token = @lexer.next_token
|
||||||
|
|
|
@ -3,6 +3,10 @@ def Object.from_cbor(string_or_io)
|
||||||
new(parser)
|
new(parser)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def Object.from_cbor(parser : CBOR::Decoder)
|
||||||
|
new(parser)
|
||||||
|
end
|
||||||
|
|
||||||
def String.new(decoder : CBOR::Decoder)
|
def String.new(decoder : CBOR::Decoder)
|
||||||
decoder.read_string
|
decoder.read_string
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class CBOR::Lexer
|
class CBOR::Lexer
|
||||||
|
property io : IO
|
||||||
def self.new(slice : Bytes)
|
def self.new(slice : Bytes)
|
||||||
new IO::Memory.new(slice)
|
new IO::Memory.new(slice)
|
||||||
end
|
end
|
||||||
|
@ -8,6 +9,11 @@ class CBOR::Lexer
|
||||||
def initialize(@io : IO)
|
def initialize(@io : IO)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reset(value : Int32 | Int64 = 0)
|
||||||
|
@io.seek value
|
||||||
|
@eof = false
|
||||||
|
end
|
||||||
|
|
||||||
def next_token : Token::T?
|
def next_token : Token::T?
|
||||||
return nil if @eof
|
return nil if @eof
|
||||||
|
|
||||||
|
|
|
@ -345,6 +345,36 @@ module CBOR
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
macro use_cbor_discriminator(field, mapping)
|
||||||
|
{% unless mapping.is_a?(HashLiteral) || mapping.is_a?(NamedTupleLiteral) %}
|
||||||
|
{% mapping.raise "mapping argument must be a HashLiteral or a NamedTupleLiteral, not #{mapping.class_name.id}" %}
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
# SLOW. Read everything, get the type, read everything again.
|
||||||
|
def self.new(decoder : ::CBOR::Decoder)
|
||||||
|
current_offset = decoder.pos
|
||||||
|
if v = decoder.read_value
|
||||||
|
decoder.reset current_offset
|
||||||
|
case v
|
||||||
|
when Hash(CBOR::Type, CBOR::Type)
|
||||||
|
discriminator_value = v[{{field.id.stringify}}]?
|
||||||
|
case discriminator_value
|
||||||
|
{% for key, value in mapping %}
|
||||||
|
when {{key.id.stringify}}
|
||||||
|
return {{value.id}}.from_cbor(decoder)
|
||||||
|
{% end %}
|
||||||
|
else
|
||||||
|
raise "Unknown '{{field.id}}' discriminator value: #{discriminator_value.inspect}"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
raise "cannot get cbor discriminator #{ {{ field.id.stringify }} }"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
raise "cannot decode cbor value"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Tells this class to decode CBOR by using a field as a discriminator.
|
# Tells this class to decode CBOR by using a field as a discriminator.
|
||||||
#
|
#
|
||||||
# - *field* must be the field name to use as a discriminator
|
# - *field* must be the field name to use as a discriminator
|
||||||
|
|
Loading…
Reference in New Issue