# Defines a byte format to encode integers and floats # from/to `Bytes` and `IO`. # # ### Decode from bytes # # ``` # bytes = Bytes[0x34, 0x12] # int16 = IO::ByteFormat::LittleEndian.decode(Int16, bytes) # int16 # => 0x1234_i16 # ``` # # ### Decode from an IO # # ``` # io = IO::Memory.new(Bytes[0x34, 0x12]) # int16 = io.read_bytes(Int16, IO::ByteFormat::LittleEndian) # int16 # => 0x1234_i16 # ``` # # ### Encode to bytes # # ``` # raw = uninitialized UInt8[2] # IO::ByteFormat::LittleEndian.encode(0x1234_i16, raw.to_slice) # raw # => StaticArray[0x34, 0x12] # ``` # # ### Encode to IO # # ``` # io = IO::Memory.new # io.write_bytes(0x1234_i16, IO::ByteFormat::LittleEndian) # io.to_slice # => Bytes[0x34, 0x12] # ``` module IO::ByteFormat abstract def encode(int : Int8, io : IO) abstract def encode(int : UInt8, io : IO) abstract def encode(int : Int16, io : IO) abstract def encode(int : UInt16, io : IO) abstract def encode(int : Int32, io : IO) abstract def encode(int : UInt32, io : IO) abstract def encode(int : Int64, io : IO) abstract def encode(int : UInt64, io : IO) abstract def encode(int : Int128, io : IO) abstract def encode(int : UInt128, io : IO) abstract def encode(int : Int8, bytes : Bytes) abstract def encode(int : UInt8, bytes : Bytes) abstract def encode(int : Int16, bytes : Bytes) abstract def encode(int : UInt16, bytes : Bytes) abstract def encode(int : Int32, bytes : Bytes) abstract def encode(int : UInt32, bytes : Bytes) abstract def encode(int : Int64, bytes : Bytes) abstract def encode(int : UInt64, bytes : Bytes) abstract def encode(int : Int128, bytes : Bytes) abstract def encode(int : UInt128, bytes : Bytes) abstract def decode(int : Int8.class, io : IO) abstract def decode(int : UInt8.class, io : IO) abstract def decode(int : Int16.class, io : IO) abstract def decode(int : UInt16.class, io : IO) abstract def decode(int : Int32.class, io : IO) abstract def decode(int : UInt32.class, io : IO) abstract def decode(int : Int64.class, io : IO) abstract def decode(int : UInt64.class, io : IO) abstract def decode(int : Int128.class, io : IO) abstract def decode(int : UInt128.class, io : IO) abstract def decode(int : Int8.class, bytes : Bytes) abstract def decode(int : UInt8.class, bytes : Bytes) abstract def decode(int : Int16.class, bytes : Bytes) abstract def decode(int : UInt16.class, bytes : Bytes) abstract def decode(int : Int32.class, bytes : Bytes) abstract def decode(int : UInt32.class, bytes : Bytes) abstract def decode(int : Int64.class, bytes : Bytes) abstract def decode(int : UInt64.class, bytes : Bytes) abstract def decode(int : Int128.class, bytes : Bytes) abstract def decode(int : UInt128.class, bytes : Bytes) def encode(float : Float32, io : IO) : Nil encode(float.unsafe_as(Int32), io) end def encode(float : Float32, bytes : Bytes) encode(float.unsafe_as(Int32), bytes) end def decode(type : Float32.class, io : IO) : Float32 decode(Int32, io).unsafe_as(Float32) end def decode(type : Float32.class, bytes : Bytes) : Float32 decode(Int32, bytes).unsafe_as(Float32) end def encode(float : Float64, io : IO) : Nil encode(float.unsafe_as(Int64), io) end def encode(float : Float64, bytes : Bytes) encode(float.unsafe_as(Int64), bytes) end def decode(type : Float64.class, io : IO) : Float64 decode(Int64, io).unsafe_as(Float64) end def decode(type : Float64.class, bytes : Bytes) : Float64 decode(Int64, bytes).unsafe_as(Float64) end module LittleEndian extend ByteFormat end module BigEndian extend ByteFormat end alias SystemEndian = LittleEndian alias NetworkEndian = BigEndian {% for mod in %w(LittleEndian BigEndian) %} module {{mod.id}} {% for type, i in %w(Int8 UInt8 Int16 UInt16 Int32 UInt32 Int64 UInt64 Int128 UInt128) %} {% bytesize = 2 ** (i // 2) %} def self.encode(int : {{type.id}}, io : IO) buffer = int.unsafe_as(StaticArray(UInt8, {{bytesize}})) buffer.reverse! unless SystemEndian == self io.write(buffer.to_slice) end def self.encode(int : {{type.id}}, bytes : Bytes) buffer = int.unsafe_as(StaticArray(UInt8, {{bytesize}})) buffer.reverse! unless SystemEndian == self buffer.to_slice.copy_to(bytes) end def self.decode(int : {{type.id}}.class, io : IO) buffer = uninitialized UInt8[{{bytesize}}] io.read_fully(buffer.to_slice) buffer.reverse! unless SystemEndian == self buffer.unsafe_as({{type.id}}) end def self.decode(int : {{type.id}}.class, bytes : Bytes) buffer = uninitialized UInt8[{{bytesize}}] bytes.copy_to(buffer.to_unsafe, {{bytesize}}) buffer.reverse! unless SystemEndian == self buffer.unsafe_as({{type.id}}) end @[Deprecated("Use `.decode(int : {{type.id}}.class, io : IO)` instead")] def self.decode(*, type : {{type.id}}.class, io : IO) decode(type, io) end @[Deprecated("Use `.decode(int : {{type.id}}.class, bytes : Bytes)` instead")] def self.decode(*, type : {{type.id}}.class, bytes : Bytes) decode(type, bytes) end {% end %} end {% end %} end