File: marshaler.go

package info (click to toggle)
golang-github-facebook-ent 0.5.4-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 14,284 kB
  • sloc: javascript: 349; makefile: 8
file content (134 lines) | stat: -rw-r--r-- 3,589 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright 2019-present Facebook Inc. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.

package graphson

import (
	"fmt"
	"io"
	"unsafe"

	jsoniter "github.com/json-iterator/go"
	"github.com/modern-go/reflect2"
	"github.com/pkg/errors"
)

// DecoratorOfMarshaler decorates a value encoder of a Marshaler interface.
func (ext encodeExtension) DecoratorOfMarshaler(typ reflect2.Type, enc jsoniter.ValEncoder) jsoniter.ValEncoder {
	if typ == marshalerType {
		enc := marshalerEncoder{enc, typ}
		return directMarshalerEncoder{enc}
	}
	if typ.Implements(marshalerType) {
		return marshalerEncoder{enc, typ}
	}
	ptrType := reflect2.PtrTo(typ)
	if ptrType.Implements(marshalerType) {
		ptrEnc := ext.LazyEncoderOf(ptrType)
		enc := marshalerEncoder{ptrEnc, ptrType}
		return referenceEncoder{enc}
	}
	return nil
}

// DecoderOfUnmarshaler returns a value decoder of an Unmarshaler interface.
func (decodeExtension) DecoderOfUnmarshaler(typ reflect2.Type) jsoniter.ValDecoder {
	ptrType := reflect2.PtrTo(typ)
	if ptrType.Implements(unmarshalerType) {
		return referenceDecoder{
			unmarshalerDecoder{ptrType},
		}
	}
	return nil
}

// DecoratorOfUnmarshaler decorates a value encoder of an Unmarshaler interface.
func (decodeExtension) DecoratorOfUnmarshaler(typ reflect2.Type, dec jsoniter.ValDecoder) jsoniter.ValDecoder {
	if reflect2.PtrTo(typ).Implements(unmarshalerType) {
		return dec
	}
	return nil
}

var (
	marshalerType   = reflect2.TypeOfPtr((*Marshaler)(nil)).Elem()
	unmarshalerType = reflect2.TypeOfPtr((*Unmarshaler)(nil)).Elem()
)

type marshalerEncoder struct {
	jsoniter.ValEncoder
	reflect2.Type
}

func (enc marshalerEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
	marshaler := enc.Type.UnsafeIndirect(ptr).(Marshaler)
	enc.encode(marshaler, stream)
}

func (enc marshalerEncoder) encode(marshaler Marshaler, stream *jsoniter.Stream) {
	data, err := marshaler.MarshalGraphson()
	if err != nil {
		stream.Error = errors.Wrapf(err, "graphson: error calling MarshalGraphson for type %s", enc.Type)
		return
	}
	if !config.Valid(data) {
		stream.Error = errors.Errorf("graphson: syntax error when marshaling type %s", enc.Type)
		return
	}
	_, stream.Error = stream.Write(data)
}

type directMarshalerEncoder struct {
	marshalerEncoder
}

func (enc directMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
	marshaler := *(*Marshaler)(ptr)
	enc.encode(marshaler, stream)
}

type referenceEncoder struct {
	jsoniter.ValEncoder
}

func (enc referenceEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
	// nolint: gas
	enc.ValEncoder.Encode(unsafe.Pointer(&ptr), stream)
}

func (enc referenceEncoder) IsEmpty(ptr unsafe.Pointer) bool {
	// nolint: gas
	return enc.ValEncoder.IsEmpty(unsafe.Pointer(&ptr))
}

type unmarshalerDecoder struct {
	reflect2.Type
}

func (dec unmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
	bytes := iter.SkipAndReturnBytes()
	if iter.Error != nil && iter.Error != io.EOF {
		return
	}

	unmarshaler := dec.UnsafeIndirect(ptr).(Unmarshaler)
	if err := unmarshaler.UnmarshalGraphson(bytes); err != nil {
		iter.ReportError(
			"unmarshal graphson",
			fmt.Sprintf(
				"graphson: error calling UnmarshalGraphson for type %s: %s",
				dec.Type, err,
			),
		)
	}
}

type referenceDecoder struct {
	jsoniter.ValDecoder
}

func (dec referenceDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
	// nolint: gas
	dec.ValDecoder.Decode(unsafe.Pointer(&ptr), iter)
}