src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

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 }