From f08ca5cdead2fcc63ae7526b65df1f9a993a504b Mon Sep 17 00:00:00 2001 From: hhaensel Date: Fri, 15 Nov 2024 00:55:57 +0100 Subject: [PATCH 1/3] support user functions for Inf and NaN --- src/write.jl | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/write.jl b/src/write.jl index bfff8a1..9924520 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) + 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) From 8b966f410ba670ea4aa16e7afbb8095661b9bc5e Mon Sep 17 00:00:00 2001 From: hhaensel Date: Fri, 15 Nov 2024 08:18:02 +0100 Subject: [PATCH 2/3] fix return for isnan --- src/write.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/write.jl b/src/write.jl index 9924520..37d9803 100644 --- a/src/write.jl +++ b/src/write.jl @@ -291,7 +291,7 @@ end end end if isnan(x) - write(RawType(), buf, pos, len, Val(NaN)) + return write(RawType(), buf, pos, len, Val(NaN)) end @check Ryu.neededdigits(T) pos = Ryu.writeshortest(buf, pos, x) From e37168a8ed9bedc7f6bbe7ad86f5576e3a68eca6 Mon Sep 17 00:00:00 2001 From: hhaensel Date: Sat, 16 Nov 2024 00:13:28 +0100 Subject: [PATCH 3/3] add tests for user-defined Inf and NaN conversion --- test/json.jl | 13 +++++++++++++ 1 file changed, 13 insertions(+) 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