github.com/cloudwego/frugal@v0.1.15/internal/binary/defs/resolver.go (about) 1 /* 2 * Copyright 2022 ByteDance Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package defs 18 19 import ( 20 `fmt` 21 `math/bits` 22 `reflect` 23 `sort` 24 `strconv` 25 `strings` 26 `sync` 27 ) 28 29 type ( 30 Options uint8 31 Requiredness uint8 32 ) 33 34 const ( 35 NoCopy Options = 1 << iota 36 ) 37 38 const ( 39 Default Requiredness = iota 40 Required 41 Optional 42 ) 43 44 func (self Options) String() string { 45 nb := bits.OnesCount8(uint8(self)) 46 ret := make([]string, 0, nb) 47 48 /* check for "nocopy" option */ 49 if self & NoCopy != 0 { 50 ret = append(ret, "nocopy") 51 } 52 53 /* join them together */ 54 return fmt.Sprintf( 55 "{%s}", 56 strings.Join(ret, ","), 57 ) 58 } 59 60 func (self Requiredness) String() string { 61 switch self { 62 case Default : return "default" 63 case Required : return "required" 64 case Optional : return "optional" 65 default : panic("unreachable") 66 } 67 } 68 69 type Field struct { 70 F int 71 ID uint16 72 Type *Type 73 Opts Options 74 Spec Requiredness 75 Default reflect.Value 76 } 77 78 var ( 79 fieldsLock = new(sync.RWMutex) 80 fieldsCache = make(map[reflect.Type][]Field) 81 ) 82 83 func ResolveFields(vt reflect.Type) ([]Field, error) { 84 var ok bool 85 var ex error 86 var fv []Field 87 88 /* attempt to find in cache */ 89 fieldsLock.RLock() 90 fv, ok = fieldsCache[vt] 91 fieldsLock.RUnlock() 92 93 /* check if it exists */ 94 if ok { 95 return fv, nil 96 } 97 98 /* retry with write lock */ 99 fieldsLock.Lock() 100 defer fieldsLock.Unlock() 101 102 /* try again */ 103 if fv, ok = fieldsCache[vt]; ok { 104 return fv, nil 105 } 106 107 /* still not found, do the actual resolving */ 108 if fv, ex = doResolveFields(vt); ex != nil { 109 return nil, ex 110 } 111 112 /* update cache */ 113 fieldsCache[vt] = fv 114 return fv, nil 115 } 116 117 func doResolveFields(vt reflect.Type) ([]Field, error) { 118 var err error 119 var ret []Field 120 var mem reflect.Value 121 122 /* field ID map and default values */ 123 val := reflect.New(vt) 124 ids := make(map[uint64]struct{}, vt.NumField()) 125 126 /* check for default values */ 127 if def, ok := val.Interface().(DefaultInitializer); ok { 128 mem = val.Elem() 129 def.InitDefault() 130 } 131 132 /* traverse all the fields */ 133 for i := 0; i < vt.NumField(); i++ { 134 var ok bool 135 var pt *Type 136 var id uint64 137 var tv string 138 var fv Options 139 var ft []string 140 var rx Requiredness 141 var rv reflect.Value 142 var sf reflect.StructField 143 144 /* extract the field, ignore anonymous or private fields */ 145 if sf = vt.Field(i); sf.Anonymous || sf.PkgPath != "" { 146 continue 147 } 148 149 /* ignore fields that does not declare the "frugal" tag */ 150 if tv, ok = sf.Tag.Lookup("frugal"); !ok { 151 continue 152 } 153 154 /* must have at least 2 fields: ID and Requiredness */ 155 if ft = strings.Split(tv, ","); len(ft) < 2 { 156 return nil, fmt.Errorf("invalid tag for field %s.%s", vt, sf.Name) 157 } 158 159 /* parse the field index */ 160 if id, err = strconv.ParseUint(strings.TrimSpace(ft[0]), 10, 16); err != nil { 161 return nil, fmt.Errorf("invalid field number for field %s.%s: %w", vt, sf.Name, err) 162 } 163 164 /* convert the requiredness of this field */ 165 switch strings.TrimSpace(ft[1]) { 166 case "default" : rx = Default 167 case "required" : rx = Required 168 case "optional" : rx = Optional 169 default : return nil, fmt.Errorf("invalid requiredness for field %s.%s", vt, sf.Name) 170 } 171 172 /* check for duplicates */ 173 if _, ok = ids[id]; !ok { 174 ids[id] = struct{}{} 175 } else { 176 return nil, fmt.Errorf("duplicated field ID %d for field %s.%s", id, vt, sf.Name) 177 } 178 179 /* types and other options are optional */ 180 if len(ft) == 2 { 181 tv, ft = "", nil 182 } else { 183 tv, ft = strings.TrimSpace(ft[2]), ft[3:] 184 } 185 186 /* parse the type descriptor */ 187 if pt, err = ParseType(sf.Type, tv); err != nil { 188 return nil, fmt.Errorf("cannot parse type descriptor: %w", err) 189 } 190 191 /* only optional fields or structs can be pointers */ 192 if rx != Optional && pt.T == T_pointer && pt.V.T != T_struct { 193 return nil, fmt.Errorf("only optional fields or structs can be pointers, not %s: %s.%s", sf.Type, vt, sf.Name) 194 } 195 196 /* scan for the options */ 197 for _, opt := range ft { 198 switch opt { 199 default: { 200 return nil, fmt.Errorf("invalid option: %s", opt) 201 } 202 203 /* "nocopy" option enables zero-copy string decoding */ 204 case "nocopy": { 205 if pt.Tag() != T_string { 206 return nil, fmt.Errorf(`"nocopy" is only applicable to "string" and "binary" types, not %s`, pt) 207 } else if fv & NoCopy != 0 { 208 return nil, fmt.Errorf(`duplicated option "nocopy" for field %s.%s`, vt, sf.Name) 209 } else { 210 fv |= NoCopy 211 } 212 } 213 } 214 } 215 216 /* get the default value if any */ 217 if mem.IsValid() { 218 rv = mem.FieldByIndex(sf.Index) 219 } 220 221 /* add to result */ 222 ret = append(ret, Field { 223 F : int(sf.Offset), 224 ID : uint16(id), 225 Type : pt, 226 Opts : fv, 227 Spec : rx, 228 Default : rv, 229 }) 230 } 231 232 /* sort the field by ID */ 233 sort.Slice(ret, func(i, j int) bool { return ret[i].ID < ret[j].ID }) 234 return ret, nil 235 }