// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build goexperiment.jsonv2

package jsontext

import (
	
	
	
	
	

	
	
)

// NOTE: Value is analogous to v1 json.RawMessage.

// AppendFormat formats the JSON value in src and appends it to dst
// according to the specified options.
// See [Value.Format] for more details about the formatting behavior.
//
// The dst and src may overlap.
// If an error is reported, then the entirety of src is appended to dst.
func (,  []byte,  ...Options) ([]byte, error) {
	 := getBufferedEncoder(...)
	defer putBufferedEncoder()
	.s.Flags.Set(jsonflags.OmitTopLevelNewline | 1)
	if  := .s.WriteValue();  != nil {
		return append(, ...), 
	}
	return append(, .s.Buf...), nil
}

// Value represents a single raw JSON value, which may be one of the following:
//   - a JSON literal (i.e., null, true, or false)
//   - a JSON string (e.g., "hello, world!")
//   - a JSON number (e.g., 123.456)
//   - an entire JSON object (e.g., {"fizz":"buzz"} )
//   - an entire JSON array (e.g., [1,2,3] )
//
// Value can represent entire array or object values, while [Token] cannot.
// Value may contain leading and/or trailing whitespace.
type Value []byte

// Clone returns a copy of v.
func ( Value) () Value {
	return bytes.Clone()
}

// String returns the string formatting of v.
func ( Value) () string {
	if  == nil {
		return "null"
	}
	return string()
}

// IsValid reports whether the raw JSON value is syntactically valid
// according to the specified options.
//
// By default (if no options are specified), it validates according to RFC 7493.
// It verifies whether the input is properly encoded as UTF-8,
// that escape sequences within strings decode to valid Unicode codepoints, and
// that all names in each object are unique.
// It does not verify whether numbers are representable within the limits
// of any common numeric type (e.g., float64, int64, or uint64).
//
// Relevant options include:
//   - [AllowDuplicateNames]
//   - [AllowInvalidUTF8]
//
// All other options are ignored.
func ( Value) ( ...Options) bool {
	// TODO: Document support for [WithByteLimit] and [WithDepthLimit].
	 := getBufferedDecoder(, ...)
	defer putBufferedDecoder()
	,  := .ReadValue()
	,  := .ReadToken()
	return  == nil &&  == io.EOF
}

// Format formats the raw JSON value in place.
//
// By default (if no options are specified), it validates according to RFC 7493
// and produces the minimal JSON representation, where
// all whitespace is elided and JSON strings use the shortest encoding.
//
// Relevant options include:
//   - [AllowDuplicateNames]
//   - [AllowInvalidUTF8]
//   - [EscapeForHTML]
//   - [EscapeForJS]
//   - [PreserveRawStrings]
//   - [CanonicalizeRawInts]
//   - [CanonicalizeRawFloats]
//   - [ReorderRawObjects]
//   - [SpaceAfterColon]
//   - [SpaceAfterComma]
//   - [Multiline]
//   - [WithIndent]
//   - [WithIndentPrefix]
//
// All other options are ignored.
//
// It is guaranteed to succeed if the value is valid according to the same options.
// If the value is already formatted, then the buffer is not mutated.
func ( *Value) ( ...Options) error {
	// TODO: Document support for [WithByteLimit] and [WithDepthLimit].
	return .format(, nil)
}

// format accepts two []Options to avoid the allocation appending them together.
// It is equivalent to v.Format(append(opts1, opts2...)...).
func ( *Value) (,  []Options) error {
	 := getBufferedEncoder(...)
	defer putBufferedEncoder()
	.s.Join(...)
	.s.Flags.Set(jsonflags.OmitTopLevelNewline | 1)
	if  := .s.WriteValue(*);  != nil {
		return 
	}
	if !bytes.Equal(*, .s.Buf) {
		* = append((*)[:0], .s.Buf...)
	}
	return nil
}

// Compact removes all whitespace from the raw JSON value.
//
// It does not reformat JSON strings or numbers to use any other representation.
// To maximize the set of JSON values that can be formatted,
// this permits values with duplicate names and invalid UTF-8.
//
// Compact is equivalent to calling [Value.Format] with the following options:
//   - [AllowDuplicateNames](true)
//   - [AllowInvalidUTF8](true)
//   - [PreserveRawStrings](true)
//
// Any options specified by the caller are applied after the initial set
// and may deliberately override prior options.
func ( *Value) ( ...Options) error {
	return .format([]Options{
		AllowDuplicateNames(true),
		AllowInvalidUTF8(true),
		PreserveRawStrings(true),
	}, )
}

