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", "enc_helpers.go", "file name to write")
     24 
     25 type Type struct {
     26 	lower   string
     27 	upper   string
     28 	zero    string
     29 	encoder string
     30 }
     31 
     32 var 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 
    145 func 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, "// Created by encgen --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 	_, err = fd.Write(source)
    168 	if err != nil {
    169 		log.Fatal(err)
    170 	}
    171 }
    172 
    173 func printMaps(b *bytes.Buffer, upperClass string) {
    174 	fmt.Fprintf(b, "var enc%sHelper = map[reflect.Kind]encHelper{\n", upperClass)
    175 	for _, t := range types {
    176 		fmt.Fprintf(b, "reflect.%s: enc%s%s,\n", t.upper, t.upper, upperClass)
    177 	}
    178 	fmt.Fprintf(b, "}\n")
    179 }
    180 
    181 const header = `
    182 // Copyright 2014 The Go Authors. All rights reserved.
    183 // Use of this source code is governed by a BSD-style
    184 // license that can be found in the LICENSE file.
    185 
    186 package gob
    187 
    188 import (
    189 	"reflect"
    190 )
    191 
    192 `
    193 
    194 const arrayHelper = `
    195 func enc%[2]sArray(state *encoderState, v reflect.Value) bool {
    196 	// Can only slice if it is addressable.
    197 	if !v.CanAddr() {
    198 		return false
    199 	}
    200 	return enc%[2]sSlice(state, v.Slice(0, v.Len()))
    201 }
    202 `
    203 
    204 const sliceHelper = `
    205 func enc%[2]sSlice(state *encoderState, v reflect.Value) bool {
    206 	slice, ok := v.Interface().([]%[1]s)
    207 	if !ok {
    208 		// It is kind %[1]s but not type %[1]s. TODO: We can handle this unsafely.
    209 		return false
    210 	}
    211 	for _, x := range slice {
    212 		if x != %[3]s || state.sendZero {
    213 			%[4]s
    214 		}
    215 	}
    216 	return true
    217 }
    218 `
    219