Skip to content

Commit

Permalink
Merge pull request #31 from pao/as/break
Browse files Browse the repository at this point in the history
Make this work on 0.6, drop support for 0.5
  • Loading branch information
aviks authored Oct 25, 2017
2 parents 23fdc57 + f6eb64d commit 6b8e65a
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 52 deletions.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,21 @@ Documentation
=============
More complete documentation can be found on [Read The Docs](https://strpackjl.readthedocs.org/en/latest/).

Incompatible change for Julia v0.6
==================================

Note that the primary artifact of this package was the `@struct` macro. In Julia `v0.6`, `struct` is now a reserved word.
This necessitates a change, hence the macro is now called `@str`. This change has been made since `v0.2.0` of this package.
This means that any code that uses this package MUST be changed when running on Julia v0.6.

This will typically require a v0.6-and-above only release of any package that is a dependency of this package. If you must
support both Julia v0.5 and v0.6 in the same version, you'll have to have version-dependent code in your package; I would
not recommend doing that.

Users on Julia `v0.5` can continue to use `v0.1.0` of this package without issues.

WARNING
=======

This package is only semi-maintained. While it has been updated to work without warnings on Julia 0.5,
This package is only semi-maintained. While it has been updated to work without warnings on Julia 0.6,
there are no guarantees of correctness beyond the existing package tests. Use at your own risk.
3 changes: 1 addition & 2 deletions REQUIRE
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
julia 0.5
Compat 0.4.5
julia 0.6
18 changes: 9 additions & 9 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Let's create a C library as follows:
int int1;
float float1;
};
void getvalues(struct teststruct* ts)
{
ts->int1 = 7;
Expand All @@ -32,7 +32,7 @@ Let's also create the Julia analog of this structure::

using StrPack

@struct type TestStruct
@str type TestStruct
int1::Int32
float1::Float32
end
Expand All @@ -44,7 +44,7 @@ Let's also create the Julia analog of this structure::
Note that C's ``int`` corresponds to ``Int32``. Let's initialize an object of this type::

s = TestStruct(-1, 1.2)

We can pack ``s`` into a form suitable to pass as the input to our C function ``getvalues``, which we do in the
following way::

Expand Down Expand Up @@ -78,11 +78,11 @@ Voila! You have the result back.
Macros
------

.. function:: @struct(type, strategy, endianness)
.. function:: @str(type, strategy, endianness)

Create and register a structural Julia type with StrPack. The type argument uses an extended form of the standard Julia type syntax to define the size of arrays and strings. Each element must declare its type, and each type must be reducible to a bits type or array or composite of bits types.::

@struct type StructuralType
@str type StructuralType
a::Float64 # a bits type
b::Array{Int32,2}(4, 4) # an array of bits types
c::ASCIIString(8) # a string with a fixed number of bytes
Expand All @@ -94,16 +94,16 @@ Methods

.. function:: pack(io, composite[, asize, strategy, endianness])

Create a packed buffer representation of ``composite`` in stream ``io``, using array and string sizes fixed by ``asize`` and data alignment coded by ``strategy`` with endianness ``endianness``. If the optional arguments are not provided, then ``T``, the type of ``composite``, is expected to have been created with the ``@struct`` macro.
Create a packed buffer representation of ``composite`` in stream ``io``, using array and string sizes fixed by ``asize`` and data alignment coded by ``strategy`` with endianness ``endianness``. If the optional arguments are not provided, then ``T``, the type of ``composite``, is expected to have been created with the ``@str`` macro.

.. function:: unpack(io, T[, asize, strategy, endianness])

Extract an instance of the Julia composite type ``T`` from the packed representation in the stream ``io``.
If the optional arguments are not provided, then ``T`` is expected to have been created with the ``@struct`` macro.
If the optional arguments are not provided, then ``T`` is expected to have been created with the ``@str`` macro.

.. function:: show_struct_layout(T[, asize, strategy][, width, bytesize])

Print a graphical representation of the memory layout of the packed type ``T``. If ``asize`` and ``strategy`` are not provided, then ``T`` is expected to have been created with the ``@struct`` macro. The display will show ``width`` bytes in each row, with each byte taking up ``bytesize`` characters.
Print a graphical representation of the memory layout of the packed type ``T``. If ``asize`` and ``strategy`` are not provided, then ``T`` is expected to have been created with the ``@str`` macro. The display will show ``width`` bytes in each row, with each byte taking up ``bytesize`` characters.

----------
Endianness
Expand Down
60 changes: 30 additions & 30 deletions src/StrPack.jl
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
module StrPack

export @struct
Base.warn_once("Using v0.2.0 of StrPack, which is incompatible with previous versions")
export @str
export pack, unpack, sizeof
export DataAlign
export align_default, align_packed, align_packmax, align_structpack, align_table
export align_x86_pc_linux_gnu, align_native
export show_struct_layout

using Base.Meta
using Compat

import Base.read, Base.write
import Base.isequal
Expand All @@ -23,18 +23,18 @@ immutable DataAlign
# aggregate::(Vector{Type} -> Integer); used for composite types not in ttable
aggregate::Function
end
DataAlign(def::Function, agg::Function) = DataAlign((@compat Dict{Type,Integer}()), def, agg)
DataAlign(def::Function, agg::Function) = DataAlign((Dict{Type,Integer}()), def, agg)

immutable Struct
immutable Str
asize::Dict
strategy::DataAlign
endianness::Symbol
end

macro struct(xpr...)
macro str(xpr...)
(typname, typ, asize) = extract_annotations(xpr[1])
if length(xpr) > 3
error("too many arguments supplied to @struct")
error("too many arguments supplied to @str")
end
if length(xpr) > 2
if isexpr(xpr[3], :quote) && haskey(endianness_converters, eval(xpr[3]))
Expand All @@ -55,7 +55,7 @@ macro struct(xpr...)
alignment = :(align_default)
endianness = :(:NativeEndian)
end
new_struct = :(Struct($asize, $alignment, $endianness))
new_struct = :(Str($asize, $alignment, $endianness))
quote
$(esc(typ))
$(esc(:(isdefined(:STRUCT_REGISTRY) || const STRUCT_REGISTRY = ObjectIdDict())))
Expand Down Expand Up @@ -97,20 +97,20 @@ function extract_annotations(exprIn)
end
end
else
error("only type definitions can be supplied to @struct")
error("only type definitions can be supplied to @str")
end
asize = :(Dict(zip([$(fieldnames...)], Array{Integer,1}[$(asizes...)])))
(typname, exprIn, asize)
end

endianness_converters = @compat Dict(
endianness_converters = Dict(
:BigEndian => (hton, ntoh),
:LittleEndian => (htol, ltoh),
:NativeEndian => (identity, identity),
:SwappedEndian => (Base.bswap, Base.bswap))

# A byte of padding
bitstype 8 PadByte
primitive type PadByte 8 end
write(s::IO, x::PadByte) = write(s, 0x00)
read(s::IO, ::Type{PadByte}) = read(s, UInt8)

Expand Down Expand Up @@ -163,7 +163,7 @@ function unpack{T}(in::IO, ::Type{T}, asize::Dict, strategy::DataAlign, endianne
prod(dims)
elseif !isempty(fieldnames(intyp))
if typ <: AbstractArray
item = Array(intyp, dims...)
item = Array{intyp}(dims...)
for i in 1:prod(dims)
item[i] = unpack(in, intyp)
end
Expand All @@ -186,16 +186,16 @@ function unpack{T}(in::IO, ::Type{T}, asize::Dict, strategy::DataAlign, endianne
end
function unpack{T}(in::IO, ::Type{T}, endianness::Symbol)
chktype(T)
reg = T.name.module.STRUCT_REGISTRY[T]::Struct
reg = T.name.module.STRUCT_REGISTRY[T]::Str
unpack(in, T, reg.asize, reg.strategy, endianness)
end
function unpack{T}(in::IO, ::Type{T})
chktype(T)
reg = T.name.module.STRUCT_REGISTRY[T]::Struct
reg = T.name.module.STRUCT_REGISTRY[T]::Str
unpack(in, T, reg.asize, reg.strategy, reg.endianness)
end

function pack{T}(out::IO, struct::T, asize::Dict, strategy::DataAlign, endianness::Symbol)
function pack{T}(out::IO, str::T, asize::Dict, strategy::DataAlign, endianness::Symbol)
chktype(T)
tgtendianness = endianness_converters[endianness][1]
offset = 0
Expand All @@ -205,9 +205,9 @@ function pack{T}(out::IO, struct::T, asize::Dict, strategy::DataAlign, endiannes
end
data = if typ <: AbstractString
typ = UInt8
convert(Array{UInt8}, getfield(struct, name))
convert(Array{UInt8}, getfield(str, name))
else
getfield(struct, name)
getfield(str, name)
end

offset += write(out, zeros(UInt8, pad_next(offset, typ, strategy)))
Expand Down Expand Up @@ -238,15 +238,15 @@ end
zeros(x, n) = Base.zeros(x, n)
zeros{T}(x::Type{Ptr{T}}, n) = [x(C_NULL) for i in 1:n]

function pack{T}(out::IO, struct::T, endianness::Symbol)
function pack{T}(out::IO, str::T, endianness::Symbol)
chktype(T)
reg = T.name.module.STRUCT_REGISTRY[T]
pack(out, struct, reg.asize, reg.strategy, endianness)
pack(out, str, reg.asize, reg.strategy, endianness)
end
function pack{T}(out::IO, struct::T)
function pack{T}(out::IO, str::T)
chktype(T)
reg = T.name.module.STRUCT_REGISTRY[T]
pack(out, struct, reg.asize, reg.strategy, reg.endianness)
pack(out, str, reg.asize, reg.strategy, reg.endianness)
end

# Convenience methods when you just want to use strings
Expand All @@ -258,8 +258,8 @@ macro withIOBuffer(iostr, ex)
end
end

pack{T}(struct::T, a::Dict, s::DataAlign, n::Symbol) = @withIOBuffer iostr pack(iostr, a, s, n)
pack{T}(struct::T) = @withIOBuffer iostr pack(iostr, struct)
pack{T}(str::T, a::Dict, s::DataAlign, n::Symbol) = @withIOBuffer iostr pack(iostr, a, s, n)
pack{T}(str::T) = @withIOBuffer iostr pack(iostr, str)

unpack{T}(str::Union{AbstractString, Array{UInt8,1}}, ::Type{T}) = unpack(IOBuffer(str), T)

Expand All @@ -274,20 +274,20 @@ type_alignment_default{T}(::Type{T}) = nextpow2(sizeof(T))
align_default = DataAlign(type_alignment_default, x -> maximum(map(type_alignment_default, x)))

# equivalent to __attribute__ (( __packed__ ))
align_packed = DataAlign(_ -> 1, _ -> 1)
align_packed = DataAlign(x -> 1, x -> 1)

# equivalent to #pragma pack(n)
align_packmax(da::DataAlign, n::Integer) = DataAlign(
da.ttable,
_ -> min(type_alignment_default(_), n),
x -> min(type_alignment_default(x), n),
da.aggregate,
)

# equivalent to __attribute__ (( align(n) ))
align_structpack(da::DataAlign, n::Integer) = DataAlign(
da.ttable,
da.default,
_ -> n,
x -> n,
)

# provide an alignment table
Expand All @@ -304,7 +304,7 @@ end

# Specific architectures
align_x86_pc_linux_gnu = align_table(align_default,
@compat Dict(
Dict(
Int64 => 4,
UInt64 => 4,
Float64 => 4,
Expand Down Expand Up @@ -342,9 +342,9 @@ function calcsize{T}(::Type{T}, asize::Dict, strategy::DataAlign)
size += if isbits(typ)
prod(dims)*sizeof(typ)
elseif !isempty(fieldnames(typ))
prod(dims)*sizeof(Struct(typ))
prod(dims)*sizeof(Str(typ))
else
error("Improper type $typ in struct.")
error("Improper type $typ in str.")
end
end
size += pad_next(size, T, strategy)
Expand Down Expand Up @@ -403,13 +403,13 @@ end

## Native layout ##
align_native = align_table(align_default, let
i8a, i16a, i32a, i64a, f32a, f64a = Array(UInt, 1), Array(UInt, 1), Array(UInt, 1), Array(UInt, 1), Array(UInt, 1), Array(UInt, 1)
i8a, i16a, i32a, i64a, f32a, f64a = Array{UInt}(1), Array{UInt}(1), Array{UInt}(1), Array{UInt}(1), Array{UInt}(1), Array{UInt}(1)

ccall("jl_native_alignment", Void,
(Ptr{UInt}, Ptr{UInt}, Ptr{UInt}, Ptr{UInt}, Ptr{UInt}, Ptr{UInt}),
i8a, i16a, i32a, i64a, f32a, f64a)

@compat Dict(
Dict(
Int8 => i8a[1],
UInt8 => i8a[1],
Int16 => i16a[1],
Expand Down
20 changes: 10 additions & 10 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
using Base.Test
using StrPack

@struct type A
@str type A
a::UInt8
end

@struct type B
@str type B
a::Array{UInt8,2}(2,2)
end

@struct type C
@str type C
a::String(5)
end

@struct type D
@str type D
a::C
end

@struct type E
@str type E
a::Array{C,1}(2)
end

@struct immutable F
@str immutable F
a::Array{Float64,2}(3,2)
end

abstract abstractG
abstract type abstractG; end

@struct type G1 <: abstractG
@str type G1 <: abstractG
a::UInt8
end

@struct immutable G2 <: abstractG
@str immutable G2 <: abstractG
a::UInt8
end

@struct type Hvl_t
@str type Hvl_t
len::Csize_t
p::Ptr{Void}
end
Expand Down

0 comments on commit 6b8e65a

Please sign in to comment.