github.com/RomiChan/protobuf@v0.1.1-0.20230204044148-2ed269a2e54d/proto/struct.go (about) 1 package proto 2 3 import ( 4 "fmt" 5 "io" 6 "strconv" 7 "strings" 8 "unsafe" 9 ) 10 11 type structInfo struct { 12 fields []*structField 13 fieldIndex map[fieldNumber]*structField 14 } 15 16 type structField struct { 17 offset uintptr 18 wiretag uint64 19 codec *codec 20 tagsize int 21 } 22 23 func (f *structField) fieldNumber() fieldNumber { 24 return fieldNumber(f.wiretag >> 3) 25 } 26 27 func (f *structField) wireType() wireType { 28 return wireType(f.wiretag & 7) 29 } 30 31 func (f *structField) pointer(p unsafe.Pointer) unsafe.Pointer { 32 return unsafe.Pointer(uintptr(p) + f.offset) 33 } 34 35 func (info *structInfo) size(p unsafe.Pointer) int { 36 if p == nil { 37 return 0 38 } 39 n := 0 40 for _, f := range info.fields { 41 n += f.codec.size(f.pointer(p), f) 42 } 43 return n 44 } 45 46 func (info *structInfo) encode(b []byte, p unsafe.Pointer) []byte { 47 if p == nil { 48 return b 49 } 50 for _, f := range info.fields { 51 b = f.codec.encode(b, f.pointer(p), f) 52 } 53 return b 54 } 55 56 func (info *structInfo) decode(b []byte, p unsafe.Pointer) (int, error) { 57 offset := 0 58 for offset < len(b) { 59 fieldNumber, wireType, n, err := decodeTag(b[offset:]) 60 offset += n 61 if err != nil { 62 return offset, err 63 } 64 65 f := info.fieldIndex[fieldNumber] 66 if f == nil { 67 skip := 0 68 size := uint64(0) 69 switch wireType { 70 case varint: 71 _, skip, err = decodeVarint(b[offset:]) 72 case varlen: 73 size, skip, err = decodeVarint(b[offset:]) 74 if err == nil { 75 if size > uint64(len(b)-skip) { 76 err = io.ErrUnexpectedEOF 77 } else { 78 skip += int(size) 79 } 80 } 81 case fixed32: 82 skip = 4 83 case fixed64: 84 skip = 8 85 default: 86 err = ErrWireTypeUnknown 87 } 88 if (offset + skip) <= len(b) { 89 offset += skip 90 } else { 91 offset, err = len(b), io.ErrUnexpectedEOF 92 } 93 if err != nil { 94 return offset, fieldError(fieldNumber, wireType, err) 95 } 96 continue 97 } 98 99 if wireType != f.wireType() { 100 return offset, fieldError(fieldNumber, wireType, fmt.Errorf("expected wire type %d", f.wireType())) 101 } 102 103 // `data` will only contain the section of the input buffer where 104 // the data for the next field is available. This is necessary to 105 // limit how many bytes will be consumed by embedded messages. 106 var data []byte 107 switch wireType { 108 case varint: 109 _, n, err := decodeVarint(b[offset:]) 110 if err != nil { 111 return offset, fieldError(fieldNumber, wireType, err) 112 } 113 data = b[offset : offset+n] 114 115 case varlen: 116 l, n, err := decodeVarint(b[offset:]) 117 if err != nil { 118 return offset + n, fieldError(fieldNumber, wireType, err) 119 } 120 if l > uint64(len(b)-(offset+n)) { 121 return len(b), fieldError(fieldNumber, wireType, io.ErrUnexpectedEOF) 122 } 123 data = b[offset : offset+n+int(l)] 124 125 case fixed32: 126 if (offset + 4) > len(b) { 127 return len(b), fieldError(fieldNumber, wireType, io.ErrUnexpectedEOF) 128 } 129 data = b[offset : offset+4] 130 131 case fixed64: 132 if (offset + 8) > len(b) { 133 return len(b), fieldError(fieldNumber, wireType, io.ErrUnexpectedEOF) 134 } 135 data = b[offset : offset+8] 136 137 default: 138 return offset, fieldError(fieldNumber, wireType, ErrWireTypeUnknown) 139 } 140 141 n, err = f.codec.decode(data, f.pointer(p)) 142 offset += n 143 if err != nil { 144 return offset, fieldError(fieldNumber, wireType, err) 145 } 146 } 147 148 return offset, nil 149 } 150 151 type structTag struct { 152 // version int 153 wireType wireType 154 fieldNumber fieldNumber 155 repeated bool 156 zigzag bool 157 } 158 159 func parseStructTag(tag string) (structTag, error) { 160 t := structTag{ 161 // version: 2, 162 } 163 164 for i, f := range splitFields(tag) { 165 switch i { 166 case 0: 167 switch f { 168 case "varint": 169 t.wireType = varint 170 case "bytes": 171 t.wireType = varlen 172 case "fixed32": 173 t.wireType = fixed32 174 case "fixed64": 175 t.wireType = fixed64 176 case "zigzag32": 177 t.wireType = varint 178 t.zigzag = true 179 case "zigzag64": 180 t.wireType = varint 181 t.zigzag = true 182 default: 183 return t, fmt.Errorf("unsupported wire type in struct tag %q: %s", tag, f) 184 } 185 186 case 1: 187 n, err := strconv.Atoi(f) 188 if err != nil { 189 return t, fmt.Errorf("unsupported field number in struct tag %q: %w", tag, err) 190 } 191 t.fieldNumber = fieldNumber(n) 192 193 case 2: 194 switch f { 195 case "opt": 196 // not sure what this is for 197 case "rep": 198 t.repeated = true 199 default: 200 return t, fmt.Errorf("unsupported field option in struct tag %q: %s", tag, f) 201 } 202 203 default: 204 /* 205 name, value := splitNameValue(f) 206 switch name { 207 case "name": 208 t.name = value 209 case "enum": 210 t.enum = value 211 case "json": 212 t.json = value 213 case "proto3": 214 t.version = 3 215 default: 216 t.extensions[name] = value 217 } 218 */ 219 } 220 } 221 222 return t, nil 223 } 224 225 func splitFields(s string) []string { 226 return strings.Split(s, ",") 227 } 228 229 /* 230 func splitNameValue(s string) (name, value string) { 231 i := strings.IndexByte(s, '=') 232 if i < 0 { 233 return strings.TrimSpace(s), "" 234 } else { 235 return strings.TrimSpace(s[:i]), strings.TrimSpace(s[i+1:]) 236 } 237 } 238 */