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

// Package order provides ordered access to messages and maps.
package order import ( ) type messageField struct { fd protoreflect.FieldDescriptor v protoreflect.Value } var messageFieldPool = sync.Pool{ New: func() interface{} { return new([]messageField) }, } type ( // FieldRnger is an interface for visiting all fields in a message. // The protoreflect.Message type implements this interface. FieldRanger interface{ Range(VisitField) } // VisitField is called every time a message field is visited. VisitField = func(protoreflect.FieldDescriptor, protoreflect.Value) bool ) // RangeFields iterates over the fields of fs according to the specified order. func ( FieldRanger, FieldOrder, VisitField) { if == nil { .Range() return } // Obtain a pre-allocated scratch buffer. := messageFieldPool.Get().(*[]messageField) := (*)[:0] defer func() { if cap() < 1024 { * = messageFieldPool.Put() } }() // Collect all fields in the message and sort them. .Range(func( protoreflect.FieldDescriptor, protoreflect.Value) bool { = append(, messageField{, }) return true }) sort.Slice(, func(, int) bool { return ([].fd, [].fd) }) // Visit the fields in the specified ordering. for , := range { if !(.fd, .v) { return } } } type mapEntry struct { k protoreflect.MapKey v protoreflect.Value } var mapEntryPool = sync.Pool{ New: func() interface{} { return new([]mapEntry) }, } type ( // EntryRanger is an interface for visiting all fields in a message. // The protoreflect.Map type implements this interface. EntryRanger interface{ Range(VisitEntry) } // VisitEntry is called every time a map entry is visited. VisitEntry = func(protoreflect.MapKey, protoreflect.Value) bool ) // RangeEntries iterates over the entries of es according to the specified order. func ( EntryRanger, KeyOrder, VisitEntry) { if == nil { .Range() return } // Obtain a pre-allocated scratch buffer. := mapEntryPool.Get().(*[]mapEntry) := (*)[:0] defer func() { if cap() < 1024 { * = mapEntryPool.Put() } }() // Collect all entries in the map and sort them. .Range(func( protoreflect.MapKey, protoreflect.Value) bool { = append(, mapEntry{, }) return true }) sort.Slice(, func(, int) bool { return ([].k, [].k) }) // Visit the entries in the specified ordering. for , := range { if !(.k, .v) { return } } }