unmarshalStruct decodes a JSON object into the struct pointed to by v, enforcing object-kind, required-field, and non-nullable-field strictness as declared by lsp struct tags. Up to 64 required fields are supported.
(v any, dec *json.Decoder)
| 72 | // enforcing object-kind, required-field, and non-nullable-field strictness as |
| 73 | // declared by lsp struct tags. Up to 64 required fields are supported. |
| 74 | func unmarshalStruct(v any, dec *json.Decoder) error { |
| 75 | rv := reflect.ValueOf(v).Elem() |
| 76 | spec := specFor(rv.Type()) |
| 77 | |
| 78 | if k := dec.PeekKind(); k != '{' { |
| 79 | return errNotObject(k) |
| 80 | } |
| 81 | if _, err := dec.ReadToken(); err != nil { |
| 82 | return err |
| 83 | } |
| 84 | |
| 85 | var seen uint64 |
| 86 | for dec.PeekKind() != '}' { |
| 87 | name, err := dec.ReadValue() |
| 88 | if err != nil { |
| 89 | return err |
| 90 | } |
| 91 | // name includes surrounding quotes; m[string(b)] is a no-alloc lookup. |
| 92 | fs, ok := spec.byName[string(name[1:len(name)-1])] |
| 93 | if !ok { |
| 94 | if err := dec.SkipValue(); err != nil { |
| 95 | return err |
| 96 | } |
| 97 | continue |
| 98 | } |
| 99 | if fs.requiredID >= 0 { |
| 100 | seen |= 1 << fs.requiredID |
| 101 | } |
| 102 | if fs.rejectNull && dec.PeekKind() == 'n' { |
| 103 | return errNull(string(name[1 : len(name)-1])) |
| 104 | } |
| 105 | if err := json.UnmarshalDecode(dec, rv.Field(fs.index).Addr().Interface()); err != nil { |
| 106 | return err |
| 107 | } |
| 108 | } |
| 109 | if _, err := dec.ReadToken(); err != nil { |
| 110 | return err |
| 111 | } |
| 112 | |
| 113 | if missing := spec.requiredMask &^ seen; missing != 0 { |
| 114 | var missingProps []string |
| 115 | for id, n := range spec.requiredNames { |
| 116 | if missing&(1<<id) != 0 { |
| 117 | missingProps = append(missingProps, n) |
| 118 | } |
| 119 | } |
| 120 | return errMissing(missingProps) |
| 121 | } |
| 122 | return nil |
| 123 | } |
| 124 | |
| 125 | // marshalUnion encodes a union struct whose fields are all pointers, exactly |
| 126 | // one of which is set. It writes the single non-nil field; if nullable, an |
no test coverage detected