From b88f88ac623e05e2dc456dadf8bdb6398baf6165 Mon Sep 17 00:00:00 2001 From: Avik Sengupta Date: Tue, 8 Aug 2017 18:38:35 -0400 Subject: [PATCH 1/2] Make this work on 0.6, drop support for 0.5 --- README.md | 7 ++++++ REQUIRE | 3 +-- doc/index.rst | 18 +++++++-------- src/StrPack.jl | 60 ++++++++++++++++++++++++------------------------ test/runtests.jl | 20 ++++++++-------- 5 files changed, 57 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index 64c833f..5fd9288 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,13 @@ Documentation ============= More complete documentation can be found on [Read The Docs](https://strpackjl.readthedocs.org/en/latest/). +Incompatible change in 0.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. + WARNING ======= diff --git a/REQUIRE b/REQUIRE index 010312c..137767a 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,2 +1 @@ -julia 0.5 -Compat 0.4.5 +julia 0.6 diff --git a/doc/index.rst b/doc/index.rst index 4817e13..3be8161 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -18,7 +18,7 @@ Let's create a C library as follows: int int1; float float1; }; - + void getvalues(struct teststruct* ts) { ts->int1 = 7; @@ -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 @@ -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:: @@ -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 @@ -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 diff --git a/src/StrPack.jl b/src/StrPack.jl index 38b26b5..62ae6c7 100644 --- a/src/StrPack.jl +++ b/src/StrPack.jl @@ -1,6 +1,7 @@ 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 @@ -8,7 +9,6 @@ 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 @@ -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])) @@ -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()))) @@ -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) @@ -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 @@ -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 @@ -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))) @@ -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 @@ -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) @@ -274,12 +274,12 @@ 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, ) @@ -287,7 +287,7 @@ align_packmax(da::DataAlign, n::Integer) = DataAlign( align_structpack(da::DataAlign, n::Integer) = DataAlign( da.ttable, da.default, - _ -> n, + x -> n, ) # provide an alignment table @@ -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, @@ -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) @@ -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], diff --git a/test/runtests.jl b/test/runtests.jl index 2a304b2..a815815 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -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 From f6eb64d886c96c823f339d7d92fc8fc71a603610 Mon Sep 17 00:00:00 2001 From: Avik Sengupta Date: Wed, 9 Aug 2017 10:53:18 -0400 Subject: [PATCH 2/2] improve readme --- README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5fd9288..8a9416b 100644 --- a/README.md +++ b/README.md @@ -11,15 +11,21 @@ Documentation ============= More complete documentation can be found on [Read The Docs](https://strpackjl.readthedocs.org/en/latest/). -Incompatible change in 0.6 -========================== +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 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.