diff --git a/.travis.yml b/.travis.yml index 494c47d..dfd9cd2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,10 @@ +before_install: + - cd ../.. + - mv $TRAVIS_REPO_SLUG _old + - git config --global core.autocrlf false + - git clone --depth=50 _old $TRAVIS_REPO_SLUG + - cd $TRAVIS_REPO_SLUG + language: julia sudo: false @@ -5,16 +12,24 @@ sudo: false os: - linux - osx + - windows + +arch: + - x64 + - x86 julia: - 1.0 - - 1.1 + - 1.3 - nightly env: - JULIA_PROJECT="@." matrix: + exclude: + - os: osx + arch: x86 allow_failures: - julia: nightly @@ -22,4 +37,4 @@ notifications: email: false after_success: - - julia -e 'ENV["TRAVIS_JULIA_VERSION"] != "1.1" && ENV["TRAVIS_OS_NAME"] != "linux" && exit(); using Pkg; Pkg.add("Coverage"); using Coverage; Codecov.submit(Codecov.process_folder())' + - julia -e 'ENV["TRAVIS_JULIA_VERSION"] == "1.3" && ENV["TRAVIS_OS_NAME"] != "linux" && exit(); using Pkg; Pkg.add("Coverage"); using Coverage; Codecov.submit(Codecov.process_folder())' diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index b8d7de3..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,36 +0,0 @@ -environment: - matrix: - - julia_version: 1.0 - - julia_version: nightly - -platform: - - x86 # 32-bit - - x64 # 64-bit - -## uncomment the following lines to allow failures on nightly julia -## (tests will run but not make your overall status red) -matrix: - allow_failures: - - julia_version: nightly - -branches: - only: - - master - - /release-.*/ - -notifications: - - provider: Email - on_build_success: false - on_build_failure: false - on_build_status_changed: false - -install: - - ps: iex ((new-object net.webclient).DownloadString("https://raw.githubusercontent.com/JuliaCI/Appveyor.jl/version-1/bin/install.ps1")) - -build_script: - - echo "%JL_BUILD_SCRIPT%" - - C:\julia\bin\julia -e "%JL_BUILD_SCRIPT%" - -test_script: - - echo "%JL_TEST_SCRIPT%" - - C:\julia\bin\julia -e "%JL_TEST_SCRIPT%" \ No newline at end of file diff --git a/src/JSON3.jl b/src/JSON3.jl index 9988e0c..028244c 100644 --- a/src/JSON3.jl +++ b/src/JSON3.jl @@ -26,7 +26,7 @@ invalid JSON at byte position $pos while parsing type $T: $error $(String(buf[max(1, pos-25):min(end, pos+25)])) """)) -@enum Error UnexpectedEOF ExpectedOpeningObjectChar ExpectedOpeningQuoteChar ExpectedOpeningArrayChar ExpectedComma ExpectedSemiColon InvalidChar +@enum Error UnexpectedEOF ExpectedOpeningObjectChar ExpectedOpeningQuoteChar ExpectedOpeningArrayChar ExpectedClosingArrayChar ExpectedComma ExpectedSemiColon InvalidChar # AbstractDict interface function Base.length(obj::Object) diff --git a/src/structs.jl b/src/structs.jl index af0c798..b45e188 100644 --- a/src/structs.jl +++ b/src/structs.jl @@ -468,8 +468,10 @@ StructType(::Type{<:Tuple}) = ArrayType() construct(T, x::Vector{S}) where {S} = T(x) @inline read(::ArrayType, buf, pos, len, b, ::Type{T}) where {T} = read(ArrayType(), buf, pos, len, b, T, Base.IteratorEltype(T) == Base.HasEltype() ? eltype(T) : Any) +@inline read(::ArrayType, buf, pos, len, b, ::Type{T}, ::Type{eT}) where {T, eT} = readarray(buf, pos, len, b, T, eT) +read(::ArrayType, buf, pos, len, b, ::Type{Tuple}, ::Type{eT}) where {eT} = readarray(buf, pos, len, b, Tuple, eT) -@inline function read(::ArrayType, buf, pos, len, b, ::Type{T}, ::Type{eT}) where {T, eT} +@inline function readarray(buf, pos, len, b, ::Type{T}, ::Type{eT}) where {T, eT} if b != UInt8('[') error = ExpectedOpeningArrayChar @goto invalid @@ -480,7 +482,7 @@ construct(T, x::Vector{S}) where {S} = T(x) @wh vals = Vector{eT}(undef, 0) if b == UInt8(']') - return pos + 1, T(vals) + return pos + 1, construct(T, vals) end while true # positioned at start of value @@ -505,6 +507,70 @@ construct(T, x::Vector{S}) where {S} = T(x) invalid(error, buf, pos, T) end +@inline function read(::ArrayType, buf, pos, len, b, ::Type{T}, ::Type{eT}) where {T <: Tuple, eT} + if b != UInt8('[') + error = ExpectedOpeningArrayChar + @goto invalid + end + pos += 1 + @eof + b = getbyte(buf, pos) + @wh + if b == UInt8(']') + pos += 1 + return pos, T() + end + N = fieldcount(T) + Base.@nexprs 32 i -> begin + # positioned at start of value + eT_i = fieldtype(T, i) + pos, x_i = read(StructType(eT_i), buf, pos, len, b, eT_i) + @eof + b = getbyte(buf, pos) + @wh + if N == i + if b == UInt8(']') + return pos, Base.@ncall i tuple x + else + error = ExpectedClosingArrayChar + @goto invalid + end + elseif b != UInt8(',') + error = ExpectedComma + @goto invalid + end + pos += 1 + @eof + b = getbyte(buf, pos) + @wh + end + vals = [] + for i = 33:N + eT_i = fieldtype(T, i) + pos, y = read(StructType(eT_i), buf, pos, len, b, eT_i) + push!(vals, y) + @eof + b = getbyte(buf, pos) + @wh + if b == UInt8(']') + pos += 1 + break + elseif b != UInt8(',') + error = ExpectedComma + @goto invalid + end + pos += 1 + @eof + b = getbyte(buf, pos) + @wh + end + return pos, (x_1, x_2, x_3, x_4, x_5, x_6, x_7, x_8, x_9, x_10, x_11, x_12, x_13, x_14, x_15, x_16, + x_17, x_18, x_19, x_20, x_21, x_22, x_23, x_24, x_25, x_26, x_27, x_28, x_29, x_30, x_31, x_32, vals...) + +@label invalid + invalid(error, buf, pos, T) +end + StructType(::Type{<:AbstractDict}) = ObjectType() StructType(::Type{<:NamedTuple}) = ObjectType() StructType(::Type{<:Pair}) = ObjectType() @@ -741,8 +807,8 @@ end pos, y = readvalue(buf, pos, len, fieldtype(T, i)) push!(vals, y) end - return pos, T(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, - x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31, x32, vals...) + return pos, T(x_1, x_2, x_3, x_4, x_5, x_6, x_7, x_8, x_9, x_10, x_11, x_12, x_13, x_14, x_15, x_16, + x_17, x_18, x_19, x_20, x_21, x_22, x_23, x_24, x_25, x_26, x_27, x_28, x_29, x_30, x_31, x_32, vals...) @label invalid invalid(error, buf, pos, T) diff --git a/test/runtests.jl b/test/runtests.jl index 5d5612d..f0fcd4a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -58,6 +58,44 @@ struct AndFunction <: BinaryFunction rhs::Expression end +struct LotsOfFields + x1::String + x2::String + x3::String + x4::String + x5::String + x6::String + x7::String + x8::String + x9::String + x10::String + x11::String + x12::String + x13::String + x14::String + x15::String + x16::String + x17::String + x18::String + x19::String + x20::String + x21::String + x22::String + x23::String + x24::String + x25::String + x26::String + x27::String + x28::String + x29::String + x30::String + x31::String + x32::String + x33::String + x34::String + x35::String +end + @testset "JSON3" begin @testset "read.jl" begin @@ -489,6 +527,12 @@ expr = JSON3.read(""" @test JSON3.write(B) == "\"B\"" @test JSON3.write(Vehicle) == "\"Vehicle\"" +JSON3.StructType(::Type{LotsOfFields}) = JSON3.Struct() +lotsoffields = LotsOfFields(fill("hey", 35)...) +jlots = JSON3.write(lotsoffields) +@test jlots == "{\"x1\":\"hey\",\"x2\":\"hey\",\"x3\":\"hey\",\"x4\":\"hey\",\"x5\":\"hey\",\"x6\":\"hey\",\"x7\":\"hey\",\"x8\":\"hey\",\"x9\":\"hey\",\"x10\":\"hey\",\"x11\":\"hey\",\"x12\":\"hey\",\"x13\":\"hey\",\"x14\":\"hey\",\"x15\":\"hey\",\"x16\":\"hey\",\"x17\":\"hey\",\"x18\":\"hey\",\"x19\":\"hey\",\"x20\":\"hey\",\"x21\":\"hey\",\"x22\":\"hey\",\"x23\":\"hey\",\"x24\":\"hey\",\"x25\":\"hey\",\"x26\":\"hey\",\"x27\":\"hey\",\"x28\":\"hey\",\"x29\":\"hey\",\"x30\":\"hey\",\"x31\":\"hey\",\"x32\":\"hey\",\"x33\":\"hey\",\"x34\":\"hey\",\"x35\":\"hey\"}" +@test JSON3.read(jlots, LotsOfFields) == lotsoffields + end # @testset "structs.jl" @testset "show.jl" begin @@ -587,4 +631,9 @@ obj = JSON3.read("{\"hey\":1}") obj = JSON3.read("{\"a\":\"b\", \"b\":null, \"c\":[null,null]}") @test copy(obj) == Dict(:a => "b", :b => nothing, :c => [nothing, nothing]) +# better Tuple reading support +@test JSON3.read("[\"car\",\"Mercedes\"]", Tuple{Symbol, String}) == (:car, "Mercedes") +@test JSON3.read("[\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\",\"hey\"]", NTuple{35, String}) == + ("hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey", "hey") + end # @testset "JSON3"