Implement hash and set
parent
74c71a57c3
commit
6a70810667
|
@ -21,14 +21,17 @@ describe "CBOR helpers on basic types" do
|
|||
{Nil, Bytes[0xf7], nil},
|
||||
{Float32, Bytes[0xfb, 0x3f, 0xf1, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a], 1.1_f32},
|
||||
{Float64, Bytes[0xfa, 0x47, 0xc3, 0x50, 0x00], 100000.0_f64},
|
||||
{Set(Int8), Bytes[0x83, 0x01, 0x02, 0x03], Set(Int8){1, 2, 3}},
|
||||
{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(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]]},
|
||||
{Hash(UInt8, UInt8), Bytes[0xa0], {} of UInt8 => UInt8},
|
||||
{Hash(UInt8, UInt8), Bytes[0xa2, 0x01, 0x02, 0x03, 0x04], Hash(UInt8, UInt8){1 => 2, 3 => 4}},
|
||||
]
|
||||
|
||||
tests.each do |tt|
|
||||
|
|
|
@ -76,12 +76,19 @@ class CBOR::Decoder
|
|||
end
|
||||
end
|
||||
|
||||
def consume_hash(&block)
|
||||
read_type(Token::MapT, finish_token: false) do |token|
|
||||
read(token.size) { yield }
|
||||
end
|
||||
end
|
||||
|
||||
private def finish_token!
|
||||
@current_token = @lexer.next_token
|
||||
end
|
||||
|
||||
def read(size : Int32?, &block)
|
||||
private def read(size : Int32?, &block)
|
||||
if size
|
||||
finish_token!
|
||||
size.times { yield }
|
||||
else
|
||||
@lexer.until_break do |token|
|
||||
|
|
|
@ -45,6 +45,21 @@ def Array.new(decoder : CBOR::Decoder)
|
|||
arr
|
||||
end
|
||||
|
||||
def Set.new(decoder : CBOR::Decoder)
|
||||
set = new
|
||||
decoder.consume_array { set << T.new(decoder) }
|
||||
set
|
||||
end
|
||||
|
||||
def Hash.new(decoder : CBOR::Decoder)
|
||||
hash = new
|
||||
decoder.consume_hash do
|
||||
k = K.new(decoder)
|
||||
hash[k] = V.new(decoder)
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
# 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].
|
||||
#
|
||||
|
@ -66,50 +81,51 @@ def Time.new(decoder : CBOR::Decoder)
|
|||
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 %}
|
||||
case decoder.current_token
|
||||
{% if T.includes? Nil %}
|
||||
when CBOR::Token::SimpleValueT
|
||||
return decoder.read_nil
|
||||
{% end %}
|
||||
{% if T.includes? Bool %}
|
||||
when CBOR::Token::BoolT
|
||||
return decoder.read_bool
|
||||
{% end %}
|
||||
{% if T.includes? String %}
|
||||
when CBOR::Token::StringT
|
||||
return decoder.read_string
|
||||
{% end %}
|
||||
when CBOR::Token::IntT
|
||||
{% type_order = [Int64, UInt64, Int32, UInt32, Int16, UInt16, Int8, UInt8, Float64, Float32] %}
|
||||
{% for type in type_order.select { |t| T.includes? t } %}
|
||||
return {{type}}.new(decoder)
|
||||
{% end %}
|
||||
when CBOR::Token::FloatT
|
||||
{% type_order = [Float64, Float32] %}
|
||||
{% for type in type_order.select { |t| T.includes? t } %}
|
||||
return {{type}}.new(decoder)
|
||||
{% end %}
|
||||
end
|
||||
{% end %}
|
||||
|
||||
{% begin %}
|
||||
{% primitive_types = [Nil, Bool, String] + Number::Primitive.union_types %}
|
||||
{% non_primitives = T.reject { |t| primitive_types.includes? t } %}
|
||||
|
||||
# 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 %}
|
||||
string = pull.read_raw
|
||||
{% for type in non_primitives %}
|
||||
begin
|
||||
return {{type}}.from_json(string)
|
||||
rescue CBOR::ParseError
|
||||
# Ignore
|
||||
end
|
||||
{% end %}
|
||||
raise CBOR::ParseError.new("Couldn't parse #{self} from #{string}", *location)
|
||||
{% end %}
|
||||
{% end %}
|
||||
|
||||
raise CBOR::ParseError.new("Couldn't parse data as " + {{T.stringify}})
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue