From 486534c67cde830affb4f605c170f653bc9f7511 Mon Sep 17 00:00:00 2001
From: Tao Wen <taowen@gmail.com>
Date: Tue, 20 Jun 2017 17:43:47 +0800
Subject: [PATCH] #67 time as int64

---
 extra/time_as_int64_codec.go      | 27 ++++++++++++++++++++++++++
 extra/time_as_int64_codec_test.go | 16 ++++++++++++++++
 feature_config.go                 |  6 +++---
 feature_reflect.go                |  6 +++---
 feature_reflect_array.go          |  2 +-
 feature_reflect_extension.go      |  2 +-
 feature_reflect_map.go            |  4 ++--
 feature_reflect_native.go         | 32 +++++++++++++++----------------
 feature_reflect_object.go         |  6 +++---
 feature_reflect_slice.go          |  2 +-
 jsoniter_customize_test.go        |  8 ++++----
 11 files changed, 77 insertions(+), 34 deletions(-)
 create mode 100644 extra/time_as_int64_codec.go
 create mode 100644 extra/time_as_int64_codec_test.go

diff --git a/extra/time_as_int64_codec.go b/extra/time_as_int64_codec.go
new file mode 100644
index 0000000..202c9ed
--- /dev/null
+++ b/extra/time_as_int64_codec.go
@@ -0,0 +1,27 @@
+package extra
+
+import (
+	"github.com/json-iterator/go"
+	"unsafe"
+	"time"
+)
+
+// keep epoch milliseconds
+func RegisterTimeAsInt64Codec() {
+	jsoniter.RegisterTypeEncoder("time.Time", &timeAsInt64Codec{})
+}
+
+type timeAsInt64Codec struct {
+}
+
+func (codec *timeAsInt64Codec) IsEmpty(ptr unsafe.Pointer) bool {
+	ts := *((*time.Time)(ptr))
+	return ts.UnixNano() == 0
+}
+func (codec *timeAsInt64Codec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
+	ts := *((*time.Time)(ptr))
+	stream.WriteInt64(ts.UnixNano())
+}
+func (codec *timeAsInt64Codec) EncodeInterface(val interface{}, stream *jsoniter.Stream) {
+	jsoniter.WriteToStream(val, stream, codec)
+}
diff --git a/extra/time_as_int64_codec_test.go b/extra/time_as_int64_codec_test.go
new file mode 100644
index 0000000..357685c
--- /dev/null
+++ b/extra/time_as_int64_codec_test.go
@@ -0,0 +1,16 @@
+package extra
+
+import (
+	"testing"
+	"time"
+	"github.com/json-iterator/go/require"
+	"github.com/json-iterator/go"
+)
+
+func Test_time_as_int64(t *testing.T) {
+	should := require.New(t)
+	RegisterTimeAsInt64Codec()
+	output, err := jsoniter.Marshal(time.Unix(1, 1002))
+	should.Nil(err)
+	should.Equal("1000001002", string(output))
+}
diff --git a/feature_config.go b/feature_config.go
index 5261621..7504ac0 100644
--- a/feature_config.go
+++ b/feature_config.go
@@ -96,7 +96,7 @@ func (encoder *lossyFloat32Encoder) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *lossyFloat32Encoder) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (encoder *lossyFloat32Encoder) IsEmpty(ptr unsafe.Pointer) bool {
@@ -111,7 +111,7 @@ func (encoder *lossyFloat64Encoder) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *lossyFloat64Encoder) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (encoder *lossyFloat64Encoder) IsEmpty(ptr unsafe.Pointer) bool {
@@ -135,7 +135,7 @@ func (encoder *htmlEscapedStringEncoder) Encode(ptr unsafe.Pointer, stream *Stre
 }
 
 func (encoder *htmlEscapedStringEncoder) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (encoder *htmlEscapedStringEncoder) IsEmpty(ptr unsafe.Pointer) bool {
diff --git a/feature_reflect.go b/feature_reflect.go
index 1400485..e01dc16 100644
--- a/feature_reflect.go
+++ b/feature_reflect.go
@@ -32,7 +32,7 @@ type ValEncoder interface {
 	EncodeInterface(val interface{}, stream *Stream)
 }
 
-func writeToStream(val interface{}, stream *Stream, encoder ValEncoder) {
+func WriteToStream(val interface{}, stream *Stream, encoder ValEncoder) {
 	e := (*emptyInterface)(unsafe.Pointer(&val))
 	if e.word == nil {
 		stream.WriteNil()
@@ -100,7 +100,7 @@ func (encoder *optionalEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *optionalEncoder) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (encoder *optionalEncoder) IsEmpty(ptr unsafe.Pointer) bool {
@@ -121,7 +121,7 @@ func (encoder *placeholderEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *placeholderEncoder) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (encoder *placeholderEncoder) IsEmpty(ptr unsafe.Pointer) bool {
diff --git a/feature_reflect_array.go b/feature_reflect_array.go
index bdfb868..727b654 100644
--- a/feature_reflect_array.go
+++ b/feature_reflect_array.go
@@ -52,7 +52,7 @@ func (encoder *arrayEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *arrayEncoder) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (encoder *arrayEncoder) IsEmpty(ptr unsafe.Pointer) bool {
diff --git a/feature_reflect_extension.go b/feature_reflect_extension.go
index 8cb0f5a..a637218 100644
--- a/feature_reflect_extension.go
+++ b/feature_reflect_extension.go
@@ -84,7 +84,7 @@ func (encoder *funcEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *funcEncoder) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (encoder *funcEncoder) IsEmpty(ptr unsafe.Pointer) bool {
diff --git a/feature_reflect_map.go b/feature_reflect_map.go
index 45c0373..6405b10 100644
--- a/feature_reflect_map.go
+++ b/feature_reflect_map.go
@@ -127,7 +127,7 @@ func encodeMapKey(key reflect.Value, stream *Stream) {
 }
 
 func (encoder *mapEncoder) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (encoder *mapEncoder) IsEmpty(ptr unsafe.Pointer) bool {
@@ -178,7 +178,7 @@ func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) }
 func (sv stringValues) get(i int) string   { return sv[i].String() }
 
 func (encoder *sortKeysMapEncoder) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (encoder *sortKeysMapEncoder) IsEmpty(ptr unsafe.Pointer) bool {
diff --git a/feature_reflect_native.go b/feature_reflect_native.go
index 14c5b38..b8e569b 100644
--- a/feature_reflect_native.go
+++ b/feature_reflect_native.go
@@ -19,7 +19,7 @@ func (codec *stringCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (codec *stringCodec) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, codec)
+	WriteToStream(val, stream, codec)
 }
 
 func (codec *stringCodec) IsEmpty(ptr unsafe.Pointer) bool {
@@ -38,7 +38,7 @@ func (codec *intCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *intCodec) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (codec *intCodec) IsEmpty(ptr unsafe.Pointer) bool {
@@ -57,7 +57,7 @@ func (codec *int8Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *int8Codec) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (codec *int8Codec) IsEmpty(ptr unsafe.Pointer) bool {
@@ -76,7 +76,7 @@ func (codec *int16Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *int16Codec) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (codec *int16Codec) IsEmpty(ptr unsafe.Pointer) bool {
@@ -95,7 +95,7 @@ func (codec *int32Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *int32Codec) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (codec *int32Codec) IsEmpty(ptr unsafe.Pointer) bool {
@@ -114,7 +114,7 @@ func (codec *int64Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *int64Codec) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (codec *int64Codec) IsEmpty(ptr unsafe.Pointer) bool {
@@ -133,7 +133,7 @@ func (codec *uintCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *uintCodec) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (codec *uintCodec) IsEmpty(ptr unsafe.Pointer) bool {
@@ -152,7 +152,7 @@ func (codec *uint8Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *uint8Codec) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (codec *uint8Codec) IsEmpty(ptr unsafe.Pointer) bool {
@@ -171,7 +171,7 @@ func (codec *uint16Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *uint16Codec) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (codec *uint16Codec) IsEmpty(ptr unsafe.Pointer) bool {
@@ -190,7 +190,7 @@ func (codec *uint32Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *uint32Codec) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (codec *uint32Codec) IsEmpty(ptr unsafe.Pointer) bool {
@@ -209,7 +209,7 @@ func (codec *uint64Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *uint64Codec) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (codec *uint64Codec) IsEmpty(ptr unsafe.Pointer) bool {
@@ -228,7 +228,7 @@ func (codec *float32Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *float32Codec) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (codec *float32Codec) IsEmpty(ptr unsafe.Pointer) bool {
@@ -247,7 +247,7 @@ func (codec *float64Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *float64Codec) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (codec *float64Codec) IsEmpty(ptr unsafe.Pointer) bool {
@@ -266,7 +266,7 @@ func (codec *boolCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *boolCodec) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (codec *boolCodec) IsEmpty(ptr unsafe.Pointer) bool {
@@ -478,7 +478,7 @@ func (encoder *stringModeEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *stringModeEncoder) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (encoder *stringModeEncoder) IsEmpty(ptr unsafe.Pointer) bool {
@@ -502,7 +502,7 @@ func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
 	}
 }
 func (encoder *marshalerEncoder) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (encoder *marshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
diff --git a/feature_reflect_object.go b/feature_reflect_object.go
index 0ad49d2..ebb8228 100644
--- a/feature_reflect_object.go
+++ b/feature_reflect_object.go
@@ -968,7 +968,7 @@ func (encoder *structFieldEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *structFieldEncoder) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (encoder *structFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool {
@@ -1021,7 +1021,7 @@ func (encoder *structEncoder) EncodeInterface(val interface{}, stream *Stream) {
 			}
 		}
 	}
-	writeToStream(val, stream, encoderToUse)
+	WriteToStream(val, stream, encoderToUse)
 }
 
 func (encoder *structEncoder) IsEmpty(ptr unsafe.Pointer) bool {
@@ -1041,7 +1041,7 @@ func (encoder *emptyStructEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *emptyStructEncoder) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (encoder *emptyStructEncoder) IsEmpty(ptr unsafe.Pointer) bool {
diff --git a/feature_reflect_slice.go b/feature_reflect_slice.go
index 93115ad..aff3cb7 100644
--- a/feature_reflect_slice.go
+++ b/feature_reflect_slice.go
@@ -57,7 +57,7 @@ func (encoder *sliceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
 }
 
 func (encoder *sliceEncoder) EncodeInterface(val interface{}, stream *Stream) {
-	writeToStream(val, stream, encoder)
+	WriteToStream(val, stream, encoder)
 }
 
 func (encoder *sliceEncoder) IsEmpty(ptr unsafe.Pointer) bool {
diff --git a/jsoniter_customize_test.go b/jsoniter_customize_test.go
index 5984313..30bec4f 100644
--- a/jsoniter_customize_test.go
+++ b/jsoniter_customize_test.go
@@ -139,18 +139,18 @@ func Test_customize_field_by_extension(t *testing.T) {
 
 type timeImplementedMarshaler time.Time
 
-func (obj *timeImplementedMarshaler) MarshalJSON() ([]byte, error) {
-	seconds := time.Time(*obj).Unix()
+func (obj timeImplementedMarshaler) MarshalJSON() ([]byte, error) {
+	seconds := time.Time(obj).Unix()
 	return []byte(strconv.FormatInt(seconds, 10)), nil
 }
 
 func Test_marshaler(t *testing.T) {
 	type TestObject struct {
-		Field *timeImplementedMarshaler
+		Field timeImplementedMarshaler
 	}
 	should := require.New(t)
 	val := timeImplementedMarshaler(time.Unix(123, 0))
-	obj := TestObject{&val}
+	obj := TestObject{val}
 	bytes, err := json.Marshal(obj)
 	should.Nil(err)
 	should.Equal(`{"Field":123}`, string(bytes))