Start implementing from_cbor decoding
parent
9739c4971b
commit
547e8af2bd
|
@ -0,0 +1,24 @@
|
||||||
|
require "../spec_helper"
|
||||||
|
|
||||||
|
describe "CBOR helpers on basic types" do
|
||||||
|
describe "#from_cbor" do
|
||||||
|
tests = [
|
||||||
|
{String, Bytes[0x61, 0x61], "a"},
|
||||||
|
{UInt8, Bytes[0x18, 0x18], 24},
|
||||||
|
{UInt16, Bytes[0x19, 0x03, 0xe8], 1000},
|
||||||
|
{UInt32, Bytes[0x1a, 0x00, 0x0f, 0x42, 0x40], 1000000},
|
||||||
|
{UInt64, Bytes[0x1b, 0x00, 0x00, 0x00, 0xe8, 0xd4, 0xa5, 0x10, 0x00], 1000000000000},
|
||||||
|
{Int8, Bytes[0x29], -10},
|
||||||
|
{Bytes, Bytes[0x44, 0x01, 0x02, 0x03, 0x04], Bytes[0x01, 0x02, 0x03, 0x04]},
|
||||||
|
]
|
||||||
|
|
||||||
|
tests.each do |tt|
|
||||||
|
type, bytes, want = tt
|
||||||
|
|
||||||
|
it "decodes #{type.class}" do
|
||||||
|
res = type.from_cbor(bytes)
|
||||||
|
res.should eq(want)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,50 @@
|
||||||
|
class CBOR::Decoder
|
||||||
|
@lexer : Lexer
|
||||||
|
@current_token : Token::T?
|
||||||
|
|
||||||
|
def initialize(input)
|
||||||
|
@lexer = Lexer.new(input)
|
||||||
|
@current_token = @lexer.next_token
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_string : String
|
||||||
|
case token = @current_token
|
||||||
|
when Token::StringT
|
||||||
|
finish_token!
|
||||||
|
token.value
|
||||||
|
when Token::BytesT
|
||||||
|
finish_token!
|
||||||
|
String.new(token.value)
|
||||||
|
else
|
||||||
|
unexpected_token(token, "StringT or BytesT")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_int
|
||||||
|
read_type(Token::IntT) { |token| token.value }
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_bytes
|
||||||
|
read_type(Token::BytesT) { |token| token.value }
|
||||||
|
end
|
||||||
|
|
||||||
|
private def finish_token!
|
||||||
|
@current_token = @lexer.next_token
|
||||||
|
end
|
||||||
|
|
||||||
|
private macro read_type(type, finish_token = true, &block)
|
||||||
|
case token = @current_token
|
||||||
|
when {{type}}
|
||||||
|
{% if finish_token %}finish_token!{% end %}
|
||||||
|
{{ block.body }}
|
||||||
|
else
|
||||||
|
unexpected_token(token, {{type.stringify.split("::").last}})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private def unexpected_token(token, expected = nil)
|
||||||
|
message = "Unexpected token #{token.class}"
|
||||||
|
message += " expected #{expected}" if expected
|
||||||
|
raise ParseError.new(message)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,24 @@
|
||||||
|
def Object.from_cbor(string_or_io)
|
||||||
|
parser = CBOR::Decoder.new(string_or_io)
|
||||||
|
new(parser)
|
||||||
|
end
|
||||||
|
|
||||||
|
def String.new(decoder : CBOR::Decoder)
|
||||||
|
decoder.read_string
|
||||||
|
end
|
||||||
|
|
||||||
|
{% for size in [8, 16, 32, 64] %}
|
||||||
|
|
||||||
|
def Int{{size.id}}.new(decoder : CBOR::Decoder)
|
||||||
|
decoder.read_int.to_i{{size.id}}
|
||||||
|
end
|
||||||
|
|
||||||
|
def UInt{{size.id}}.new(decoder : CBOR::Decoder)
|
||||||
|
decoder.read_int.to_u{{size.id}}
|
||||||
|
end
|
||||||
|
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
def Slice.new(decoder : CBOR::Decoder)
|
||||||
|
decoder.read_bytes.to_slice
|
||||||
|
end
|
|
@ -1,10 +1,6 @@
|
||||||
class CBOR::Lexer
|
class CBOR::Lexer
|
||||||
BREAK = 0xff
|
BREAK = 0xff
|
||||||
|
|
||||||
def self.new(string : String)
|
|
||||||
new IO::Memory.new(string)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.new(slice : Bytes)
|
def self.new(slice : Bytes)
|
||||||
new IO::Memory.new(slice)
|
new IO::Memory.new(slice)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue