// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2017 The Go Authors.  All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package proto

import (
	
	
	
	
	
)

type generatedDiscarder interface {
	XXX_DiscardUnknown()
}

// DiscardUnknown recursively discards all unknown fields from this message
// and all embedded messages.
//
// When unmarshaling a message with unrecognized fields, the tags and values
// of such fields are preserved in the Message. This allows a later call to
// marshal to be able to produce a message that continues to have those
// unrecognized fields. To avoid this, DiscardUnknown is used to
// explicitly clear the unknown fields after unmarshaling.
//
// For proto2 messages, the unknown fields of message extensions are only
// discarded from messages that have been accessed via GetExtension.
func ( Message) {
	if ,  := .(generatedDiscarder);  {
		.XXX_DiscardUnknown()
		return
	}
	// TODO: Dynamically populate a InternalMessageInfo for legacy messages,
	// but the master branch has no implementation for InternalMessageInfo,
	// so it would be more work to replicate that approach.
	discardLegacy()
}

// DiscardUnknown recursively discards all unknown fields.
func ( *InternalMessageInfo) ( Message) {
	 := atomicLoadDiscardInfo(&.discard)
	if  == nil {
		 = getDiscardInfo(reflect.TypeOf().Elem())
		atomicStoreDiscardInfo(&.discard, )
	}
	.discard(toPointer(&))
}

type discardInfo struct {
	typ reflect.Type

	initialized int32 // 0: only typ is valid, 1: everything is valid
	lock        sync.Mutex

	fields       []discardFieldInfo
	unrecognized field
}

type discardFieldInfo struct {
	field   field // Offset of field, guaranteed to be valid
	discard func(src pointer)
}

var (
	discardInfoMap  = map[reflect.Type]*discardInfo{}
	discardInfoLock sync.Mutex
)

func getDiscardInfo( reflect.Type) *discardInfo {
	discardInfoLock.Lock()
	defer discardInfoLock.Unlock()
	 := discardInfoMap[]
	if  == nil {
		 = &discardInfo{typ: }
		discardInfoMap[] = 
	}
	return 
}

func ( *discardInfo) ( pointer) {
	if .isNil() {
		return // Nothing to do.
	}

	if atomic.LoadInt32(&.initialized) == 0 {
		.computeDiscardInfo()
	}

	for ,  := range .fields {
		 := .offset(.field)
		.discard()
	}

	// For proto2 messages, only discard unknown fields in message extensions
	// that have been accessed via GetExtension.
	if ,  := extendable(.asPointerTo(.typ).Interface());  == nil {
		// Ignore lock since DiscardUnknown is not concurrency safe.
		,  := .extensionsRead()
		for ,  := range  {
			if ,  := .value.(Message);  {
				DiscardUnknown()
			}
		}
	}

	if .unrecognized.IsValid() {
		*.offset(.unrecognized).toBytes() = nil
	}
}

func ( *discardInfo) () {
	.lock.Lock()
	defer .lock.Unlock()
	if .initialized != 0 {
		return
	}
	 := .typ
	 := .NumField()

	for  := 0;  < ; ++ {
		 := .Field()
		if strings.HasPrefix(.Name, "XXX_") {
			continue
		}

		 := discardFieldInfo{field: toField(&)}
		 := .Type

		// Unwrap tf to get its most basic type.
		var ,  bool
		if .Kind() == reflect.Slice && .Elem().Kind() != reflect.Uint8 {
			 = true
			 = .Elem()
		}
		if .Kind() == reflect.Ptr {
			 = true
			 = .Elem()
		}
		if  &&  && .Kind() != reflect.Struct {
			panic(fmt.Sprintf("%v.%s cannot be a slice of pointers to primitive types", , .Name))
		}

		switch .Kind() {
		case reflect.Struct:
			switch {
			case !:
				panic(fmt.Sprintf("%v.%s cannot be a direct struct value", , .Name))
			case : // E.g., []*pb.T
				 := getDiscardInfo()
				.discard = func( pointer) {
					 := .getPointerSlice()
					for ,  := range  {
						if !.isNil() {
							.discard()
						}
					}
				}
			default: // E.g., *pb.T
				 := getDiscardInfo()
				.discard = func( pointer) {
					 := .getPointer()
					if !.isNil() {
						.discard()
					}
				}
			}
		case reflect.Map:
			switch {
			case  || :
				panic(fmt.Sprintf("%v.%s cannot be a pointer to a map or a slice of map values", , .Name))
			default: // E.g., map[K]V
				if .Elem().Kind() == reflect.Ptr { // Proto struct (e.g., *T)
					.discard = func( pointer) {
						 := .asPointerTo().Elem()
						if .Len() == 0 {
							return
						}
						for ,  := range .MapKeys() {
							 := .MapIndex()
							DiscardUnknown(.Interface().(Message))
						}
					}
				} else {
					.discard = func(pointer) {} // Noop
				}
			}
		case reflect.Interface:
			// Must be oneof field.
			switch {
			case  || :
				panic(fmt.Sprintf("%v.%s cannot be a pointer to a interface or a slice of interface values", , .Name))
			default: // E.g., interface{}
				// TODO: Make this faster?
				.discard = func( pointer) {
					 := .asPointerTo().Elem()
					if !.IsNil() {
						 := .Elem().Elem().Field(0)
						if .Kind() == reflect.Ptr && .IsNil() {
							return
						}
						switch .Type().Kind() {
						case reflect.Ptr: // Proto struct (e.g., *T)
							DiscardUnknown(.Interface().(Message))
						}
					}
				}
			}
		default:
			continue
		}
		.fields = append(.fields, )
	}

	.unrecognized = invalidField
	if ,  := .FieldByName("XXX_unrecognized");  {
		if .Type != reflect.TypeOf([]byte{}) {
			panic("expected XXX_unrecognized to be of type []byte")
		}
		.unrecognized = toField(&)
	}

	atomic.StoreInt32(&.initialized, 1)
}

func discardLegacy( Message) {
	 := reflect.ValueOf()
	if .Kind() != reflect.Ptr || .IsNil() {
		return
	}
	 = .Elem()
	if .Kind() != reflect.Struct {
		return
	}
	 := .Type()

	for  := 0;  < .NumField(); ++ {
		 := .Field()
		if strings.HasPrefix(.Name, "XXX_") {
			continue
		}
		 := .Field()
		 := .Type

		// Unwrap tf to get its most basic type.
		var ,  bool
		if .Kind() == reflect.Slice && .Elem().Kind() != reflect.Uint8 {
			 = true
			 = .Elem()
		}
		if .Kind() == reflect.Ptr {
			 = true
			 = .Elem()
		}
		if  &&  && .Kind() != reflect.Struct {
			panic(fmt.Sprintf("%T.%s cannot be a slice of pointers to primitive types", , .Name))
		}

		switch .Kind() {
		case reflect.Struct:
			switch {
			case !:
				panic(fmt.Sprintf("%T.%s cannot be a direct struct value", , .Name))
			case : // E.g., []*pb.T
				for  := 0;  < .Len(); ++ {
					(.Index().Interface().(Message))
				}
			default: // E.g., *pb.T
				(.Interface().(Message))
			}
		case reflect.Map:
			switch {
			case  || :
				panic(fmt.Sprintf("%T.%s cannot be a pointer to a map or a slice of map values", , .Name))
			default: // E.g., map[K]V
				 := .Type().Elem()
				if .Kind() == reflect.Ptr && .Implements(protoMessageType) { // Proto struct (e.g., *T)
					for ,  := range .MapKeys() {
						 := .MapIndex()
						(.Interface().(Message))
					}
				}
			}
		case reflect.Interface:
			// Must be oneof field.
			switch {
			case  || :
				panic(fmt.Sprintf("%T.%s cannot be a pointer to a interface or a slice of interface values", , .Name))
			default: // E.g., test_proto.isCommunique_Union interface
				if !.IsNil() && .Tag.Get("protobuf_oneof") != "" {
					 = .Elem() // E.g., *test_proto.Communique_Msg
					if !.IsNil() {
						 = .Elem()   // E.g., test_proto.Communique_Msg
						 = .Field(0) // E.g., Proto struct (e.g., *T) or primitive value
						if .Kind() == reflect.Ptr {
							(.Interface().(Message))
						}
					}
				}
			}
		}
	}

	if  := .FieldByName("XXX_unrecognized"); .IsValid() {
		if .Type() != reflect.TypeOf([]byte{}) {
			panic("expected XXX_unrecognized to be of type []byte")
		}
		.Set(reflect.ValueOf([]byte(nil)))
	}

	// For proto2 messages, only discard unknown fields in message extensions
	// that have been accessed via GetExtension.
	if ,  := extendable();  == nil {
		// Ignore lock since discardLegacy is not concurrency safe.
		,  := .extensionsRead()
		for ,  := range  {
			if ,  := .value.(Message);  {
				()
			}
		}
	}
}