// Indent reformats the whitespace in the raw JSON value so that each element
// in a JSON object or array begins on a indented line according to the nesting.
//
// It does not reformat JSON strings or numbers to use any other representation.
// To maximize the set of JSON values that can be formatted,
// this permits values with duplicate names and invalid UTF-8.
//
// Indent is equivalent to calling [Value.Format] with the following options:
//   - [AllowDuplicateNames](true)
//   - [AllowInvalidUTF8](true)
//   - [PreserveRawStrings](true)
//   - [Multiline](true)
//
// Any options specified by the caller are applied after the initial set
// and may deliberately override prior options.
func ( *Value) ( ...Options) error {
	return .format([]Options{
		AllowDuplicateNames(true),
		AllowInvalidUTF8(true),
		PreserveRawStrings(true),
		Multiline(true),
	}, )
}

// Canonicalize canonicalizes the raw JSON value according to the
// JSON Canonicalization Scheme (JCS) as defined by RFC 8785
// where it produces a stable representation of a JSON value.
//
// JSON strings are formatted to use their minimal representation,
// JSON numbers are formatted as double precision numbers according
// to some stable serialization algorithm.
// JSON object members are sorted in ascending order by name.
// All whitespace is removed.
//
// The output stability is dependent on the stability of the application data
// (see RFC 8785, Appendix E). It cannot produce stable output from
// fundamentally unstable input. For example, if the JSON value
// contains ephemeral data (e.g., a frequently changing timestamp),
// then the value is still unstable regardless of whether this is called.
//
// Canonicalize is equivalent to calling [Value.Format] with the following options:
//   - [CanonicalizeRawInts](true)
//   - [CanonicalizeRawFloats](true)
//   - [ReorderRawObjects](true)
//
// Any options specified by the caller are applied after the initial set
// and may deliberately override prior options.
//
// Note that JCS treats all JSON numbers as IEEE 754 double precision numbers.
// Any numbers with precision beyond what is representable by that form
// will lose their precision when canonicalized. For example, integer values
// beyond ±2⁵³ will lose their precision. To preserve the original representation
// of JSON integers, additionally set [CanonicalizeRawInts] to false:
//
//	v.Canonicalize(jsontext.CanonicalizeRawInts(false))
func ( *Value) ( ...Options) error {
	return .format([]Options{
		CanonicalizeRawInts(true),
		CanonicalizeRawFloats(true),
		ReorderRawObjects(true),
	}, )
}

// MarshalJSON returns v as the JSON encoding of v.
// It returns the stored value as the raw JSON output without any validation.
// If v is nil, then this returns a JSON null.
func ( Value) () ([]byte, error) {
	// NOTE: This matches the behavior of v1 json.RawMessage.MarshalJSON.
	if  == nil {
		return []byte("null"), nil
	}
	return , nil
}

// UnmarshalJSON sets v as the JSON encoding of b.
// It stores a copy of the provided raw JSON input without any validation.
func ( *Value) ( []byte) error {
	// NOTE: This matches the behavior of v1 json.RawMessage.UnmarshalJSON.
	if  == nil {
		return errors.New("jsontext.Value: UnmarshalJSON on nil pointer")
	}
	* = append((*)[:0], ...)
	return nil
}

// Kind returns the starting token kind.
// For a valid value, this will never include '}' or ']'.
func ( Value) () Kind {
	if  := [jsonwire.ConsumeWhitespace():]; len() > 0 {
		return Kind([0]).normalize()
	}
	return invalidKind
}

const commaAndWhitespace = ", \n\r\t"

type objectMember struct {
	// name is the unquoted name.
	name []byte // e.g., "name"
	// buffer is the entirety of the raw JSON object member
	// starting from right after the previous member (or opening '{')
	// until right after the member value.
	buffer []byte // e.g., `, \n\r\t"name": "value"`
}

func ( objectMember) ( objectMember) int {
	if  := jsonwire.CompareUTF16(.name, .name);  != 0 {
		return 
	}
	// With [AllowDuplicateNames] or [AllowInvalidUTF8],
	// names could be identical, so also sort using the member value.
	return jsonwire.CompareUTF16(
		bytes.TrimLeft(.buffer, commaAndWhitespace),
		bytes.TrimLeft(.buffer, commaAndWhitespace))
}

