// Copyright 2019 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.

package impl

import (
	
	
	

	
	proto 
	piface 
)

type marshalOptions struct {
	flags piface.MarshalInputFlags
}

func ( marshalOptions) () proto.MarshalOptions {
	return proto.MarshalOptions{
		AllowPartial:  true,
		Deterministic: .Deterministic(),
		UseCachedSize: .UseCachedSize(),
	}
}

func ( marshalOptions) () bool { return .flags&piface.MarshalDeterministic != 0 }
func ( marshalOptions) () bool { return .flags&piface.MarshalUseCachedSize != 0 }

// size is protoreflect.Methods.Size.
func ( *MessageInfo) ( piface.SizeInput) piface.SizeOutput {
	var  pointer
	if ,  := .Message.(*messageState);  {
		 = .pointer()
	} else {
		 = .Message.(*messageReflectWrapper).pointer()
	}
	 := .sizePointer(, marshalOptions{
		flags: .Flags,
	})
	return piface.SizeOutput{Size: }
}

func ( *MessageInfo) ( pointer,  marshalOptions) ( int) {
	.init()
	if .IsNil() {
		return 0
	}
	if .UseCachedSize() && .sizecacheOffset.IsValid() {
		if  := atomic.LoadInt32(.Apply(.sizecacheOffset).Int32());  >= 0 {
			return int()
		}
	}
	return .sizePointerSlow(, )
}

func ( *MessageInfo) ( pointer,  marshalOptions) ( int) {
	if flags.ProtoLegacy && .isMessageSet {
		 = sizeMessageSet(, , )
		if .sizecacheOffset.IsValid() {
			atomic.StoreInt32(.Apply(.sizecacheOffset).Int32(), int32())
		}
		return 
	}
	if .extensionOffset.IsValid() {
		 := .Apply(.extensionOffset).Extensions()
		 += .sizeExtensions(, )
	}
	for ,  := range .orderedCoderFields {
		if .funcs.size == nil {
			continue
		}
		 := .Apply(.offset)
		if .isPointer && .Elem().IsNil() {
			continue
		}
		 += .funcs.size(, , )
	}
	if .unknownOffset.IsValid() {
		if  := .getUnknownBytes();  != nil {
			 += len(*)
		}
	}
	if .sizecacheOffset.IsValid() {
		if  > math.MaxInt32 {
			// The size is too large for the int32 sizecache field.
			// We will need to recompute the size when encoding;
			// unfortunately expensive, but better than invalid output.
			atomic.StoreInt32(.Apply(.sizecacheOffset).Int32(), -1)
		} else {
			atomic.StoreInt32(.Apply(.sizecacheOffset).Int32(), int32())
		}
	}
	return 
}

// marshal is protoreflect.Methods.Marshal.
func ( *MessageInfo) ( piface.MarshalInput) ( piface.MarshalOutput,  error) {
	var  pointer
	if ,  := .Message.(*messageState);  {
		 = .pointer()
	} else {
		 = .Message.(*messageReflectWrapper).pointer()
	}
	,  := .marshalAppendPointer(.Buf, , marshalOptions{
		flags: .Flags,
	})
	return piface.MarshalOutput{Buf: }, 
}

func ( *MessageInfo) ( []byte,  pointer,  marshalOptions) ([]byte, error) {
	.init()
	if .IsNil() {
		return , nil
	}
	if flags.ProtoLegacy && .isMessageSet {
		return marshalMessageSet(, , , )
	}
	var  error
	// The old marshaler encodes extensions at beginning.
	if .extensionOffset.IsValid() {
		 := .Apply(.extensionOffset).Extensions()
		// TODO: Special handling for MessageSet?
		,  = .appendExtensions(, , )
		if  != nil {
			return , 
		}
	}
	for ,  := range .orderedCoderFields {
		if .funcs.marshal == nil {
			continue
		}
		 := .Apply(.offset)
		if .isPointer && .Elem().IsNil() {
			continue
		}
		,  = .funcs.marshal(, , , )
		if  != nil {
			return , 
		}
	}
	if .unknownOffset.IsValid() && !.isMessageSet {
		if  := .getUnknownBytes();  != nil {
			 = append(, (*)...)
		}
	}
	return , nil
}

func ( *MessageInfo) ( *map[int32]ExtensionField,  marshalOptions) ( int) {
	if  == nil {
		return 0
	}
	for ,  := range * {
		 := getExtensionFieldInfo(.Type())
		if .funcs.size == nil {
			continue
		}
		 += .funcs.size(.Value(), .tagsize, )
	}
	return 
}

func ( *MessageInfo) ( []byte,  *map[int32]ExtensionField,  marshalOptions) ([]byte, error) {
	if  == nil {
		return , nil
	}

	switch len(*) {
	case 0:
		return , nil
	case 1:
		// Fast-path for one extension: Don't bother sorting the keys.
		var  error
		for ,  := range * {
			 := getExtensionFieldInfo(.Type())
			,  = .funcs.marshal(, .Value(), .wiretag, )
		}
		return , 
	default:
		// Sort the keys to provide a deterministic encoding.
		// Not sure this is required, but the old code does it.
		 := make([]int, 0, len(*))
		for  := range * {
			 = append(, int())
		}
		sort.Ints()
		var  error
		for ,  := range  {
			 := (*)[int32()]
			 := getExtensionFieldInfo(.Type())
			,  = .funcs.marshal(, .Value(), .wiretag, )
			if  != nil {
				return , 
			}
		}
		return , nil
	}
}