blob.go 2.69 KB
Newer Older
cznic's avatar
A+C  
cznic committed
1
// Copyright 2014 The ql Authors. All rights reserved.
cznic's avatar
cznic committed
2 3 4 5 6 7 8 9 10 11
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ql

import (
	"bytes"
	"encoding/gob"
	"log"
	"math/big"
cznic's avatar
cznic committed
12
	"sync"
cznic's avatar
cznic committed
13 14 15
	"time"
)

cznic's avatar
cznic committed
16
const shortBlob = 256 // bytes
cznic's avatar
cznic committed
17 18

var (
cznic's avatar
cznic committed
19 20 21 22
	gobInitDuration = time.Duration(278)
	gobInitInt      = big.NewInt(42)
	gobInitRat      = big.NewRat(355, 113)
	gobInitTime     time.Time
cznic's avatar
cznic committed
23 24 25 26 27 28 29
)

func init() {
	var err error
	if gobInitTime, err = time.ParseInLocation(
		"Jan 2, 2006 at 3:04pm (MST)",
		"Jul 9, 2012 at 5:02am (CEST)",
cznic's avatar
cznic committed
30
		time.FixedZone("XYZ", 1234),
cznic's avatar
cznic committed
31 32 33
	); err != nil {
		log.Panic(err)
	}
34
	newGobCoder()
cznic's avatar
cznic committed
35
}
cznic's avatar
cznic committed
36

cznic's avatar
cznic committed
37 38 39 40 41
type gobCoder struct {
	buf bytes.Buffer
	dec *gob.Decoder
	enc *gob.Encoder
	mu  sync.Mutex
cznic's avatar
cznic committed
42 43
}

cznic's avatar
cznic committed
44 45 46 47
func newGobCoder() (g *gobCoder) {
	g = &gobCoder{}
	g.enc = gob.NewEncoder(&g.buf)
	if err := g.enc.Encode(gobInitInt); err != nil {
cznic's avatar
cznic committed
48 49 50
		log.Panic(err)
	}

cznic's avatar
cznic committed
51
	if err := g.enc.Encode(gobInitRat); err != nil {
cznic's avatar
cznic committed
52 53 54
		log.Panic(err)
	}

cznic's avatar
cznic committed
55
	if err := g.enc.Encode(gobInitTime); err != nil {
cznic's avatar
cznic committed
56 57 58
		log.Panic(err)
	}

cznic's avatar
cznic committed
59 60 61
	if err := g.enc.Encode(gobInitDuration); err != nil {
		log.Panic(err)
	}
cznic's avatar
cznic committed
62

cznic's avatar
cznic committed
63
	g.dec = gob.NewDecoder(&g.buf)
cznic's avatar
cznic committed
64
	i := big.NewInt(0)
cznic's avatar
cznic committed
65
	if err := g.dec.Decode(i); err != nil {
cznic's avatar
cznic committed
66 67 68 69
		log.Panic(err)
	}

	r := big.NewRat(3, 5)
cznic's avatar
cznic committed
70
	if err := g.dec.Decode(r); err != nil {
cznic's avatar
cznic committed
71 72 73 74
		log.Panic(err)
	}

	t := time.Now()
cznic's avatar
cznic committed
75 76 77 78 79 80
	if err := g.dec.Decode(&t); err != nil {
		log.Panic(err)
	}

	var d time.Duration
	if err := g.dec.Decode(&d); err != nil {
cznic's avatar
cznic committed
81 82 83 84 85
		log.Panic(err)
	}

	return
}
cznic's avatar
cznic committed
86

cznic's avatar
WIPS  
cznic committed
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
func isBlobType(v interface{}) (bool, Type) {
	switch v.(type) {
	case []byte:
		return true, Blob
	case *big.Int:
		return true, BigInt
	case *big.Rat:
		return true, BigRat
	case time.Time:
		return true, Time
	case time.Duration:
		return true, Duration
	default:
		return false, -1
	}
}

cznic's avatar
cznic committed
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
func (g *gobCoder) encode(v interface{}) (b []byte, err error) {
	g.mu.Lock()
	defer g.mu.Unlock()

	g.buf.Reset()
	switch x := v.(type) {
	case []byte:
		return x, nil
	case *big.Int:
		err = g.enc.Encode(x)
	case *big.Rat:
		err = g.enc.Encode(x)
	case time.Time:
		err = g.enc.Encode(x)
	case time.Duration:
cznic's avatar
cznic committed
119
		err = g.enc.Encode(int64(x))
cznic's avatar
cznic committed
120
	default:
cznic's avatar
cznic committed
121
		//dbg("%T(%v)", v, v)
cznic's avatar
cznic committed
122
		log.Panic("internal error 002")
cznic's avatar
cznic committed
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
	}
	b = g.buf.Bytes()
	return
}

func (g *gobCoder) decode(b []byte, typ int) (v interface{}, err error) {
	g.mu.Lock()
	defer g.mu.Unlock()

	g.buf.Reset()
	g.buf.Write(b)
	switch typ {
	case qBlob:
		return b, nil
	case qBigInt:
		x := big.NewInt(0)
		err = g.dec.Decode(&x)
		v = x
	case qBigRat:
cznic's avatar
cznic committed
142
		x := big.NewRat(1, 1)
cznic's avatar
cznic committed
143 144 145 146 147 148 149
		err = g.dec.Decode(&x)
		v = x
	case qTime:
		var x time.Time
		err = g.dec.Decode(&x)
		v = x
	case qDuration:
cznic's avatar
cznic committed
150
		var x int64
cznic's avatar
cznic committed
151
		err = g.dec.Decode(&x)
cznic's avatar
cznic committed
152
		v = time.Duration(x)
cznic's avatar
cznic committed
153
	default:
cznic's avatar
cznic committed
154
		log.Panic("internal error 003")
cznic's avatar
cznic committed
155 156 157
	}
	return
}