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", "dec_helpers.go", "file name to write")
24
25type Type struct {
26	lower   string
27	upper   string
28	decoder string
29}
30
31var types = []Type{
32	{
33		"bool",
34		"Bool",
35		`slice[i] = state.decodeUint() != 0`,
36	},
37	{
38		"complex64",
39		"Complex64",
40		`real := float32FromBits(state.decodeUint(), ovfl)
41		imag := float32FromBits(state.decodeUint(), ovfl)
42		slice[i] = complex(float32(real), float32(imag))`,
43	},
44	{
45		"complex128",
46		"Complex128",
47		`real := float64FromBits(state.decodeUint())
48		imag := float64FromBits(state.decodeUint())
49		slice[i] = complex(real, imag)`,
50	},
51	{
52		"float32",
53		"Float32",
54		`slice[i] = float32(float32FromBits(state.decodeUint(), ovfl))`,
55	},
56	{
57		"float64",
58		"Float64",
59		`slice[i] = float64FromBits(state.decodeUint())`,
60	},
61	{
62		"int",
63		"Int",
64		`x := state.decodeInt()
65		// MinInt and MaxInt
66		if x < ^int64(^uint(0)>>1) || int64(^uint(0)>>1) < x {
67			error_(ovfl)
68		}
69		slice[i] = int(x)`,
70	},
71	{
72		"int16",
73		"Int16",
74		`x := state.decodeInt()
75		if x < math.MinInt16 || math.MaxInt16 < x {
76			error_(ovfl)
77		}
78		slice[i] = int16(x)`,
79	},
80	{
81		"int32",
82		"Int32",
83		`x := state.decodeInt()
84		if x < math.MinInt32 || math.MaxInt32 < x {
85			error_(ovfl)
86		}
87		slice[i] = int32(x)`,
88	},
89	{
90		"int64",
91		"Int64",
92		`slice[i] = state.decodeInt()`,
93	},
94	{
95		"int8",
96		"Int8",
97		`x := state.decodeInt()
98		if x < math.MinInt8 || math.MaxInt8 < x {
99			error_(ovfl)
100		}
101		slice[i] = int8(x)`,
102	},
103	{
104		"string",
105		"String",
106		`u := state.decodeUint()
107		n := int(u)
108		if n < 0 || uint64(n) != u || n > state.b.Len() {
109			errorf("length of string exceeds input size (%d bytes)", u)
110		}
111		if n > state.b.Len() {
112			errorf("string data too long for buffer: %d", n)
113		}
114		// Read the data.
115		data := state.b.Bytes()
116		if len(data) < n {
117			errorf("invalid string length %d: exceeds input size %d", n, len(data))
118		}
119		slice[i] = string(data[:n])
120		state.b.Drop(n)`,
121	},
122	{
123		"uint",
124		"Uint",
125		`x := state.decodeUint()
126		/*TODO if math.MaxUint32 < x {
127			error_(ovfl)
128		}*/
129		slice[i] = uint(x)`,
130	},
131	{
132		"uint16",
133		"Uint16",
134		`x := state.decodeUint()
135		if math.MaxUint16 < x {
136			error_(ovfl)
137		}
138		slice[i] = uint16(x)`,
139	},
140	{
141		"uint32",
142		"Uint32",
143		`x := state.decodeUint()
144		if math.MaxUint32 < x {
145			error_(ovfl)
146		}
147		slice[i] = uint32(x)`,
148	},
149	{
150		"uint64",
151		"Uint64",
152		`slice[i] = state.decodeUint()`,
153	},
154	{
155		"uintptr",
156		"Uintptr",
157		`x := state.decodeUint()
158		if uint64(^uintptr(0)) < x {
159			error_(ovfl)
160		}
161		slice[i] = uintptr(x)`,
162	},
163	// uint8 Handled separately.
164}
165
166func main() {
167	log.SetFlags(0)
168	log.SetPrefix("decgen: ")
169	flag.Parse()
170	if flag.NArg() != 0 {
171		log.Fatal("usage: decgen [--output filename]")
172	}
173	var b bytes.Buffer
174	fmt.Fprintf(&b, "// Code generated by go run decgen.go -output %s; DO NOT EDIT.\n", *output)
175	fmt.Fprint(&b, header)
176	printMaps(&b, "Array")
177	fmt.Fprint(&b, "\n")
178	printMaps(&b, "Slice")
179	for _, t := range types {
180		fmt.Fprintf(&b, arrayHelper, t.lower, t.upper)
181		fmt.Fprintf(&b, sliceHelper, t.lower, t.upper, t.decoder)
182	}
183	fmt.Fprintf(&b, trailer)
184	source, err := format.Source(b.Bytes())
185	if err != nil {
186		log.Fatal("source format error:", err)
187	}
188	fd, err := os.Create(*output)
189	if err != nil {
190		log.Fatal(err)
191	}
192	if _, err := fd.Write(source); err != nil {
193		log.Fatal(err)
194	}
195	if err := fd.Close(); err != nil {
196		log.Fatal(err)
197	}
198}
199
200func printMaps(b *bytes.Buffer, upperClass string) {
201	fmt.Fprintf(b, "var dec%sHelper = map[reflect.Kind]decHelper{\n", upperClass)
202	for _, t := range types {
203		fmt.Fprintf(b, "reflect.%s: dec%s%s,\n", t.upper, t.upper, upperClass)
204	}
205	fmt.Fprintf(b, "}\n")
206}
207
208const header = `
209// Copyright 2014 The Go Authors. All rights reserved.
210// Use of this source code is governed by a BSD-style
211// license that can be found in the LICENSE file.
212
213package gob
214
215import (
216	"math"
217	"reflect"
218)
219
220`
221
222const arrayHelper = `
223func dec%[2]sArray(state *decoderState, v reflect.Value, length int, ovfl error) bool {
224	// Can only slice if it is addressable.
225	if !v.CanAddr() {
226		return false
227	}
228	return dec%[2]sSlice(state, v.Slice(0, v.Len()), length, ovfl)
229}
230`
231
232const sliceHelper = `
233func dec%[2]sSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
234	slice, ok := v.Interface().([]%[1]s)
235	if !ok {
236		// It is kind %[1]s but not type %[1]s. TODO: We can handle this unsafely.
237		return false
238	}
239	for i := 0; i < length; i++ {
240		if state.b.Len() == 0 {
241			errorf("decoding %[1]s array or slice: length exceeds input size (%%d elements)", length)
242		}
243		if i >= len(slice) {
244			// This is a slice that we only partially allocated.
245			growSlice(v, &slice, length)
246		}
247		%[3]s
248	}
249	return true
250}
251`
252
253const trailer = `
254// growSlice is called for a slice that we only partially allocated,
255// to grow it up to length.
256func growSlice[E any](v reflect.Value, ps *[]E, length int) {
257	var zero E
258	s := *ps
259	s = append(s, zero)
260	cp := cap(s)
261	if cp > length {
262		cp = length
263	}
264	s = s[:cp]
265	v.Set(reflect.ValueOf(s))
266	*ps = s
267}
268`
269