1// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5//go:build ignore
6
7// encgen writes the helper functions for encoding. Intended to be
8// used with go generate; see the invocation in encode.go.
9
10// TODO: We could do more by being unsafe. Add a -unsafe flag?
11
12package main
13
14import (
15	"bytes"
16	"flag"
17	"fmt"
18	"go/format"
19	"log"
20	"os"
21)
22
23var output = flag.String("output", "enc_helpers.go", "file name to write")
24
25type Type struct {
26	lower   string
27	upper   string
28	zero    string
29	encoder string
30}
31
32var types = []Type{
33	{
34		"bool",
35		"Bool",
36		"false",
37		`if x {
38			state.encodeUint(1)
39		} else {
40			state.encodeUint(0)
41		}`,
42	},
43	{
44		"complex64",
45		"Complex64",
46		"0+0i",
47		`rpart := floatBits(float64(real(x)))
48		ipart := floatBits(float64(imag(x)))
49		state.encodeUint(rpart)
50		state.encodeUint(ipart)`,
51	},
52	{
53		"complex128",
54		"Complex128",
55		"0+0i",
56		`rpart := floatBits(real(x))
57		ipart := floatBits(imag(x))
58		state.encodeUint(rpart)
59		state.encodeUint(ipart)`,
60	},
61	{
62		"float32",
63		"Float32",
64		"0",
65		`bits := floatBits(float64(x))
66		state.encodeUint(bits)`,
67	},
68	{
69		"float64",
70		"Float64",
71		"0",
72		`bits := floatBits(x)
73		state.encodeUint(bits)`,
74	},
75	{
76		"int",
77		"Int",
78		"0",
79		`state.encodeInt(int64(x))`,
80	},
81	{
82		"int16",
83		"Int16",
84		"0",
85		`state.encodeInt(int64(x))`,
86	},
87	{
88		"int32",
89		"Int32",
90		"0",
91		`state.encodeInt(int64(x))`,
92	},
93	{
94		"int64",
95		"Int64",
96		"0",
97		`state.encodeInt(x)`,
98	},
99	{
100		"int8",
101		"Int8",
102		"0",
103		`state.encodeInt(int64(x))`,
104	},
105	{
106		"string",
107		"String",
108		`""`,
109		`state.encodeUint(uint64(len(x)))
110		state.b.WriteString(x)`,
111	},
112	{
113		"uint",
114		"Uint",
115		"0",
116		`state.encodeUint(uint64(x))`,
117	},
118	{
119		"uint16",
120		"Uint16",
121		"0",
122		`state.encodeUint(uint64(x))`,
123	},
124	{
125		"uint32",
126		"Uint32",
127		"0",
128		`state.encodeUint(uint64(x))`,
129	},
130	{
131		"uint64",
132		"Uint64",
133		"0",
134		`state.encodeUint(x)`,
135	},
136	{
137		"uintptr",
138		"Uintptr",
139		"0",
140		`state.encodeUint(uint64(x))`,
141	},
142	// uint8 Handled separately.
143}
144
145func main() {
146	log.SetFlags(0)
147	log.SetPrefix("encgen: ")
148	flag.Parse()
149	if flag.NArg() != 0 {
150		log.Fatal("usage: encgen [--output filename]")
151	}
152	var b bytes.Buffer
153	fmt.Fprintf(&b, "// Code generated by go run encgen.go -output %s; DO NOT EDIT.\n", *output)
154	fmt.Fprint(&b, header)
155	printMaps(&b, "Array")
156	fmt.Fprint(&b, "\n")
157	printMaps(&b, "Slice")
158	for _, t := range types {
159		fmt.Fprintf(&b, arrayHelper, t.lower, t.upper)
160		fmt.Fprintf(&b, sliceHelper, t.lower, t.upper, t.zero, t.encoder)
161	}
162	source, err := format.Source(b.Bytes())
163	if err != nil {
164		log.Fatal("source format error:", err)
165	}
166	fd, err := os.Create(*output)
167	if err != nil {
168		log.Fatal(err)
169	}
170	if _, err := fd.Write(source); err != nil {
171		log.Fatal(err)
172	}
173	if err := fd.Close(); err != nil {
174		log.Fatal(err)
175	}
176}
177
178func printMaps(b *bytes.Buffer, upperClass string) {
179	fmt.Fprintf(b, "var enc%sHelper = map[reflect.Kind]encHelper{\n", upperClass)
180	for _, t := range types {
181		fmt.Fprintf(b, "reflect.%s: enc%s%s,\n", t.upper, t.upper, upperClass)
182	}
183	fmt.Fprintf(b, "}\n")
184}
185
186const header = `
187// Copyright 2014 The Go Authors. All rights reserved.
188// Use of this source code is governed by a BSD-style
189// license that can be found in the LICENSE file.
190
191package gob
192
193import (
194	"reflect"
195)
196
197`
198
199const arrayHelper = `
200func enc%[2]sArray(state *encoderState, v reflect.Value) bool {
201	// Can only slice if it is addressable.
202	if !v.CanAddr() {
203		return false
204	}
205	return enc%[2]sSlice(state, v.Slice(0, v.Len()))
206}
207`
208
209const sliceHelper = `
210func enc%[2]sSlice(state *encoderState, v reflect.Value) bool {
211	slice, ok := v.Interface().([]%[1]s)
212	if !ok {
213		// It is kind %[1]s but not type %[1]s. TODO: We can handle this unsafely.
214		return false
215	}
216	for _, x := range slice {
217		if x != %[3]s || state.sendZero {
218			%[4]s
219		}
220	}
221	return true
222}
223`
224