deserializer.go (6718B)
1 package eventstream 2 3 import ( 4 "fmt" 5 "math/big" 6 "time" 7 8 "github.com/aws/smithy-go" 9 "github.com/aws/smithy-go/document" 10 "github.com/aws/smithy-go/traits" 11 ) 12 13 // ShapeDeserializer wraps a [smithy.ShapeDeserializer] to handle event stream 14 // message binding traits. 15 type ShapeDeserializer struct { 16 Message *Message 17 18 inner smithy.ShapeDeserializer 19 20 depth int 21 schema *smithy.Schema 22 23 bindings []*smithy.Schema 24 bindIdx int 25 inBindings bool 26 27 inBody bool 28 hasPayload bool 29 hasBody bool 30 } 31 32 var _ smithy.ShapeDeserializer = (*ShapeDeserializer)(nil) 33 34 // NewShapeDeserializer returns a deserializer for a Message. 35 func NewShapeDeserializer(msg *Message, inner smithy.ShapeDeserializer) *ShapeDeserializer { 36 return &ShapeDeserializer{ 37 Message: msg, 38 inner: inner, 39 } 40 } 41 42 func (d *ShapeDeserializer) ReadStruct(s *smithy.Schema) error { 43 d.depth++ 44 if d.depth > 1 { 45 return d.inner.ReadStruct(s) 46 } 47 d.schema = s 48 for _, m := range s.Members() { 49 if _, ok := smithy.SchemaTrait[*traits.EventPayload](m); ok { 50 d.hasPayload = true 51 } 52 if isEventBound(m) { 53 d.bindings = append(d.bindings, m) 54 } else { 55 d.hasBody = true 56 } 57 } 58 return nil 59 } 60 61 func (d *ShapeDeserializer) ReadStructMember() (*smithy.Schema, error) { 62 if d.depth > 1 { 63 ms, err := d.inner.ReadStructMember() 64 if ms == nil { 65 d.depth-- 66 } 67 return ms, err 68 } 69 70 // like httpbinding, throw back the bound stuff first before we drop into 71 // the body 72 for d.bindIdx < len(d.bindings) { 73 m := d.bindings[d.bindIdx] 74 d.bindIdx++ 75 if isEventHeader(m) && d.Message.Headers.Get(m.MemberName()) == nil { 76 continue 77 } 78 d.inBindings = true 79 return m, nil 80 } 81 d.inBindings = false 82 83 if d.hasPayload { 84 d.depth-- 85 return nil, nil 86 } 87 88 if !d.hasBody { 89 d.depth-- 90 return nil, nil 91 } 92 93 if !d.inBody { 94 d.inBody = true 95 if err := d.inner.ReadStruct(d.schema); err != nil { 96 return nil, err 97 } 98 } 99 100 ms, err := d.inner.ReadStructMember() 101 if ms == nil { 102 d.depth-- 103 } 104 105 return ms, err 106 } 107 108 func (d *ShapeDeserializer) ReadString(s *smithy.Schema, v *string) error { 109 if d.inBindings { 110 if isEventHeader(s) { 111 hv := d.Message.Headers.Get(s.MemberName()) 112 if hv == nil { 113 return nil 114 } 115 sv, ok := hv.(StringValue) 116 if !ok { 117 return fmt.Errorf("event header %q: expected string, got %T", s.MemberName(), hv) 118 } 119 *v = string(sv) 120 return nil 121 } 122 if isEventPayload(s) { 123 *v = string(d.Message.Payload) 124 return nil 125 } 126 } 127 return d.inner.ReadString(s, v) 128 } 129 130 func (d *ShapeDeserializer) ReadBool(s *smithy.Schema, v *bool) error { 131 if d.inBindings && isEventHeader(s) { 132 hv := d.Message.Headers.Get(s.MemberName()) 133 if hv == nil { 134 return nil 135 } 136 bv, ok := hv.(BoolValue) 137 if !ok { 138 return fmt.Errorf("event header %q: expected bool, got %T", s.MemberName(), hv) 139 } 140 *v = bool(bv) 141 return nil 142 } 143 return d.inner.ReadBool(s, v) 144 } 145 146 func (d *ShapeDeserializer) readHeaderInt64(name string) (int64, bool, error) { 147 hv := d.Message.Headers.Get(name) 148 if hv == nil { 149 return 0, false, nil 150 } 151 switch v := hv.(type) { 152 case Int8Value: 153 return int64(v), true, nil 154 case Int16Value: 155 return int64(v), true, nil 156 case Int32Value: 157 return int64(v), true, nil 158 case Int64Value: 159 return int64(v), true, nil 160 default: 161 return 0, false, fmt.Errorf("event header %q: expected integer, got %T", name, hv) 162 } 163 } 164 165 type intn interface { 166 int8 | int16 | int32 | int64 167 } 168 169 func readEventHeaderInt[T intn](d *ShapeDeserializer, s *smithy.Schema, v *T) error { 170 n, ok, err := d.readHeaderInt64(s.MemberName()) 171 if err != nil || !ok { 172 return err 173 } 174 *v = T(n) 175 return nil 176 } 177 178 func (d *ShapeDeserializer) ReadInt8(s *smithy.Schema, v *int8) error { 179 if d.inBindings && isEventHeader(s) { 180 return readEventHeaderInt(d, s, v) 181 } 182 return d.inner.ReadInt8(s, v) 183 } 184 185 func (d *ShapeDeserializer) ReadInt16(s *smithy.Schema, v *int16) error { 186 if d.inBindings && isEventHeader(s) { 187 return readEventHeaderInt(d, s, v) 188 } 189 return d.inner.ReadInt16(s, v) 190 } 191 192 func (d *ShapeDeserializer) ReadInt32(s *smithy.Schema, v *int32) error { 193 if d.inBindings && isEventHeader(s) { 194 return readEventHeaderInt(d, s, v) 195 } 196 return d.inner.ReadInt32(s, v) 197 } 198 199 func (d *ShapeDeserializer) ReadInt64(s *smithy.Schema, v *int64) error { 200 if d.inBindings && isEventHeader(s) { 201 return readEventHeaderInt(d, s, v) 202 } 203 return d.inner.ReadInt64(s, v) 204 } 205 206 func (d *ShapeDeserializer) ReadFloat32(s *smithy.Schema, v *float32) error { 207 return d.inner.ReadFloat32(s, v) 208 } 209 210 func (d *ShapeDeserializer) ReadFloat64(s *smithy.Schema, v *float64) error { 211 return d.inner.ReadFloat64(s, v) 212 } 213 214 func (d *ShapeDeserializer) ReadBlob(s *smithy.Schema, v *[]byte) error { 215 if d.inBindings { 216 if isEventHeader(s) { 217 hv := d.Message.Headers.Get(s.MemberName()) 218 if hv == nil { 219 return nil 220 } 221 bv, ok := hv.(BytesValue) 222 if !ok { 223 return fmt.Errorf("event header %q: expected bytes, got %T", s.MemberName(), hv) 224 } 225 *v = []byte(bv) 226 return nil 227 } 228 if isEventPayload(s) { 229 *v = d.Message.Payload 230 return nil 231 } 232 } 233 return d.inner.ReadBlob(s, v) 234 } 235 236 func (d *ShapeDeserializer) ReadTime(s *smithy.Schema, v *time.Time) error { 237 if d.inBindings && isEventHeader(s) { 238 hv := d.Message.Headers.Get(s.MemberName()) 239 if hv == nil { 240 return nil 241 } 242 tv, ok := hv.(TimestampValue) 243 if !ok { 244 return fmt.Errorf("event header %q: expected timestamp, got %T", s.MemberName(), hv) 245 } 246 *v = time.Time(tv) 247 return nil 248 } 249 return d.inner.ReadTime(s, v) 250 } 251 252 func (d *ShapeDeserializer) ReadList(s *smithy.Schema) error { 253 return d.inner.ReadList(s) 254 } 255 256 func (d *ShapeDeserializer) ReadListItem(s *smithy.Schema) (bool, error) { 257 return d.inner.ReadListItem(s) 258 } 259 260 func (d *ShapeDeserializer) ReadMap(s *smithy.Schema) error { 261 return d.inner.ReadMap(s) 262 } 263 264 func (d *ShapeDeserializer) ReadMapKey(s *smithy.Schema) (string, bool, error) { 265 return d.inner.ReadMapKey(s) 266 } 267 268 func (d *ShapeDeserializer) ReadUnion(s *smithy.Schema) (*smithy.Schema, error) { 269 return d.inner.ReadUnion(s) 270 } 271 272 func (d *ShapeDeserializer) ReadNil(s *smithy.Schema) (bool, error) { 273 return d.inner.ReadNil(s) 274 } 275 276 func (d *ShapeDeserializer) ReadDocument(s *smithy.Schema, v *document.Value) error { 277 return d.inner.ReadDocument(s, v) 278 } 279 280 func isEventBound(schema *smithy.Schema) bool { 281 _, h := smithy.SchemaTrait[*traits.EventHeader](schema) 282 _, p := smithy.SchemaTrait[*traits.EventPayload](schema) 283 return h || p 284 } 285 286 // ReadBigInt is unimplemented and will return an error. 287 func (d *ShapeDeserializer) ReadBigInt(_ *smithy.Schema, _ *big.Int) error { 288 return fmt.Errorf("unimplemented") 289 } 290 291 // ReadBigFloat is unimplemented and will return an error. 292 func (d *ShapeDeserializer) ReadBigFloat(_ *smithy.Schema, _ *big.Float) error { 293 return fmt.Errorf("unimplemented") 294 }