toJsonSummaryString

fun Variant.toJsonSummaryString(limit: Int = DEFAULT_SUMMARY_LIMIT): String

The first limit top-level children, with everything below them elided.

{"id":42,"name":"ada","tags":[…1024],"blob":…4200000 bytes,…9 more}

This is not JSON, and making it into JSON would be worse rather than better. It is JSON-shaped so that anyone who reads JSON can skim it, and every elision is spelled with a … that JSON has no production for — deliberately, so the output cannot be mistaken for the value. The alternative is to elide into something JSON can express, and an elided array rendered [] is readable and wrong: nothing distinguishes it from an empty one. Use toJsonString when you want JSON.

A container child shows its shape and its own child count ({…12}, […1024], or {} and [] when genuinely empty); a scalar too large to show is reported by size (…4200000 bytes); the children past limit are counted (…9 more). A small value elides nothing and therefore does come out as JSON — that agreement is a consequence of sharing one scalar renderer with toJsonString rather than a promise, and the suite asserts it as a consequence.

Both the length of the result and the bytes read are bounded by a function of limit and SUMMARY_VALUE_LIMIT alone. Both are the point: this exists to be called on a value whose size is the reason you cannot call toJsonString.

Parameters

limit

top-level children to show. 0 shows only the count, which is the "just tell me the shape" form. Unlimited is deliberately not offered — that is toJsonString, which already exists, and a second spelling of it would be the worse one.

Throws

if the bytes do not decode. A summary reports unreadable data rather than eliding it: eliding would be a default invented for exactly the thing that has to be signalled, and would report "here are eight children" about bytes that have none. Reach for toSummaryString when you need something that cannot throw.

for a non-finite double among the children shown, as toJsonString does for the same value. It cannot throw for depth: at one level there is nothing to recurse into. The overload taking a depth is the form that can be asked to go further.


fun Variant.toJsonSummaryString(limit: Int = DEFAULT_SUMMARY_LIMIT, depth: Int): String

The first limit children of every level down to depth, with everything below them elided.

limit = 3, depth = 3, on a twelve-field document:
{"id":42,"order":{"lines":[{…4},{…4},{…4},…2 more],"total":9.5},"tags":["a","b","c",…1021 more],…9 more}

Both elision spellings are in there and they say different things: {…4} is a container the walk stopped at, reporting its own child count, and …2 more is what a level had left over after showing limit of it. The first is where depth ran out and the second is where limit did.

This is toJsonSummaryString reaching further, and it is that function rather than a second one that resembles it. depth = 1 is the top-level outline — the same walk, the same scalar renderer, the same elision vocabulary — and the suite asserts the two agree for every document and every limit rather than leaving it to be read off the code. So everything the one-level form promises holds here unchanged: it is deliberately not JSON, an elision is always spelled …, a container that shows nothing shows its own count, and unreadable bytes are reported rather than elided. Only the reach differs.

The cost contract survives too, and it is worth being exact about what survives. The bytes read and the characters written are still a function of limit, depth and SUMMARY_VALUE_LIMIT alone, and still have no term in them for the value's size — which is the property this whole file exists for, and the reason this is not simply toJsonString with a stopping rule. What changes is that the function is exponential in depth: at most limit + limit² + … + limit^depth values are shown, so the default limit at four levels is already some four thousand of them and at eight is past anything a reader wanted.

That is why depth has no default and is not going to be given one. A caller who wants to see further has to say how much further, and the number they write is the price they are agreeing to; a default here would be a cost decision taken on their behalf, in the one place where the cost is the entire subject. depth = 1 needs no such decision, which is exactly why it is spelled as its own function rather than as this one's default.

Parameters

limit

children to show at each level, not only at the top. 0 shows every level's count and none of its children, which collapses the whole outline to the root's {…N more}.

depth

levels to expand before eliding a container by shape and count. 1 is toJsonSummaryString. The ceiling is DEFAULT_MAX_JSON_DEPTH because this recurses and that is the depth toJsonString already refuses to descend past — one number for how deep this module will walk a document, not a second one that could disagree with it. The document's own nesting never enters into it: the walk stops at depth whether the value bottoms out above it or runs far below.

Throws

if limit is negative, or if depth is not in 1..DEFAULT_MAX_JSON_DEPTH.

if the bytes do not decode, in any level it reached.

for a non-finite double among the values shown.