helpers.go raw
1 // Package easyjson contains marshaler/unmarshaler interfaces and helper functions.
2 package easyjson
3
4 import (
5 "io"
6 "io/ioutil"
7 "net/http"
8 "strconv"
9 "unsafe"
10
11 "github.com/mailru/easyjson/jlexer"
12 "github.com/mailru/easyjson/jwriter"
13 )
14
15 // Marshaler is an easyjson-compatible marshaler interface.
16 type Marshaler interface {
17 MarshalEasyJSON(w *jwriter.Writer)
18 }
19
20 // Unmarshaler is an easyjson-compatible unmarshaler interface.
21 type Unmarshaler interface {
22 UnmarshalEasyJSON(w *jlexer.Lexer)
23 }
24
25 // MarshalerUnmarshaler is an easyjson-compatible marshaler/unmarshaler interface.
26 type MarshalerUnmarshaler interface {
27 Marshaler
28 Unmarshaler
29 }
30
31 // Optional defines an undefined-test method for a type to integrate with 'omitempty' logic.
32 type Optional interface {
33 IsDefined() bool
34 }
35
36 // UnknownsUnmarshaler provides a method to unmarshal unknown struct fileds and save them as you want
37 type UnknownsUnmarshaler interface {
38 UnmarshalUnknown(in *jlexer.Lexer, key string)
39 }
40
41 // UnknownsMarshaler provides a method to write additional struct fields
42 type UnknownsMarshaler interface {
43 MarshalUnknowns(w *jwriter.Writer, first bool)
44 }
45
46 func isNilInterface(i interface{}) bool {
47 return (*[2]uintptr)(unsafe.Pointer(&i))[1] == 0
48 }
49
50 // Marshal returns data as a single byte slice. Method is suboptimal as the data is likely to be copied
51 // from a chain of smaller chunks.
52 func Marshal(v Marshaler) ([]byte, error) {
53 if isNilInterface(v) {
54 return nullBytes, nil
55 }
56
57 w := jwriter.Writer{}
58 v.MarshalEasyJSON(&w)
59 return w.BuildBytes()
60 }
61
62 // MarshalToWriter marshals the data to an io.Writer.
63 func MarshalToWriter(v Marshaler, w io.Writer) (written int, err error) {
64 if isNilInterface(v) {
65 return w.Write(nullBytes)
66 }
67
68 jw := jwriter.Writer{}
69 v.MarshalEasyJSON(&jw)
70 return jw.DumpTo(w)
71 }
72
73 // MarshalToHTTPResponseWriter sets Content-Length and Content-Type headers for the
74 // http.ResponseWriter, and send the data to the writer. started will be equal to
75 // false if an error occurred before any http.ResponseWriter methods were actually
76 // invoked (in this case a 500 reply is possible).
77 func MarshalToHTTPResponseWriter(v Marshaler, w http.ResponseWriter) (started bool, written int, err error) {
78 if isNilInterface(v) {
79 w.Header().Set("Content-Type", "application/json")
80 w.Header().Set("Content-Length", strconv.Itoa(len(nullBytes)))
81 written, err = w.Write(nullBytes)
82 return true, written, err
83 }
84
85 jw := jwriter.Writer{}
86 v.MarshalEasyJSON(&jw)
87 if jw.Error != nil {
88 return false, 0, jw.Error
89 }
90 w.Header().Set("Content-Type", "application/json")
91 w.Header().Set("Content-Length", strconv.Itoa(jw.Size()))
92
93 started = true
94 written, err = jw.DumpTo(w)
95 return
96 }
97
98 // Unmarshal decodes the JSON in data into the object.
99 func Unmarshal(data []byte, v Unmarshaler) error {
100 l := jlexer.Lexer{Data: data}
101 v.UnmarshalEasyJSON(&l)
102 return l.Error()
103 }
104
105 // UnmarshalFromReader reads all the data in the reader and decodes as JSON into the object.
106 func UnmarshalFromReader(r io.Reader, v Unmarshaler) error {
107 data, err := ioutil.ReadAll(r)
108 if err != nil {
109 return err
110 }
111 l := jlexer.Lexer{Data: data}
112 v.UnmarshalEasyJSON(&l)
113 return l.Error()
114 }
115