1*1c12ee1eSDan Willemsen// Copyright 2020 The Go Authors. All rights reserved. 2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style 3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file. 4*1c12ee1eSDan Willemsen 5*1c12ee1eSDan Willemsen// Package order provides ordered access to messages and maps. 6*1c12ee1eSDan Willemsenpackage order 7*1c12ee1eSDan Willemsen 8*1c12ee1eSDan Willemsenimport ( 9*1c12ee1eSDan Willemsen "sort" 10*1c12ee1eSDan Willemsen "sync" 11*1c12ee1eSDan Willemsen 12*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoreflect" 13*1c12ee1eSDan Willemsen) 14*1c12ee1eSDan Willemsen 15*1c12ee1eSDan Willemsentype messageField struct { 16*1c12ee1eSDan Willemsen fd protoreflect.FieldDescriptor 17*1c12ee1eSDan Willemsen v protoreflect.Value 18*1c12ee1eSDan Willemsen} 19*1c12ee1eSDan Willemsen 20*1c12ee1eSDan Willemsenvar messageFieldPool = sync.Pool{ 21*1c12ee1eSDan Willemsen New: func() interface{} { return new([]messageField) }, 22*1c12ee1eSDan Willemsen} 23*1c12ee1eSDan Willemsen 24*1c12ee1eSDan Willemsentype ( 25*1c12ee1eSDan Willemsen // FieldRnger is an interface for visiting all fields in a message. 26*1c12ee1eSDan Willemsen // The protoreflect.Message type implements this interface. 27*1c12ee1eSDan Willemsen FieldRanger interface{ Range(VisitField) } 28*1c12ee1eSDan Willemsen // VisitField is called every time a message field is visited. 29*1c12ee1eSDan Willemsen VisitField = func(protoreflect.FieldDescriptor, protoreflect.Value) bool 30*1c12ee1eSDan Willemsen) 31*1c12ee1eSDan Willemsen 32*1c12ee1eSDan Willemsen// RangeFields iterates over the fields of fs according to the specified order. 33*1c12ee1eSDan Willemsenfunc RangeFields(fs FieldRanger, less FieldOrder, fn VisitField) { 34*1c12ee1eSDan Willemsen if less == nil { 35*1c12ee1eSDan Willemsen fs.Range(fn) 36*1c12ee1eSDan Willemsen return 37*1c12ee1eSDan Willemsen } 38*1c12ee1eSDan Willemsen 39*1c12ee1eSDan Willemsen // Obtain a pre-allocated scratch buffer. 40*1c12ee1eSDan Willemsen p := messageFieldPool.Get().(*[]messageField) 41*1c12ee1eSDan Willemsen fields := (*p)[:0] 42*1c12ee1eSDan Willemsen defer func() { 43*1c12ee1eSDan Willemsen if cap(fields) < 1024 { 44*1c12ee1eSDan Willemsen *p = fields 45*1c12ee1eSDan Willemsen messageFieldPool.Put(p) 46*1c12ee1eSDan Willemsen } 47*1c12ee1eSDan Willemsen }() 48*1c12ee1eSDan Willemsen 49*1c12ee1eSDan Willemsen // Collect all fields in the message and sort them. 50*1c12ee1eSDan Willemsen fs.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { 51*1c12ee1eSDan Willemsen fields = append(fields, messageField{fd, v}) 52*1c12ee1eSDan Willemsen return true 53*1c12ee1eSDan Willemsen }) 54*1c12ee1eSDan Willemsen sort.Slice(fields, func(i, j int) bool { 55*1c12ee1eSDan Willemsen return less(fields[i].fd, fields[j].fd) 56*1c12ee1eSDan Willemsen }) 57*1c12ee1eSDan Willemsen 58*1c12ee1eSDan Willemsen // Visit the fields in the specified ordering. 59*1c12ee1eSDan Willemsen for _, f := range fields { 60*1c12ee1eSDan Willemsen if !fn(f.fd, f.v) { 61*1c12ee1eSDan Willemsen return 62*1c12ee1eSDan Willemsen } 63*1c12ee1eSDan Willemsen } 64*1c12ee1eSDan Willemsen} 65*1c12ee1eSDan Willemsen 66*1c12ee1eSDan Willemsentype mapEntry struct { 67*1c12ee1eSDan Willemsen k protoreflect.MapKey 68*1c12ee1eSDan Willemsen v protoreflect.Value 69*1c12ee1eSDan Willemsen} 70*1c12ee1eSDan Willemsen 71*1c12ee1eSDan Willemsenvar mapEntryPool = sync.Pool{ 72*1c12ee1eSDan Willemsen New: func() interface{} { return new([]mapEntry) }, 73*1c12ee1eSDan Willemsen} 74*1c12ee1eSDan Willemsen 75*1c12ee1eSDan Willemsentype ( 76*1c12ee1eSDan Willemsen // EntryRanger is an interface for visiting all fields in a message. 77*1c12ee1eSDan Willemsen // The protoreflect.Map type implements this interface. 78*1c12ee1eSDan Willemsen EntryRanger interface{ Range(VisitEntry) } 79*1c12ee1eSDan Willemsen // VisitEntry is called every time a map entry is visited. 80*1c12ee1eSDan Willemsen VisitEntry = func(protoreflect.MapKey, protoreflect.Value) bool 81*1c12ee1eSDan Willemsen) 82*1c12ee1eSDan Willemsen 83*1c12ee1eSDan Willemsen// RangeEntries iterates over the entries of es according to the specified order. 84*1c12ee1eSDan Willemsenfunc RangeEntries(es EntryRanger, less KeyOrder, fn VisitEntry) { 85*1c12ee1eSDan Willemsen if less == nil { 86*1c12ee1eSDan Willemsen es.Range(fn) 87*1c12ee1eSDan Willemsen return 88*1c12ee1eSDan Willemsen } 89*1c12ee1eSDan Willemsen 90*1c12ee1eSDan Willemsen // Obtain a pre-allocated scratch buffer. 91*1c12ee1eSDan Willemsen p := mapEntryPool.Get().(*[]mapEntry) 92*1c12ee1eSDan Willemsen entries := (*p)[:0] 93*1c12ee1eSDan Willemsen defer func() { 94*1c12ee1eSDan Willemsen if cap(entries) < 1024 { 95*1c12ee1eSDan Willemsen *p = entries 96*1c12ee1eSDan Willemsen mapEntryPool.Put(p) 97*1c12ee1eSDan Willemsen } 98*1c12ee1eSDan Willemsen }() 99*1c12ee1eSDan Willemsen 100*1c12ee1eSDan Willemsen // Collect all entries in the map and sort them. 101*1c12ee1eSDan Willemsen es.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool { 102*1c12ee1eSDan Willemsen entries = append(entries, mapEntry{k, v}) 103*1c12ee1eSDan Willemsen return true 104*1c12ee1eSDan Willemsen }) 105*1c12ee1eSDan Willemsen sort.Slice(entries, func(i, j int) bool { 106*1c12ee1eSDan Willemsen return less(entries[i].k, entries[j].k) 107*1c12ee1eSDan Willemsen }) 108*1c12ee1eSDan Willemsen 109*1c12ee1eSDan Willemsen // Visit the entries in the specified ordering. 110*1c12ee1eSDan Willemsen for _, e := range entries { 111*1c12ee1eSDan Willemsen if !fn(e.k, e.v) { 112*1c12ee1eSDan Willemsen return 113*1c12ee1eSDan Willemsen } 114*1c12ee1eSDan Willemsen } 115*1c12ee1eSDan Willemsen} 116