WIP: Array
parent
839a41dd84
commit
74c71a57c3
|
@ -21,6 +21,14 @@ describe "CBOR helpers on basic types" do
|
||||||
{Nil, Bytes[0xf7], nil},
|
{Nil, Bytes[0xf7], nil},
|
||||||
{Float32, Bytes[0xfb, 0x3f, 0xf1, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a], 1.1_f32},
|
{Float32, Bytes[0xfb, 0x3f, 0xf1, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a], 1.1_f32},
|
||||||
{Float64, Bytes[0xfa, 0x47, 0xc3, 0x50, 0x00], 100000.0_f64},
|
{Float64, Bytes[0xfa, 0x47, 0xc3, 0x50, 0x00], 100000.0_f64},
|
||||||
|
{Array(Int8), Bytes[0x83, 0x01, 0x02, 0x03], [1_i8, 2_i8, 3_i8]},
|
||||||
|
{Array(Array(Int8) | Int8),
|
||||||
|
Bytes[0x83, 0x01, 0x82, 0x02, 0x03, 0x82, 0x04, 0x05],
|
||||||
|
[1_i8, [2_i8, 3_i8], [4_i8, 5_i8]]},
|
||||||
|
{Array(UInt8), Bytes[0x9f, 0xff], [] of UInt8},
|
||||||
|
# {Array(Array(Int8) | Int8),
|
||||||
|
# Bytes[0x9f, 0x01, 0x82, 0x02, 0x03, 0x9f, 0x04, 0x05, 0xff, 0xff],
|
||||||
|
# [1_i8, [2_i8, 3_i8], [4_i8, 5_i8]]},
|
||||||
]
|
]
|
||||||
|
|
||||||
tests.each do |tt|
|
tests.each do |tt|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
class CBOR::Decoder
|
class CBOR::Decoder
|
||||||
@lexer : Lexer
|
@lexer : Lexer
|
||||||
@current_token : Token::T?
|
getter current_token : Token::T?
|
||||||
|
|
||||||
def initialize(input)
|
def initialize(input)
|
||||||
@lexer = Lexer.new(input)
|
@lexer = Lexer.new(input)
|
||||||
|
@ -70,10 +70,27 @@ class CBOR::Decoder
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def consume_array(&block)
|
||||||
|
read_type(Token::ArrayT, finish_token: false) do |token|
|
||||||
|
read(token.size) { yield }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private def finish_token!
|
private def finish_token!
|
||||||
@current_token = @lexer.next_token
|
@current_token = @lexer.next_token
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def read(size : Int32?, &block)
|
||||||
|
if size
|
||||||
|
size.times { yield }
|
||||||
|
else
|
||||||
|
@lexer.until_break do |token|
|
||||||
|
@current_token = token
|
||||||
|
yield
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private macro read_type(type, finish_token = true, ignore_tag = true, &block)
|
private macro read_type(type, finish_token = true, ignore_tag = true, &block)
|
||||||
# Skip the tag unless the token we want to read is a tag
|
# Skip the tag unless the token we want to read is a tag
|
||||||
{% if ignore_tag %}
|
{% if ignore_tag %}
|
||||||
|
|
|
@ -39,6 +39,12 @@ def Slice.new(decoder : CBOR::Decoder)
|
||||||
decoder.read_bytes.to_slice
|
decoder.read_bytes.to_slice
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def Array.new(decoder : CBOR::Decoder)
|
||||||
|
arr = new
|
||||||
|
decoder.consume_array { arr << T.new(decoder) }
|
||||||
|
arr
|
||||||
|
end
|
||||||
|
|
||||||
# Reads the CBOR values as a time. The value must be surrounded by a time tag as
|
# Reads the CBOR values as a time. The value must be surrounded by a time tag as
|
||||||
# specified by [Section 2.4.1 of RFC 7049][1].
|
# specified by [Section 2.4.1 of RFC 7049][1].
|
||||||
#
|
#
|
||||||
|
@ -58,3 +64,52 @@ def Time.new(decoder : CBOR::Decoder)
|
||||||
raise CBOR::ParseError.new("Expected tag to have value 0 or 1, got #{tag.value.to_s}")
|
raise CBOR::ParseError.new("Expected tag to have value 0 or 1, got #{tag.value.to_s}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def Union.new(decoder : CBOR::Decoder)
|
||||||
|
token = decoder.current_token
|
||||||
|
|
||||||
|
# Optimization: use fast path for primitive types
|
||||||
|
{% begin %}
|
||||||
|
# Here we store types that are not primitive types
|
||||||
|
{% non_primitives = [] of Nil %}
|
||||||
|
|
||||||
|
{% for type, index in T %}
|
||||||
|
{% if type == Nil %}
|
||||||
|
return decoder.read_nil if token.is_a?(CBOR::Token::SimpleValueT)
|
||||||
|
{% elsif type == Bool %}
|
||||||
|
return decoder.read_bool if token.is_a?(CBOR::Token::SimpleValueT)
|
||||||
|
{% elsif type == String %}
|
||||||
|
return decoder.read_string if token.is_a?(CBOR::Token::StringT)
|
||||||
|
{% elsif type == Int8 || type == Int16 || type == Int32 || type == Int64 ||
|
||||||
|
type == UInt8 || type == UInt16 || type == UInt32 || type == UInt64 %}
|
||||||
|
return {{type}}.new(decoder) if token.is_a?(CBOR::Token::IntT)
|
||||||
|
{% elsif type == Float32 || type == Float64 %}
|
||||||
|
return {{type}}.new(decoder) if token.is_a?(CBOR::Token::FloatT)
|
||||||
|
{% unless T.any? { |t| t < Int } %}
|
||||||
|
return {{type}}.new(decoder) if token.is_a?(CBOR::Token::IntT)
|
||||||
|
{% end %}
|
||||||
|
{% else %}
|
||||||
|
{% non_primitives << type %}
|
||||||
|
{% end %}
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
# If after traversing all the types we are left with just one
|
||||||
|
# non-primitive type, we can parse it directly (no need to use `read_raw`)
|
||||||
|
{% if non_primitives.size == 1 %}
|
||||||
|
return {{non_primitives[0]}}.new(decoder)
|
||||||
|
{% else %}
|
||||||
|
raise "What is this?"
|
||||||
|
# node = decoder.read_node
|
||||||
|
# {% for type in non_primitives %}
|
||||||
|
# unpacker = CBOR::NodeUnpacker.new(node)
|
||||||
|
# begin
|
||||||
|
# return {{type}}.new(unpacker)
|
||||||
|
# rescue e : CBOR::TypeCastError
|
||||||
|
# # ignore
|
||||||
|
# end
|
||||||
|
# {% end %}
|
||||||
|
# {% end %}
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
raise CBOR::ParseError.new("Couldn't parse data as " + {{T.stringify}})
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in New Issue