main.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. // Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
  2. // All rights reserved. Use of this source code is governed by an MIT-style
  3. // license that can be found in the LICENSE file.
  4. // +build ignore
  5. package main
  6. import (
  7. "bytes"
  8. "flag"
  9. "fmt"
  10. "go/ast"
  11. "go/format"
  12. "go/parser"
  13. "go/token"
  14. "os"
  15. "regexp"
  16. "strconv"
  17. "strings"
  18. "text/template"
  19. )
  20. type fieldInfo struct {
  21. Name string
  22. IsBasic bool // handled by one the native Read/WriteUint64 etc functions
  23. IsSlice bool // field is a slice of FieldType
  24. FieldType string // original type of field, i.e. "int"
  25. Encoder string // the encoder name, i.e. "Uint64" for Read/WriteUint64
  26. Convert string // what to convert to when encoding, i.e. "uint64"
  27. Max int // max size for slices and strings
  28. }
  29. type structInfo struct {
  30. Name string
  31. Fields []fieldInfo
  32. }
  33. var headerTpl = template.Must(template.New("header").Parse(`// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
  34. // All rights reserved. Use of this source code is governed by an MIT-style
  35. // license that can be found in the LICENSE file.
  36. // ************************************************************
  37. // This file is automatically generated by genxdr. Do not edit.
  38. // ************************************************************
  39. package {{.Package}}
  40. import (
  41. "bytes"
  42. "io"
  43. "github.com/calmh/syncthing/xdr"
  44. )
  45. `))
  46. var encodeTpl = template.Must(template.New("encoder").Parse(`
  47. func (o {{.TypeName}}) EncodeXDR(w io.Writer) (int, error) {
  48. var xw = xdr.NewWriter(w)
  49. return o.encodeXDR(xw)
  50. }//+n
  51. func (o {{.TypeName}}) MarshalXDR() []byte {
  52. return o.AppendXDR(make([]byte, 0, 128))
  53. }//+n
  54. func (o {{.TypeName}}) AppendXDR(bs []byte) []byte {
  55. var aw = xdr.AppendWriter(bs)
  56. var xw = xdr.NewWriter(&aw)
  57. o.encodeXDR(xw)
  58. return []byte(aw)
  59. }//+n
  60. func (o {{.TypeName}}) encodeXDR(xw *xdr.Writer) (int, error) {
  61. {{range $fieldInfo := .Fields}}
  62. {{if not $fieldInfo.IsSlice}}
  63. {{if ne $fieldInfo.Convert ""}}
  64. xw.Write{{$fieldInfo.Encoder}}({{$fieldInfo.Convert}}(o.{{$fieldInfo.Name}}))
  65. {{else if $fieldInfo.IsBasic}}
  66. {{if ge $fieldInfo.Max 1}}
  67. if len(o.{{$fieldInfo.Name}}) > {{$fieldInfo.Max}} {
  68. return xw.Tot(), xdr.ErrElementSizeExceeded
  69. }
  70. {{end}}
  71. xw.Write{{$fieldInfo.Encoder}}(o.{{$fieldInfo.Name}})
  72. {{else}}
  73. _, err := o.{{$fieldInfo.Name}}.encodeXDR(xw)
  74. if err != nil {
  75. return xw.Tot(), err
  76. }
  77. {{end}}
  78. {{else}}
  79. {{if ge $fieldInfo.Max 1}}
  80. if len(o.{{$fieldInfo.Name}}) > {{$fieldInfo.Max}} {
  81. return xw.Tot(), xdr.ErrElementSizeExceeded
  82. }
  83. {{end}}
  84. xw.WriteUint32(uint32(len(o.{{$fieldInfo.Name}})))
  85. for i := range o.{{$fieldInfo.Name}} {
  86. {{if ne $fieldInfo.Convert ""}}
  87. xw.Write{{$fieldInfo.Encoder}}({{$fieldInfo.Convert}}(o.{{$fieldInfo.Name}}[i]))
  88. {{else if $fieldInfo.IsBasic}}
  89. xw.Write{{$fieldInfo.Encoder}}(o.{{$fieldInfo.Name}}[i])
  90. {{else}}
  91. _, err := o.{{$fieldInfo.Name}}[i].encodeXDR(xw)
  92. if err != nil {
  93. return xw.Tot(), err
  94. }
  95. {{end}}
  96. }
  97. {{end}}
  98. {{end}}
  99. return xw.Tot(), xw.Error()
  100. }//+n
  101. func (o *{{.TypeName}}) DecodeXDR(r io.Reader) error {
  102. xr := xdr.NewReader(r)
  103. return o.decodeXDR(xr)
  104. }//+n
  105. func (o *{{.TypeName}}) UnmarshalXDR(bs []byte) error {
  106. var br = bytes.NewReader(bs)
  107. var xr = xdr.NewReader(br)
  108. return o.decodeXDR(xr)
  109. }//+n
  110. func (o *{{.TypeName}}) decodeXDR(xr *xdr.Reader) error {
  111. {{range $fieldInfo := .Fields}}
  112. {{if not $fieldInfo.IsSlice}}
  113. {{if ne $fieldInfo.Convert ""}}
  114. o.{{$fieldInfo.Name}} = {{$fieldInfo.FieldType}}(xr.Read{{$fieldInfo.Encoder}}())
  115. {{else if $fieldInfo.IsBasic}}
  116. {{if ge $fieldInfo.Max 1}}
  117. o.{{$fieldInfo.Name}} = xr.Read{{$fieldInfo.Encoder}}Max({{$fieldInfo.Max}})
  118. {{else}}
  119. o.{{$fieldInfo.Name}} = xr.Read{{$fieldInfo.Encoder}}()
  120. {{end}}
  121. {{else}}
  122. (&o.{{$fieldInfo.Name}}).decodeXDR(xr)
  123. {{end}}
  124. {{else}}
  125. _{{$fieldInfo.Name}}Size := int(xr.ReadUint32())
  126. {{if ge $fieldInfo.Max 1}}
  127. if _{{$fieldInfo.Name}}Size > {{$fieldInfo.Max}} {
  128. return xdr.ErrElementSizeExceeded
  129. }
  130. {{end}}
  131. o.{{$fieldInfo.Name}} = make([]{{$fieldInfo.FieldType}}, _{{$fieldInfo.Name}}Size)
  132. for i := range o.{{$fieldInfo.Name}} {
  133. {{if ne $fieldInfo.Convert ""}}
  134. o.{{$fieldInfo.Name}}[i] = {{$fieldInfo.FieldType}}(xr.Read{{$fieldInfo.Encoder}}())
  135. {{else if $fieldInfo.IsBasic}}
  136. o.{{$fieldInfo.Name}}[i] = xr.Read{{$fieldInfo.Encoder}}()
  137. {{else}}
  138. (&o.{{$fieldInfo.Name}}[i]).decodeXDR(xr)
  139. {{end}}
  140. }
  141. {{end}}
  142. {{end}}
  143. return xr.Error()
  144. }`))
  145. var maxRe = regexp.MustCompile(`\Wmax:(\d+)`)
  146. type typeSet struct {
  147. Type string
  148. Encoder string
  149. }
  150. var xdrEncoders = map[string]typeSet{
  151. "int16": typeSet{"uint16", "Uint16"},
  152. "uint16": typeSet{"", "Uint16"},
  153. "int32": typeSet{"uint32", "Uint32"},
  154. "uint32": typeSet{"", "Uint32"},
  155. "int64": typeSet{"uint64", "Uint64"},
  156. "uint64": typeSet{"", "Uint64"},
  157. "int": typeSet{"uint64", "Uint64"},
  158. "string": typeSet{"", "String"},
  159. "[]byte": typeSet{"", "Bytes"},
  160. "bool": typeSet{"", "Bool"},
  161. }
  162. func handleStruct(t *ast.StructType) []fieldInfo {
  163. var fs []fieldInfo
  164. for _, sf := range t.Fields.List {
  165. if len(sf.Names) == 0 {
  166. // We don't handle anonymous fields
  167. continue
  168. }
  169. fn := sf.Names[0].Name
  170. var max = 0
  171. if sf.Comment != nil {
  172. c := sf.Comment.List[0].Text
  173. if m := maxRe.FindStringSubmatch(c); m != nil {
  174. max, _ = strconv.Atoi(m[1])
  175. }
  176. if strings.Contains(c, "noencode") {
  177. continue
  178. }
  179. }
  180. var f fieldInfo
  181. switch ft := sf.Type.(type) {
  182. case *ast.Ident:
  183. tn := ft.Name
  184. if enc, ok := xdrEncoders[tn]; ok {
  185. f = fieldInfo{
  186. Name: fn,
  187. IsBasic: true,
  188. FieldType: tn,
  189. Encoder: enc.Encoder,
  190. Convert: enc.Type,
  191. Max: max,
  192. }
  193. } else {
  194. f = fieldInfo{
  195. Name: fn,
  196. IsBasic: false,
  197. FieldType: tn,
  198. Max: max,
  199. }
  200. }
  201. case *ast.ArrayType:
  202. if ft.Len != nil {
  203. // We don't handle arrays
  204. continue
  205. }
  206. tn := ft.Elt.(*ast.Ident).Name
  207. if enc, ok := xdrEncoders["[]"+tn]; ok {
  208. f = fieldInfo{
  209. Name: fn,
  210. IsBasic: true,
  211. FieldType: tn,
  212. Encoder: enc.Encoder,
  213. Convert: enc.Type,
  214. Max: max,
  215. }
  216. } else if enc, ok := xdrEncoders[tn]; ok {
  217. f = fieldInfo{
  218. Name: fn,
  219. IsBasic: true,
  220. IsSlice: true,
  221. FieldType: tn,
  222. Encoder: enc.Encoder,
  223. Convert: enc.Type,
  224. Max: max,
  225. }
  226. } else {
  227. f = fieldInfo{
  228. Name: fn,
  229. IsBasic: false,
  230. IsSlice: true,
  231. FieldType: tn,
  232. Max: max,
  233. }
  234. }
  235. }
  236. fs = append(fs, f)
  237. }
  238. return fs
  239. }
  240. func generateCode(s structInfo) {
  241. name := s.Name
  242. fs := s.Fields
  243. var buf bytes.Buffer
  244. err := encodeTpl.Execute(&buf, map[string]interface{}{"TypeName": name, "Fields": fs})
  245. if err != nil {
  246. panic(err)
  247. }
  248. bs := regexp.MustCompile(`(\s*\n)+`).ReplaceAll(buf.Bytes(), []byte("\n"))
  249. bs = bytes.Replace(bs, []byte("//+n"), []byte("\n"), -1)
  250. bs, err = format.Source(bs)
  251. if err != nil {
  252. panic(err)
  253. }
  254. fmt.Println(string(bs))
  255. }
  256. func uncamelize(s string) string {
  257. return regexp.MustCompile("[a-z][A-Z]").ReplaceAllStringFunc(s, func(camel string) string {
  258. return camel[:1] + " " + camel[1:]
  259. })
  260. }
  261. func generateDiagram(s structInfo) {
  262. sn := s.Name
  263. fs := s.Fields
  264. fmt.Println(sn + " Structure:")
  265. fmt.Println()
  266. fmt.Println(" 0 1 2 3")
  267. fmt.Println(" 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1")
  268. line := "+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+"
  269. fmt.Println(line)
  270. for _, f := range fs {
  271. tn := f.FieldType
  272. sl := f.IsSlice
  273. name := uncamelize(f.Name)
  274. if sl {
  275. fmt.Printf("| %s |\n", center("Number of "+name, 61))
  276. fmt.Println(line)
  277. }
  278. switch tn {
  279. case "bool":
  280. fmt.Printf("| %s |V|\n", center(name+" (V=0 or 1)", 59))
  281. fmt.Println(line)
  282. case "uint16":
  283. fmt.Printf("| %s | %s |\n", center("0x0000", 29), center(name, 29))
  284. fmt.Println(line)
  285. case "uint32":
  286. fmt.Printf("| %s |\n", center(name, 61))
  287. fmt.Println(line)
  288. case "int64", "uint64":
  289. fmt.Printf("| %-61s |\n", "")
  290. fmt.Printf("+ %s +\n", center(name+" (64 bits)", 61))
  291. fmt.Printf("| %-61s |\n", "")
  292. fmt.Println(line)
  293. case "string", "byte": // XXX We assume slice of byte!
  294. fmt.Printf("| %s |\n", center("Length of "+name, 61))
  295. fmt.Println(line)
  296. fmt.Printf("/ %61s /\n", "")
  297. fmt.Printf("\\ %s \\\n", center(name+" (variable length)", 61))
  298. fmt.Printf("/ %61s /\n", "")
  299. fmt.Println(line)
  300. default:
  301. if sl {
  302. tn = "Zero or more " + tn + " Structures"
  303. fmt.Printf("/ %s /\n", center("", 61))
  304. fmt.Printf("\\ %s \\\n", center(tn, 61))
  305. fmt.Printf("/ %s /\n", center("", 61))
  306. } else {
  307. fmt.Printf("| %s |\n", center(tn, 61))
  308. }
  309. fmt.Println(line)
  310. }
  311. }
  312. fmt.Println()
  313. fmt.Println()
  314. }
  315. func generateXdr(s structInfo) {
  316. sn := s.Name
  317. fs := s.Fields
  318. fmt.Printf("struct %s {\n", sn)
  319. for _, f := range fs {
  320. tn := f.FieldType
  321. fn := f.Name
  322. suf := ""
  323. l := ""
  324. if f.Max > 0 {
  325. l = strconv.Itoa(f.Max)
  326. }
  327. if f.IsSlice {
  328. suf = "<" + l + ">"
  329. }
  330. switch tn {
  331. case "uint16", "uint32":
  332. fmt.Printf("\tunsigned int %s%s;\n", fn, suf)
  333. case "int64":
  334. fmt.Printf("\thyper %s%s;\n", fn, suf)
  335. case "uint64":
  336. fmt.Printf("\tunsigned hyper %s%s;\n", fn, suf)
  337. case "string":
  338. fmt.Printf("\tstring %s<%s>;\n", fn, l)
  339. case "byte":
  340. fmt.Printf("\topaque %s<%s>;\n", fn, l)
  341. default:
  342. fmt.Printf("\t%s %s%s;\n", tn, fn, suf)
  343. }
  344. }
  345. fmt.Println("}")
  346. fmt.Println()
  347. }
  348. func center(s string, w int) string {
  349. w -= len(s)
  350. l := w / 2
  351. r := l
  352. if l+r < w {
  353. r++
  354. }
  355. return strings.Repeat(" ", l) + s + strings.Repeat(" ", r)
  356. }
  357. func inspector(structs *[]structInfo) func(ast.Node) bool {
  358. return func(n ast.Node) bool {
  359. switch n := n.(type) {
  360. case *ast.TypeSpec:
  361. switch t := n.Type.(type) {
  362. case *ast.StructType:
  363. name := n.Name.Name
  364. fs := handleStruct(t)
  365. *structs = append(*structs, structInfo{name, fs})
  366. }
  367. return false
  368. default:
  369. return true
  370. }
  371. }
  372. }
  373. func main() {
  374. flag.Parse()
  375. fname := flag.Arg(0)
  376. fset := token.NewFileSet()
  377. f, err := parser.ParseFile(fset, fname, nil, parser.ParseComments)
  378. if err != nil {
  379. panic(err)
  380. }
  381. var structs []structInfo
  382. i := inspector(&structs)
  383. ast.Inspect(f, i)
  384. headerTpl.Execute(os.Stdout, map[string]string{"Package": f.Name.Name})
  385. for _, s := range structs {
  386. fmt.Printf("\n/*\n\n")
  387. generateDiagram(s)
  388. generateXdr(s)
  389. fmt.Printf("*/\n")
  390. generateCode(s)
  391. }
  392. }