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