Skip to content

Commit

Permalink
Merge pull request #12 from Keno/sf/increased_coverage
Browse files Browse the repository at this point in the history
Increase coverage
  • Loading branch information
staticfloat authored Oct 13, 2017
2 parents 8b4aa96 + e6626d1 commit e36dc82
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 18 deletions.
35 changes: 18 additions & 17 deletions src/StructIO.jl
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ Unpack an object of type `T` from `io` into `target`, byte-swapping if
packed structs recurse until bitstypes objects are eventually reached, at which
point `Default` packing is the only behavior.
"""
function unsafe_unpack(io, T, target, endianness, ::Type{Default})
function unsafe_unpack(io, ::Type{T}, target, endianness, ::Type{Default}) where {T}
sz = Core.sizeof(T)

if !needs_bswap(endianness)
Expand All @@ -160,18 +160,19 @@ function unsafe_unpack(io, T, target, endianness, ::Type{Default})
# Special case small sizes, LLVM should turn this into a jump table
if sz == 1
elseif sz == 2
ptr = Base.unsafe_convert(Ptr{UInt16}, target)
ptr = Base.unsafe_convert(Ptr{T}, target)
unsafe_store!(ptr, bswap(unsafe_load(ptr)))
elseif sz == 4
ptr = Base.unsafe_convert(Ptr{UInt32}, target)
ptr = Base.unsafe_convert(Ptr{T}, target)
unsafe_store!(ptr, bswap(unsafe_load(ptr)))
elseif sz == 8
ptr = Base.unsafe_convert(Ptr{UInt64}, target)
ptr = Base.unsafe_convert(Ptr{T}, target)
unsafe_store!(ptr, bswap(unsafe_load(ptr)))
else
# Otherwise, for large primitive objects, fall back to our
# `bswap!()` method which will swap in-place
bswap!(Base.unsafe_convert(Ptr{UInt8}, target), sz)
void_ptr = Base.unsafe_convert(Ptr{Void}, target)
bswap!(Base.unsafe_convert(Ptr{UInt8}, void_ptr), sz)
end
else
# If we need to bswap, but it's not a primitive type, recurse!
Expand All @@ -198,32 +199,32 @@ last argument is a packing strategy, used to determine the layout of the data
in memory. All `Packed` objects recurse until bitstypes objects are eventually
reached, at which point `Default` packing is identical to `Packed` behavior.
"""
function unsafe_pack{T}(io, source::Ref{T}, endianness, ::Type{Default})
function unsafe_pack(io, source::Ref{T}, endianness, ::Type{Default}) where {T}
sz = packed_sizeof(T)
if !needs_bswap(endianness)
# If we don't need to bswap, just write directly from `source`
unsafe_write(io, source, sz)
elseif @compat fieldcount(T) == 0
# Hopefully, LLVM turns this into a jump list for us
if sz == 1
unsafe_write(io, source[])
write(io, source[])
elseif sz == 2
ptr = Base.unsafe_convert(Ptr{UInt16}, source)
unsafe_write(io, bswap(unsafe_load(ptr)), sz)
ptr = Base.unsafe_convert(Ptr{T}, source)
write(io, bswap(unsafe_load(ptr)))
elseif sz == 4
ptr = Base.unsafe_convert(Ptr{UInt32}, source)
unsafe_write(io, bswap(unsafe_load(ptr)), sz)
ptr = Base.unsafe_convert(Ptr{T}, source)
write(io, bswap(unsafe_load(ptr)))
elseif sz == 8
ptr = Base.unsafe_convert(Ptr{UInt64}, source)
unsafe_write(io, bswap(unsafe_load(ptr)), sz)
ptr = Base.unsafe_convert(Ptr{T}, source)
write(io, bswap(unsafe_load(ptr)))
else
# If we must bswap something of unknown size, copy first so as
# to not clobber `source`, then bswap, then write
ptr = Base.unsafe_convert(Ptr{UInt8}, copy(source))
void_ptr = Base.unsafe_convert(Ptr{Void}, Ref{T}(copy(source[])))
ptr = Base.unsafe_convert(Ptr{UInt8}, void_ptr)
bswap!(ptr, sz)
unsafe_write(io, ptr, sz)
end
@show position(io), T, sz
else
# If we need to bswap, but it's not a primitive type, recurse!
for i = 1:@compat fieldcount(T)
Expand Down Expand Up @@ -253,7 +254,7 @@ function unsafe_unpack(io, T, target, endianness, ::Type{Packed})
end

# `Packed` packing strategy override for `unsafe_pack`
function unsafe_pack{T}(io, source::Ref{T}, endianness, ::Type{Packed})
function unsafe_pack(io, source::Ref{T}, endianness, ::Type{Packed}) where {T}
# If this type cannot be subdivided, packing strategy means nothing, so
# hand it off to the `Default` packing strategy method
if @compat fieldcount(T) == 0
Expand Down Expand Up @@ -297,7 +298,7 @@ no byteswapping will occur. If `endianness` is `:LittleEndian` or
`:BigEndian`, byteswapping will occur if the endianness of the host system
does not match the endianness of `io`.
"""
function pack{T}(io::IO, source::T, endianness::Symbol = :NativeEndian)
function pack(io::IO, source::T, endianness::Symbol = :NativeEndian) where {T}
r = Ref{T}(source)
packstrat = @compat fieldcount(T) == 0 ? Default : packing_strategy(T)
unsafe_pack(io, r, endianness, packstrat)
Expand Down
19 changes: 18 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,30 @@ end
end

@testset "pack()" begin
# Pack simple types
for endian in [:BigEndian, :LittleEndian]
buf = IOBuffer()
pack(buf, UInt8(1), endian)
pack(buf, Int16(2), endian)
pack(buf, UInt32(4), endian)
pack(buf, Int64(8), endian)
pack(buf, UInt128(16), endian)
@test position(buf) == 1 + 2 + 4 + 8 + 16
seekstart(buf)
@test unpack(buf, UInt8, endian) === UInt8(1)
@test unpack(buf, Int16, endian) === Int16(2)
@test unpack(buf, UInt32, endian) === UInt32(4)
@test unpack(buf, Int64, endian) === Int64(8)
@test unpack(buf, UInt128, endian) === UInt128(16)
end

# Pack a simple object
buf = IOBuffer()
tu = TwoUInts(2, 3)
pack(buf, tu)

# Test that the stream looks reasonable
@test position(buf) == Core.sizeof(TwoUInts)
@test position(buf) == sizeof(TwoUInts)
seekstart(buf)
@test read(buf, UInt) == 2
@test read(buf, UInt) == 3
Expand Down

0 comments on commit e36dc82

Please sign in to comment.