Home | History | Annotate | Download | only in gob
      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 // +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 
     12 package main
     13 
     14 import (
     15 	"bytes"
     16 	"flag"
     17 	"fmt"
     18 	"go/format"
     19 	"log"
     20 	"os"
     21 )
     22 
     23 var output = flag.String("output", "dec_helpers.go", "file name to write")
     24 
     25 type Type struct {
     26 	lower   string
     27 	upper   string
     28 	decoder string
     29 }
     30 
     31 var 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 
    166 func 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, "// Created by decgen --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 	source, err := format.Source(b.Bytes())
    184 	if err != nil {
    185 		log.Fatal("source format error:", err)
    186 	}
    187 	fd, err := os.Create(*output)
    188 	_, err = fd.Write(source)
    189 	if err != nil {
    190 		log.Fatal(err)
    191 	}
    192 }
    193 
    194 func printMaps(b *bytes.Buffer, upperClass string) {
    195 	fmt.Fprintf(b, "var dec%sHelper = map[reflect.Kind]decHelper{\n", upperClass)
    196 	for _, t := range types {
    197 		fmt.Fprintf(b, "reflect.%s: dec%s%s,\n", t.upper, t.upper, upperClass)
    198 	}
    199 	fmt.Fprintf(b, "}\n")
    200 }
    201 
    202 const header = `
    203 // Copyright 2014 The Go Authors. All rights reserved.
    204 // Use of this source code is governed by a BSD-style
    205 // license that can be found in the LICENSE file.
    206 
    207 package gob
    208 
    209 import (
    210 	"math"
    211 	"reflect"
    212 )
    213 
    214 `
    215 
    216 const arrayHelper = `
    217 func dec%[2]sArray(state *decoderState, v reflect.Value, length int, ovfl error) bool {
    218 	// Can only slice if it is addressable.
    219 	if !v.CanAddr() {
    220 		return false
    221 	}
    222 	return dec%[2]sSlice(state, v.Slice(0, v.Len()), length, ovfl)
    223 }
    224 `
    225 
    226 const sliceHelper = `
    227 func dec%[2]sSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
    228 	slice, ok := v.Interface().([]%[1]s)
    229 	if !ok {
    230 		// It is kind %[1]s but not type %[1]s. TODO: We can handle this unsafely.
    231 		return false
    232 	}
    233 	for i := 0; i < length; i++ {
    234 		if state.b.Len() == 0 {
    235 			errorf("decoding %[1]s array or slice: length exceeds input size (%%d elements)", length)
    236 		}
    237 		%[3]s
    238 	}
    239 	return true
    240 }
    241 `
    242