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