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