// 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 json

import (
	
	
	
	

	
	
	
	
)

// This package supports "inlining" a Go struct field, where the contents
// of the serialized field (which must be a JSON object) are treated as if
// they are part of the parent Go struct (which represents a JSON object).
//
// Generally, inlined fields are of a Go struct type, where the fields of the
// nested struct are virtually hoisted up to the parent struct using rules
// similar to how Go embedding works (but operating within the JSON namespace).
//
// However, inlined fields may also be of a Go map type with a string key or
// a jsontext.Value. Such inlined fields are called "fallback" fields since they
// represent any arbitrary JSON object member. Explicitly named fields take
// precedence over the inlined fallback. Only one inlined fallback is allowed.

var errRawInlinedNotObject = errors.New("inlined raw value must be a JSON object")

var jsontextValueType = reflect.TypeFor[jsontext.Value]()

// marshalInlinedFallbackAll marshals all the members in an inlined fallback.
func marshalInlinedFallbackAll( *jsontext.Encoder,  addressableValue,  *jsonopts.Struct,  *structField,  func([]byte) bool) error {
	 := addressableValue{.Field(.index0), .forcedAddr} // addressable if struct value is addressable
	if len(.index) > 0 {
		 = .fieldByIndex(.index, false)
		if !.IsValid() {
			return nil // implies a nil inlined field
		}
	}
	 = .indirect(false)
	if !.IsValid() {
		return nil
	}

	if .Type() == jsontextValueType {
		// TODO(https://go.dev/issue/62121): Use reflect.Value.AssertTo.
		 := *.Addr().Interface().(*jsontext.Value)
		if len() == 0 { // TODO: Should this be nil? What if it were all whitespace?
			return nil
		}

		 := export.GetBufferedDecoder()
		defer export.PutBufferedDecoder()
		 := export.Decoder()
		.Flags.Set(jsonflags.AllowDuplicateNames | jsonflags.AllowInvalidUTF8 | 1)

		,  := .ReadToken()
		if  != nil {
			if  == io.EOF {
				 = io.ErrUnexpectedEOF
			}
			return newMarshalErrorBefore(, .Type(), )
		}
		if .Kind() != '{' {
			return newMarshalErrorBefore(, .Type(), errRawInlinedNotObject)
		}
		for .PeekKind() != '}' {
			// Parse the JSON object name.
			var  jsonwire.ValueFlags
			,  := .ReadValue(&)
			if  != nil {
				return newMarshalErrorBefore(, .Type(), )
			}
			if  != nil {
				 := jsonwire.UnquoteMayCopy(, .IsVerbatim())
				if !() {
					return newDuplicateNameError(.StackPointer().Parent(), , .OutputOffset())
				}
			}
			if  := .WriteValue();  != nil {
				return 
			}

			// Parse the JSON object value.
			,  = .ReadValue(&)
			if  != nil {
				return newMarshalErrorBefore(, .Type(), )
			}
			if  := .WriteValue();  != nil {
				return 
			}
		}
		if ,  := .ReadToken();  != nil {
			return newMarshalErrorBefore(, .Type(), )
		}
		if  := .CheckEOF();  != nil {
			return newMarshalErrorBefore(, .Type(), )
		}
		return nil
	} else {
		 :=  // must be a map[~string]V
		 := .Len()
		if  == 0 {
			return nil
		}
		 := newAddressableValue(.Type().Key())
		 := newAddressableValue(.Type().Elem())
		 := func( addressableValue) error {
			,  := jsonwire.AppendQuote(.UnusedBuffer(), .String(), &.Flags)
			if  != nil {
				return newMarshalErrorBefore(, .Type().Key(), )
			}
			if  != nil {
				 := bytes.IndexByte(, '\\') < 0
				 := jsonwire.UnquoteMayCopy(, )
				if !() {
					return newDuplicateNameError(.StackPointer().Parent(), , .OutputOffset())
				}
			}
			return .WriteValue()
		}
		 := .fncs.marshal
		if .Marshalers != nil {
			, _ = .Marshalers.(*Marshalers).lookup(, .Type())
		}
		if !.Flags.Get(jsonflags.Deterministic) ||  <= 1 {
			for  := .MapRange(); .Next(); {
				.SetIterKey()
				if  := ();  != nil {
					return 
				}
				.Set(.Value())
				if  := (, , );  != nil {
					return 
				}
			}
		} else {
			 := getStrings()
			for ,  := 0, .Value.MapRange();  <  && .Next(); ++ {
				.SetIterKey()
				(*)[] = .String()
			}
			.Sort()
			for ,  := range * {
				.SetString()
				if  := ();  != nil {
					return 
				}
				// TODO(https://go.dev/issue/57061): Use mv.SetMapIndexOf.
				.Set(.MapIndex(.Value))
				if  := (, , );  != nil {
					return 
				}
			}
			putStrings()
		}
		return nil
	}
}

// unmarshalInlinedFallbackNext unmarshals only the next member in an inlined fallback.
func unmarshalInlinedFallbackNext( *jsontext.Decoder,  addressableValue,  *jsonopts.Struct,  *structField, ,  []byte) error {
	 := addressableValue{.Field(.index0), .forcedAddr} // addressable if struct value is addressable
	if len(.index) > 0 {
		 = .fieldByIndex(.index, true)
	}
	 = .indirect(true)

	if .Type() == jsontextValueType {
		 := .Addr().Interface().(*jsontext.Value)
		if len(*) == 0 { // TODO: Should this be nil? What if it were all whitespace?
			* = append(*, '{')
		} else {
			* = jsonwire.TrimSuffixWhitespace(*)
			if jsonwire.HasSuffixByte(*, '}') {
				// TODO: When merging into an object for the first time,
				// should we verify that it is valid?
				* = jsonwire.TrimSuffixByte(*, '}')
				* = jsonwire.TrimSuffixWhitespace(*)
				if !jsonwire.HasSuffixByte(*, ',') && !jsonwire.HasSuffixByte(*, '{') {
					* = append(*, ',')
				}
			} else {
				return newUnmarshalErrorAfterWithSkipping(, , .Type(), errRawInlinedNotObject)
			}
		}
		* = append(*, ...)
		* = append(*, ':')
		,  := .ReadValue()
		if  != nil {
			return 
		}
		* = append(*, ...)
		* = append(*, '}')
		return nil
	} else {
		 := string() // TODO: Intern this?

		 :=  // must be a map[~string]V
		if .IsNil() {
			.Set(reflect.MakeMap(.Type()))
		}
		 := reflect.ValueOf()
		if  := .Type().Key();  != stringType {
			 = .Convert()
		}
		 := newAddressableValue(.Type().Elem()) // TODO: Cache across calls?
		if  := .MapIndex(); .IsValid() {
			.Set()
		}

		 := .fncs.unmarshal
		if .Unmarshalers != nil {
			, _ = .Unmarshalers.(*Unmarshalers).lookup(, .Type())
		}
		 := (, , )
		.SetMapIndex(, .Value)
		if  != nil {
			return 
		}
		return nil
	}
}