From 55e2dff4830a24d66126ad229d9e58cd2a003dd3 Mon Sep 17 00:00:00 2001 From: Jacob Quinn Date: Mon, 6 Oct 2025 19:06:25 -0600 Subject: [PATCH] Add check for positive float precision for non-shortest float_style --- docs/src/writing.md | 2 ++ src/write.jl | 7 ++++++- test/json.jl | 7 ++++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/src/writing.md b/docs/src/writing.md index 18a980e6..65925fa0 100644 --- a/docs/src/writing.md +++ b/docs/src/writing.md @@ -171,6 +171,8 @@ JSON.json(pi_value; float_style=:exp, float_precision=3) # [3.142e+00] ``` +`float_precision` must be a positive integer when `float_style` is `:fixed` or `:exp`. + ### JSON Lines Format The JSON Lines format is useful for streaming records where each line is a JSON value: diff --git a/src/write.jl b/src/write.jl index ef99f052..7a5c9c15 100644 --- a/src/write.jl +++ b/src/write.jl @@ -393,6 +393,9 @@ end @noinline float_style_throw(fs) = throw(ArgumentError("Invalid float style: $fs")) float_style_check(fs) = fs == :shortest || fs == :fixed || fs == :exp || float_style_throw(fs) +@noinline float_precision_throw(fs, fp) = throw(ArgumentError("float_precision must be positive when float_style is $fs; got $fp")) +float_precision_check(fs, fp) = (fs == :shortest || fp > 0) || float_precision_throw(fs, fp) + # if jsonlines and pretty is not 0 or false, throw an ArgumentError @noinline _jsonlines_pretty_throw() = throw(ArgumentError("pretty printing is not supported when writing jsonlines")) _jsonlines_pretty_check(jsonlines, pretty) = jsonlines && pretty !== false && !iszero(pretty) && _jsonlines_pretty_throw() @@ -401,6 +404,7 @@ function json(io::IO, x::T; pretty::Union{Integer,Bool}=false, kw...) where {T} opts = WriteOptions(; pretty=pretty === true ? 2 : Int(pretty), kw...) _jsonlines_pretty_check(opts.jsonlines, opts.pretty) float_style_check(opts.float_style) + float_precision_check(opts.float_style, opts.float_precision) y = StructUtils.lower(opts.style, x) # Use smaller initial buffer size, limited by bufsize initial_size = min(sizeguess(y), opts.bufsize) @@ -423,6 +427,7 @@ function json(x; pretty::Union{Integer,Bool}=false, kw...) opts = WriteOptions(; pretty=pretty === true ? 2 : Int(pretty), kw...) _jsonlines_pretty_check(opts.jsonlines, opts.pretty) float_style_check(opts.float_style) + float_precision_check(opts.float_style, opts.float_precision) y = StructUtils.lower(opts.style, x) buf = stringvec(sizeguess(y)) pos = json!(buf, 1, y, opts, Any[y], nothing) @@ -762,4 +767,4 @@ function anyinvalidnumberchars(x) end end return false -end \ No newline at end of file +end diff --git a/test/json.jl b/test/json.jl index 47077998..2564ff83 100644 --- a/test/json.jl +++ b/test/json.jl @@ -258,6 +258,11 @@ end # float_style and float_precision @test JSON.json(Float64(π); float_style=:fixed, float_precision=2) == "3.14" @test JSON.json(Float64(π); float_style=:exp, float_precision=2) == "3.14e+00" + @test_throws ArgumentError JSON.json(Float64(π); float_style=:fixed, float_precision=0) + @test_throws ArgumentError JSON.json(Float64(π); float_style=:fixed, float_precision=-1) + @test_throws ArgumentError JSON.json(Float64(π); float_style=:exp, float_precision=0) + io = IOBuffer() + @test_throws ArgumentError JSON.json(io, Float64(π); float_style=:fixed, float_precision=0) @test_throws ArgumentError JSON.json(Float64(π); float_style=:not_a_style) end @@ -585,4 +590,4 @@ end end end -end # @testset "JSON.json" \ No newline at end of file +end # @testset "JSON.json"