#Replacement for std.json.stringify?

1 messages · Page 1 of 1 (latest)

distant vale
#

zig 0.15.1 seems to have removed std.json.stringify, is there an equivalent replacement?

I'm noticing in the source code, they are doing this:

fn testStringify(expected: []const u8, v: anytype, options: Options) !void {
    var buffer: [4096]u8 = undefined;
    var w: Writer = .fixed(&buffer);
    try value(v, options, &w);
    try std.testing.expectEqualStrings(expected, w.buffered());
}

but the fixed writer would fail if the output text size of v would be greater than 4096, right? Maybe there's a writer that could be created with an allocator, but I'm having a hard time figuring out where all these replacements are (and knowing if I'm even going down the correct route in the first place).

Is there something more simple I'm not seeing?

wheat sail
#

You can use std.json.Stringify.value to write data as JSON to an arbitrary writer. They're using a fixed buffer for the tests as they know their expected output will always fit. Depending on your use case, you probably want a different writer.

distant vale
#

They removed the buffered writer as well, is there a writer I can create that would just use a buffer or do I need some writer that uses an allocator? I'm not seeing anything I can use

spark pawn
#

std.Io.Writer.fixed() uses a fixed buffer. std.Io.Writer.Allocating uses an allocator to allocate more memory as needed.

wheat sail
#

You may also be able to stream the JSON data to where you need it, but for that, we'd need to know more.

distant vale
#

Right, as I was saying in my post, fixed would just run out of memory in this case right? If the stringified value were too big

wheat sail
#

You'd probably get an error.WriteFailed

spark pawn
#

If you don't know how much memory you need, then the Allocating writer is probably the answer if you want to write to memory.

distant vale
#

Does this look appropriate for stringifying and returning copied memory?

pub fn stringify(alloc: Allocator, value: anytype, options: std.json.Stringify.Options) ![]const u8 {
    var writer = std.Io.Writer.Allocating.init(alloc);
    defer writer.deinit();
    try std.json.Stringify.value(value, options, writer);

    const written = writer.written();
    const new_memory = try alloc.alignedAlloc(u8, @alignOf(u8), written.len);
    @memcpy(new_memory, written);
    return new_memory;
}
tardy dock
#

Even without that, you could alloc.dupe

#

Though again to be clear, I wouldn't dupe

distant vale
#

Seems like toOwnedSlice is doing some extra work behind the scenes
You wouldn't dupe the memory?

tardy dock
distant vale
#

Should I just not call writer.deinit and return writer.written(), then the caller "owns" the memory?

tardy dock
#

You could however because Zig allocators are anal about the exact number of bytes in an allocation it'll yell if you try to free only a part of an allocation

#

And that is what toOwnedSlice addreses

distant vale
#

toOwnedSlice converts the data structure to an arraylist, then memcopy's the underlying memory

tardy dock
#

Only if the allocator cannot shrink it

#
        pub fn toOwnedSlice(self: *Self, gpa: Allocator) Allocator.Error!Slice {
            const old_memory = self.allocatedSlice();
            if (gpa.remap(old_memory, self.items.len)) |new_items| {
                self.* = .empty;
                return new_items;
            }

            const new_memory = try gpa.alignedAlloc(T, alignment, self.items.len);
            @memcpy(new_memory, self.items);
            self.clearAndFree(gpa);
            return new_memory;
        }

distant vale
#

The conversion to an arraylist in the first place seems a bit odd but I guess it's not that much overhead, even if this is called a lot...

tardy dock