Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions src/JSON.jl
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,67 @@ print(io::IO, obj, indent=nothing) = json(io, obj; pretty=something(indent, 0))
print(a, indent=nothing) = print(stdout, a, indent)
@doc (@doc json) print

"""
JSON.writefile(Vector{UInt8}, x; kw...)::Vector{UInt8}
JSON.writefile(io::IO, x; kw...)
JSON.writefile(filename::AbstractString, x; kw...)

Serialize `x` to JSON format. This function provides the same functionality as [`JSON.json`](@ref)

The first method returns the JSON output as a `Vector{UInt8}`.
The second method writes JSON output to an `IO` object.
The third method writes JSON output to a file specified by `filename` which will
be created if it does not exist yet or overwritten if it does exist.

This function is provided for backward compatibility when upgrading from
older versions of JSON.jl where the `json` function signature differed.
For new code, prefer using [`JSON.json`](@ref) directly.

All methods accept the same keyword arguments as [`JSON.json`](@ref):

- `omit_null`, `omit_empty`, `allownan`, `jsonlines`, `pretty`, `inline_limit`
- `ninf`, `inf`, `nan`, `float_style`, `float_precision`, `bufsize`, `style`

See [`JSON.json`](@ref) for detailed documentation of all keyword arguments and more examples.

# Examples
```julia
# Write to IO
io = IOBuffer()
JSON.writefile(io, Dict("key" => "value"))
String(take!(io)) # "{\"key\":\"value\"}"

# Write to file
JSON.writefile("output.json", [1, 2, 3])

# Get as bytes
bytes = JSON.writefile(Vector{UInt8}, Dict("hello" => "world"))
String(bytes) # "{\"hello\":\"world\"}"
```
"""
function writefile end

function writefile(::Type{Vector{UInt8}}, x; pretty::Union{Integer,Bool}=false, kw...)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not following why we want this or the 2nd definitions? writefile that doesn't write to a file and just returns a byte vector?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to avoid extra conversions between String and Vector{UInt8} for use with Zarr.jl and SmallZarrGroups.jl

I'm also trying to match the style of the writefile function in Parquet2.jl https://expandingman.gitlab.io/Parquet2.jl/#Writing-Data

opts = WriteOptions(; pretty=pretty === true ? 2 : Int(pretty), kw...)
_jsonlines_pretty_check(opts.jsonlines, opts.pretty)
float_style_check(opts.float_style)
y = StructUtils.lower(opts.style, x)
buf = Vector{UInt8}(undef, sizeguess(y))
pos = json!(buf, 1, y, opts, Any[y], nothing)
resize!(buf, pos - 1)
return buf
end

function writefile(io::IO, x; kw...)
json(io, x; kw...)
end

function writefile(filename::AbstractString, x; kw...)
open(filename; write=true) do io
writefile(io, x; kw...)
end
end

@compile_workload begin
x = JSON.parse("{\"a\": 1, \"b\": null, \"c\": true, \"d\": false, \"e\": \"\", \"f\": [1,null,true], \"g\": {\"key\": \"value\"}}")
json = JSON.json(x)
Expand Down
15 changes: 15 additions & 0 deletions test/json.jl
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,21 @@ end
# inline_limit tests
@test JSON.json([1, 2]; pretty=2, inline_limit=3) == "[1,2]"
@test JSON.json([1, 2, 3]; pretty=2, inline_limit=3) == "[\n 1,\n 2,\n 3\n]"
# writefile
for (obj, kw, output) in [
([1, 2, 3], (;), b"[1,2,3]"),
([1, 2, 3], (;pretty=true), b"[\n 1,\n 2,\n 3\n]"),
(NaN, (;allownan=true), b"NaN"),
(NaN, (;allownan=true, nan="different nan string"), b"different nan string"),
]
@test JSON.writefile(Vector{UInt8}, obj; kw...) == output
io = IOBuffer()
@test JSON.writefile(io, obj; kw...) === nothing
@test take!(io) == output
fname = tempname()
@test JSON.writefile(fname, obj; kw...) === nothing
@test read(fname) == output
end
end
# non-Integer/AbstractFloat but <: Real output
@test_throws MethodError JSON.json(CustomNumber(3.14))
Expand Down
Loading