1// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
2// Use of this source code is governed by a MIT license found in the LICENSE file.
3
4package codec
5
6import (
7	"math/rand"
8	"time"
9)
10
11// NoopHandle returns a no-op handle. It basically does nothing.
12// It is only useful for benchmarking, as it gives an idea of the
13// overhead from the codec framework.
14//
15// LIBRARY USERS: *** DO NOT USE ***
16func NoopHandle(slen int) *noopHandle {
17	h := noopHandle{}
18	h.rand = rand.New(rand.NewSource(time.Now().UnixNano()))
19	h.B = make([][]byte, slen)
20	h.S = make([]string, slen)
21	for i := 0; i < len(h.S); i++ {
22		b := make([]byte, i+1)
23		for j := 0; j < len(b); j++ {
24			b[j] = 'a' + byte(i)
25		}
26		h.B[i] = b
27		h.S[i] = string(b)
28	}
29	return &h
30}
31
32// noopHandle does nothing.
33// It is used to simulate the overhead of the codec framework.
34type noopHandle struct {
35	BasicHandle
36	binaryEncodingType
37	noopDrv // noopDrv is unexported here, so we can get a copy of it when needed.
38}
39
40type noopDrv struct {
41	d    *Decoder
42	e    *Encoder
43	i    int
44	S    []string
45	B    [][]byte
46	mks  []bool    // stack. if map (true), else if array (false)
47	mk   bool      // top of stack. what container are we on? map or array?
48	ct   valueType // last response for IsContainerType.
49	cb   int       // counter for ContainerType
50	rand *rand.Rand
51}
52
53func (h *noopDrv) r(v int) int { return h.rand.Intn(v) }
54func (h *noopDrv) m(v int) int { h.i++; return h.i % v }
55
56func (h *noopDrv) newEncDriver(e *Encoder) encDriver { h.e = e; return h }
57func (h *noopDrv) newDecDriver(d *Decoder) decDriver { h.d = d; return h }
58
59func (h *noopDrv) reset()       {}
60func (h *noopDrv) uncacheRead() {}
61
62// --- encDriver
63
64// stack functions (for map and array)
65func (h *noopDrv) start(b bool) {
66	// println("start", len(h.mks)+1)
67	h.mks = append(h.mks, b)
68	h.mk = b
69}
70func (h *noopDrv) end() {
71	// println("end: ", len(h.mks)-1)
72	h.mks = h.mks[:len(h.mks)-1]
73	if len(h.mks) > 0 {
74		h.mk = h.mks[len(h.mks)-1]
75	} else {
76		h.mk = false
77	}
78}
79
80func (h *noopDrv) EncodeBuiltin(rt uintptr, v interface{}) {}
81func (h *noopDrv) EncodeNil()                              {}
82func (h *noopDrv) EncodeInt(i int64)                       {}
83func (h *noopDrv) EncodeUint(i uint64)                     {}
84func (h *noopDrv) EncodeBool(b bool)                       {}
85func (h *noopDrv) EncodeFloat32(f float32)                 {}
86func (h *noopDrv) EncodeFloat64(f float64)                 {}
87func (h *noopDrv) EncodeRawExt(re *RawExt, e *Encoder)     {}
88func (h *noopDrv) EncodeArrayStart(length int)             { h.start(true) }
89func (h *noopDrv) EncodeMapStart(length int)               { h.start(false) }
90func (h *noopDrv) EncodeEnd()                              { h.end() }
91
92func (h *noopDrv) EncodeString(c charEncoding, v string)      {}
93func (h *noopDrv) EncodeSymbol(v string)                      {}
94func (h *noopDrv) EncodeStringBytes(c charEncoding, v []byte) {}
95
96func (h *noopDrv) EncodeExt(rv interface{}, xtag uint64, ext Ext, e *Encoder) {}
97
98// ---- decDriver
99func (h *noopDrv) initReadNext()                              {}
100func (h *noopDrv) CheckBreak() bool                           { return false }
101func (h *noopDrv) IsBuiltinType(rt uintptr) bool              { return false }
102func (h *noopDrv) DecodeBuiltin(rt uintptr, v interface{})    {}
103func (h *noopDrv) DecodeInt(bitsize uint8) (i int64)          { return int64(h.m(15)) }
104func (h *noopDrv) DecodeUint(bitsize uint8) (ui uint64)       { return uint64(h.m(35)) }
105func (h *noopDrv) DecodeFloat(chkOverflow32 bool) (f float64) { return float64(h.m(95)) }
106func (h *noopDrv) DecodeBool() (b bool)                       { return h.m(2) == 0 }
107func (h *noopDrv) DecodeString() (s string)                   { return h.S[h.m(8)] }
108
109// func (h *noopDrv) DecodeStringAsBytes(bs []byte) []byte       { return h.DecodeBytes(bs) }
110
111func (h *noopDrv) DecodeBytes(bs []byte, isstring, zerocopy bool) []byte { return h.B[h.m(len(h.B))] }
112
113func (h *noopDrv) ReadEnd() { h.end() }
114
115// toggle map/slice
116func (h *noopDrv) ReadMapStart() int   { h.start(true); return h.m(10) }
117func (h *noopDrv) ReadArrayStart() int { h.start(false); return h.m(10) }
118
119func (h *noopDrv) ContainerType() (vt valueType) {
120	// return h.m(2) == 0
121	// handle kStruct, which will bomb is it calls this and doesn't get back a map or array.
122	// consequently, if the return value is not map or array, reset it to one of them based on h.m(7) % 2
123	// for kstruct: at least one out of every 2 times, return one of valueTypeMap or Array (else kstruct bombs)
124	// however, every 10th time it is called, we just return something else.
125	var vals = [...]valueType{valueTypeArray, valueTypeMap}
126	//  ------------ TAKE ------------
127	// if h.cb%2 == 0 {
128	// 	if h.ct == valueTypeMap || h.ct == valueTypeArray {
129	// 	} else {
130	// 		h.ct = vals[h.m(2)]
131	// 	}
132	// } else if h.cb%5 == 0 {
133	// 	h.ct = valueType(h.m(8))
134	// } else {
135	// 	h.ct = vals[h.m(2)]
136	// }
137	//  ------------ TAKE ------------
138	// if h.cb%16 == 0 {
139	// 	h.ct = valueType(h.cb % 8)
140	// } else {
141	// 	h.ct = vals[h.cb%2]
142	// }
143	h.ct = vals[h.cb%2]
144	h.cb++
145	return h.ct
146
147	// if h.ct == valueTypeNil || h.ct == valueTypeString || h.ct == valueTypeBytes {
148	// 	return h.ct
149	// }
150	// return valueTypeUnset
151	// TODO: may need to tweak this so it works.
152	// if h.ct == valueTypeMap && vt == valueTypeArray || h.ct == valueTypeArray && vt == valueTypeMap {
153	// 	h.cb = !h.cb
154	// 	h.ct = vt
155	// 	return h.cb
156	// }
157	// // go in a loop and check it.
158	// h.ct = vt
159	// h.cb = h.m(7) == 0
160	// return h.cb
161}
162func (h *noopDrv) TryDecodeAsNil() bool {
163	if h.mk {
164		return false
165	} else {
166		return h.m(8) == 0
167	}
168}
169func (h *noopDrv) DecodeExt(rv interface{}, xtag uint64, ext Ext) uint64 {
170	return 0
171}
172
173func (h *noopDrv) DecodeNaked() {
174	// use h.r (random) not h.m() because h.m() could cause the same value to be given.
175	var sk int
176	if h.mk {
177		// if mapkey, do not support values of nil OR bytes, array, map or rawext
178		sk = h.r(7) + 1
179	} else {
180		sk = h.r(12)
181	}
182	n := &h.d.n
183	switch sk {
184	case 0:
185		n.v = valueTypeNil
186	case 1:
187		n.v, n.b = valueTypeBool, false
188	case 2:
189		n.v, n.b = valueTypeBool, true
190	case 3:
191		n.v, n.i = valueTypeInt, h.DecodeInt(64)
192	case 4:
193		n.v, n.u = valueTypeUint, h.DecodeUint(64)
194	case 5:
195		n.v, n.f = valueTypeFloat, h.DecodeFloat(true)
196	case 6:
197		n.v, n.f = valueTypeFloat, h.DecodeFloat(false)
198	case 7:
199		n.v, n.s = valueTypeString, h.DecodeString()
200	case 8:
201		n.v, n.l = valueTypeBytes, h.B[h.m(len(h.B))]
202	case 9:
203		n.v = valueTypeArray
204	case 10:
205		n.v = valueTypeMap
206	default:
207		n.v = valueTypeExt
208		n.u = h.DecodeUint(64)
209		n.l = h.B[h.m(len(h.B))]
210	}
211	h.ct = n.v
212	return
213}
214