diff --git a/src/write.jl b/src/write.jl index bfff8a1..37d9803 100644 --- a/src/write.jl +++ b/src/write.jl @@ -284,17 +284,32 @@ end if isinf(x) # Although this is non-standard JSON, "Infinity" is commonly used. # See https://docs.python.org/3/library/json.html#infinite-and-nan-number-values. - if sign(x) == -1 - @writechar '-' + return if sign(x) == 1 + write(RawType(), buf, pos, len, Val(Inf)) + else + write(RawType(), buf, pos, len, Val(-Inf)) end - @writechar 'I' 'n' 'f' 'i' 'n' 'i' 't' 'y' - return buf, pos, len + end + if isnan(x) + return write(RawType(), buf, pos, len, Val(NaN)) end @check Ryu.neededdigits(T) pos = Ryu.writeshortest(buf, pos, x) return buf, pos, len end +function rawbytes(::Val{T}) where T + codeunits( + if T === Inf + "Infinity" + elseif T === -Inf + "-Infinity" + else + "NaN" + end + ) +end + const NEEDESCAPE = Set(map(UInt8, ('"', '\\', '\b', '\f', '\n', '\r', '\t'))) function escapechar(b) diff --git a/test/json.jl b/test/json.jl index 98b1e2c..c42c56c 100644 --- a/test/json.jl +++ b/test/json.jl @@ -46,6 +46,19 @@ end @test JSON3.read("Inf"; allow_inf=true) === Inf @test JSON3.read("Infinity"; allow_inf=true) === Inf @test JSON3.read("-Infinity"; allow_inf=true) === -Inf + + JSON3.rawbytes(::Val{Inf}) = codeunits("1e1000") + JSON3.rawbytes(::Val{-Inf}) = codeunits("__-inf__") + JSON3.rawbytes(::Val{NaN}) = codeunits("__nan__") + + @test JSON3.write([Inf], allow_inf=true) == "[1e1000]" + @test JSON3.write([-Inf], allow_inf=true) == "[__-inf__]" + @test JSON3.write([NaN], allow_inf=true) == "[__nan__]" + + # delete the methods to avoid affecting other tests + Base.delete_method.(methods(JSON3.rawbytes, (Val{Inf},))) + Base.delete_method.(methods(JSON3.rawbytes, (Val{-Inf},))) + Base.delete_method.(methods(JSON3.rawbytes, (Val{NaN},))) end @testset "Char" begin