github.com/facebookincubator/go-belt@v0.0.0-20230703220935-39cd348f1a38/pkg/field/abstract_fields.go (about) 1 // Copyright 2022 Meta Platforms, Inc. and affiliates. 2 // 3 // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 // 5 // 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 // 7 // 2. 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. 8 // 9 // 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 // 11 // 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 HOLDER 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. 12 13 package field 14 15 // ForEachFieldser is an iterator through a collection of fields. 16 // 17 // Any object which implements this interface may be used as a source 18 // of fields. For example a generic parser of field values in a Logger 19 // checks if a value implements this interface, and if does, then 20 // it is used to provide the fields instead of using a generic method. 21 type ForEachFieldser interface { 22 // ForEachField iterates through all the fields, until first false is returned. 23 // 24 // WARNING! This callback is supposed to be used only to read 25 // the field content, but not to hold the pointer to the field itself. 26 // For the purposes of performance optimizations it is assumed 27 // that the pointer is not escapable. If it is required to store 28 // the pointer to the field after `callback` returned then copy the field. 29 // Otherwise Go's memory guarantees are broken. 30 ForEachField(callback func(f *Field) bool) bool 31 } 32 33 // AbstractFields is an abstraction of any types of collections of fields. 34 type AbstractFields interface { 35 ForEachFieldser 36 Len() int 37 } 38 39 // Slice is a collection of collections of fields. 40 type Slice[T AbstractFields] []T 41 42 // Len implements AbstractFields. 43 func (s Slice[T]) Len() int { 44 count := 0 45 for _, items := range s { 46 count += items.Len() 47 } 48 return count 49 } 50 51 // ForEachField implements AbstractFields. 52 func (s Slice[T]) ForEachField(callback func(f *Field) bool) bool { 53 for _, items := range s { 54 if !items.ForEachField(callback) { 55 return false 56 } 57 } 58 return true 59 } 60 61 // Slicer implements AbstractFields providing a subset of fields (reported through 62 // method ForEachField of the initial collection). 63 type Slicer[T AbstractFields] struct { 64 All T 65 StartIdx uint 66 EndIdx uint 67 } 68 69 var _ AbstractFields = (*Slicer[AbstractFields])(nil) 70 71 // Len implements AbstractFields. 72 func (s *Slicer[T]) Len() int { 73 count := 0 74 s.ForEachField(func(f *Field) bool { 75 count++ 76 return true 77 }) 78 return count 79 } 80 81 // ForEachField implements AbstractFields. 82 func (s *Slicer[T]) ForEachField(callback func(f *Field) bool) bool { 83 idx := uint(0) 84 return s.All.ForEachField(func(f *Field) bool { 85 if idx >= s.EndIdx { 86 return false 87 } 88 if idx >= s.StartIdx { 89 if !callback(f) { 90 return false 91 } 92 } 93 idx++ 94 return true 95 }) 96 } 97 98 // NewSlicer provides a subset of fields (reported through method ForEachField of the initial collection). 99 func NewSlicer[T AbstractFields](all T, startIdx, endIdx uint) *Slicer[T] { 100 return &Slicer[T]{ 101 All: all, 102 StartIdx: startIdx, 103 EndIdx: endIdx, 104 } 105 } 106 107 // Gather copies all the fields into a slice and returns it. 108 func Gather[T AbstractFields](fields T) Fields { 109 result := make(Fields, 0, fields.Len()) 110 fields.ForEachField(func(field *Field) bool { 111 result = append(result, *field) 112 return true 113 }) 114 return result 115 }