var objectMemberPool = sync.Pool{New: func() any { return new([]objectMember) }}

func getObjectMembers() *[]objectMember {
	 := objectMemberPool.Get().(*[]objectMember)
	* = (*)[:0]
	return 
}
func putObjectMembers( *[]objectMember) {
	if cap(*) < 1<<10 {
		clear(*) // avoid pinning name and buffer
		objectMemberPool.Put()
	}
}

// mustReorderObjects reorders in-place all object members in a JSON value,
// which must be valid otherwise it panics.
func mustReorderObjects( []byte) {
	// Obtain a buffered encoder just to use its internal buffer as
	// a scratch buffer for reordering object members.
	 := getBufferedEncoder()
	defer putBufferedEncoder()

	// Disable unnecessary checks to syntactically parse the JSON value.
	 := getBufferedDecoder()
	defer putBufferedDecoder()
	.s.Flags.Set(jsonflags.AllowDuplicateNames | jsonflags.AllowInvalidUTF8 | 1)
	mustReorderObjectsFromDecoder(, &.s.Buf) // per RFC 8785, section 3.2.3
}

// mustReorderObjectsFromDecoder recursively reorders all object members in place
// according to the ordering specified in RFC 8785, section 3.2.3.
//
// Pre-conditions:
//   - The value is valid (i.e., no decoder errors should ever occur).
//   - Initial call is provided a Decoder reading from the start of v.
//
// Post-conditions:
//   - Exactly one JSON value is read from the Decoder.
//   - All fully-parsed JSON objects are reordered by directly moving
//     the members in the value buffer.
//
// The runtime is approximately O(n·log(n)) + O(m·log(m)),
// where n is len(v) and m is the total number of object members.
func mustReorderObjectsFromDecoder( *Decoder,  *[]byte) {
	switch ,  := .ReadToken(); .Kind() {
	case '{':
		// Iterate and collect the name and offsets for every object member.
		 := getObjectMembers()
		defer putObjectMembers()
		var  objectMember
		 := true

		 := .InputOffset() // offset after '{'
		for .PeekKind() != '}' {
			 := .InputOffset()
			var  jsonwire.ValueFlags
			,  := .s.ReadValue(&)
			 = jsonwire.UnquoteMayCopy(, .IsVerbatim())
			(, )
			 := .InputOffset()

			 := objectMember{, .s.buf[:]}
			if  && len(*) > 0 {
				 = objectMember.Compare(, ) < 0
			}
			* = append(*, )
			 = 
		}
		 := .InputOffset() // offset before '}'
		.ReadToken()

		// Sort the members; return early if it's already sorted.
		if  {
			return
		}
		 := (*)[0].buffer
		slices.SortFunc(*, objectMember.Compare)
		 := (*)[0].buffer

		// Append the reordered members to a new buffer,
		// then copy the reordered members back over the original members.
		// Avoid swapping in place since each member may be a different size
		// where moving a member over a smaller member may corrupt the data
		// for subsequent members before they have been moved.
		//
		// The following invariant must hold:
		//	sum([m.after-m.before for m in members]) == afterBody-beforeBody
		 := func( []byte) []byte {
			return [:len()-len(bytes.TrimLeft(, commaAndWhitespace))]
		}
		 := (*)[:0]
		for ,  := range * {
			switch {
			case  == 0 && &.buffer[0] != &[0]:
				// First member after sorting is not the first member before sorting,
				// so use the prefix of the first member before sorting.
				 = append(, ()...)
				 = append(, bytes.TrimLeft(.buffer, commaAndWhitespace)...)
			case  != 0 && &.buffer[0] == &[0]:
				// Later member after sorting is the first member before sorting,
				// so use the prefix of the first member after sorting.
				 = append(, ()...)
				 = append(, bytes.TrimLeft(.buffer, commaAndWhitespace)...)
			default:
				 = append(, .buffer...)
			}
		}
		if int(-) != len() {
			panic("BUG: length invariant violated")
		}
		copy(.s.buf[:], )

		// Update scratch buffer to the largest amount ever used.
		if len() > len(*) {
			* = 
		}
	case '[':
		for .PeekKind() != ']' {
			(, )
		}
		.ReadToken()
	default:
		if  != nil {
			panic("BUG: " + .Error())
		}
	}
}