Start implementing from_cbor decoding

dev
Alberto Restifo 2020-04-23 00:25:11 +02:00
parent 9739c4971b
commit 547e8af2bd
4 changed files with 98 additions and 4 deletions

View File

@ -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

50
src/cbor/decoder.cr Normal file
View File

@ -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

24
src/cbor/from_cbor.cr Normal file
View File

@ -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

View File

@ -1,10 +1,6 @@
class CBOR::Lexer
BREAK = 0xff
def self.new(string : String)
new IO::Memory.new(string)
end
def self.new(slice : Bytes)
new IO::Memory.new(slice)
end