main.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  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. o.{{$fieldInfo.Name}}.encodeXDR(xw)
  74. {{end}}
  75. {{else}}
  76. {{if ge $fieldInfo.Max 1}}
  77. if len(o.{{$fieldInfo.Name}}) > {{$fieldInfo.Max}} {
  78. return xw.Tot(), xdr.ErrElementSizeExceeded
  79. }
  80. {{end}}
  81. xw.WriteUint32(uint32(len(o.{{$fieldInfo.Name}})))
  82. for i := range o.{{$fieldInfo.Name}} {
  83. {{if ne $fieldInfo.Convert ""}}
  84. xw.Write{{$fieldInfo.Encoder}}({{$fieldInfo.Convert}}(o.{{$fieldInfo.Name}}[i]))
  85. {{else if $fieldInfo.IsBasic}}
  86. xw.Write{{$fieldInfo.Encoder}}(o.{{$fieldInfo.Name}}[i])
  87. {{else}}
  88. o.{{$fieldInfo.Name}}[i].encodeXDR(xw)
  89. {{end}}
  90. }
  91. {{end}}
  92. {{end}}
  93. return xw.Tot(), xw.Error()
  94. }//+n
  95. func (o *{{.TypeName}}) DecodeXDR(r io.Reader) error {
  96. xr := xdr.NewReader(r)
  97. return o.decodeXDR(xr)
  98. }//+n
  99. func (o *{{.TypeName}}) UnmarshalXDR(bs []byte) error {
  100. var br = bytes.NewReader(bs)
  101. var xr = xdr.NewReader(br)
  102. return o.decodeXDR(xr)
  103. }//+n
  104. func (o *{{.TypeName}}) decodeXDR(xr *xdr.Reader) error {
  105. {{range $fieldInfo := .Fields}}
  106. {{if not $fieldInfo.IsSlice}}
  107. {{if ne $fieldInfo.Convert ""}}
  108. o.{{$fieldInfo.Name}} = {{$fieldInfo.FieldType}}(xr.Read{{$fieldInfo.Encoder}}())
  109. {{else if $fieldInfo.IsBasic}}
  110. {{if ge $fieldInfo.Max 1}}
  111. o.{{$fieldInfo.Name}} = xr.Read{{$fieldInfo.Encoder}}Max({{$fieldInfo.Max}})
  112. {{else}}
  113. o.{{$fieldInfo.Name}} = xr.Read{{$fieldInfo.Encoder}}()
  114. {{end}}
  115. {{else}}
  116. (&o.{{$fieldInfo.Name}}).decodeXDR(xr)
  117. {{end}}
  118. {{else}}
  119. _{{$fieldInfo.Name}}Size := int(xr.ReadUint32())
  120. {{if ge $fieldInfo.Max 1}}
  121. if _{{$fieldInfo.Name}}Size > {{$fieldInfo.Max}} {
  122. return xdr.ErrElementSizeExceeded
  123. }
  124. {{end}}
  125. o.{{$fieldInfo.Name}} = make([]{{$fieldInfo.FieldType}}, _{{$fieldInfo.Name}}Size)
  126. for i := range o.{{$fieldInfo.Name}} {
  127. {{if ne $fieldInfo.Convert ""}}
  128. o.{{$fieldInfo.Name}}[i] = {{$fieldInfo.FieldType}}(xr.Read{{$fieldInfo.Encoder}}())
  129. {{else if $fieldInfo.IsBasic}}
  130. o.{{$fieldInfo.Name}}[i] = xr.Read{{$fieldInfo.Encoder}}()
  131. {{else}}
  132. (&o.{{$fieldInfo.Name}}[i]).decodeXDR(xr)
  133. {{end}}
  134. }
  135. {{end}}
  136. {{end}}
  137. return xr.Error()
  138. }`))
  139. var maxRe = regexp.MustCompile(`\Wmax:(\d+)`)
  140. type typeSet struct {
  141. Type string
  142. Encoder string
  143. }
  144. var xdrEncoders = map[string]typeSet{
  145. "int16": typeSet{"uint16", "Uint16"},
  146. "uint16": typeSet{"", "Uint16"},
  147. "int32": typeSet{"uint32", "Uint32"},
  148. "uint32": typeSet{"", "Uint32"},
  149. "int64": typeSet{"uint64", "Uint64"},
  150. "uint64": typeSet{"", "Uint64"},
  151. "int": typeSet{"uint64", "Uint64"},
  152. "string": typeSet{"", "String"},
  153. "[]byte": typeSet{"", "Bytes"},
  154. "bool": typeSet{"", "Bool"},
  155. }
  156. func handleStruct(t *ast.StructType) []fieldInfo {
  157. var fs []fieldInfo
  158. for _, sf := range t.Fields.List {
  159. if len(sf.Names) == 0 {
  160. // We don't handle anonymous fields
  161. continue
  162. }
  163. fn := sf.Names[0].Name
  164. var max = 0
  165. if sf.Comment != nil {
  166. c := sf.Comment.List[0].Text
  167. if m := maxRe.FindStringSubmatch(c); m != nil {
  168. max, _ = strconv.Atoi(m[1])
  169. }
  170. if strings.Contains(c, "noencode") {
  171. continue
  172. }
  173. }
  174. var f fieldInfo
  175. switch ft := sf.Type.(type) {
  176. case *ast.Ident:
  177. tn := ft.Name
  178. if enc, ok := xdrEncoders[tn]; ok {
  179. f = fieldInfo{
  180. Name: fn,
  181. IsBasic: true,
  182. FieldType: tn,
  183. Encoder: enc.Encoder,
  184. Convert: enc.Type,
  185. Max: max,
  186. }
  187. } else {
  188. f = fieldInfo{
  189. Name: fn,
  190. IsBasic: false,
  191. FieldType: tn,
  192. Max: max,
  193. }
  194. }
  195. case *ast.ArrayType:
  196. if ft.Len != nil {
  197. // We don't handle arrays
  198. continue
  199. }
  200. tn := ft.Elt.(*ast.Ident).Name
  201. if enc, ok := xdrEncoders["[]"+tn]; ok {
  202. f = fieldInfo{
  203. Name: fn,
  204. IsBasic: true,
  205. FieldType: tn,
  206. Encoder: enc.Encoder,
  207. Convert: enc.Type,
  208. Max: max,
  209. }
  210. } else if enc, ok := xdrEncoders[tn]; ok {
  211. f = fieldInfo{
  212. Name: fn,
  213. IsBasic: true,
  214. IsSlice: true,
  215. FieldType: tn,
  216. Encoder: enc.Encoder,
  217. Convert: enc.Type,
  218. Max: max,
  219. }
  220. } else {
  221. f = fieldInfo{
  222. Name: fn,
  223. IsBasic: false,
  224. IsSlice: true,
  225. FieldType: tn,
  226. Max: max,
  227. }
  228. }
  229. }
  230. fs = append(fs, f)
  231. }
  232. return fs
  233. }
  234. func generateCode(s structInfo) {
  235. name := s.Name
  236. fs := s.Fields
  237. var buf bytes.Buffer
  238. err := encodeTpl.Execute(&buf, map[string]interface{}{"TypeName": name, "Fields": fs})
  239. if err != nil {
  240. panic(err)
  241. }
  242. bs := regexp.MustCompile(`(\s*\n)+`).ReplaceAll(buf.Bytes(), []byte("\n"))
  243. bs = bytes.Replace(bs, []byte("//+n"), []byte("\n"), -1)
  244. bs, err = format.Source(bs)
  245. if err != nil {
  246. panic(err)
  247. }
  248. fmt.Println(string(bs))
  249. }
  250. func uncamelize(s string) string {
  251. return regexp.MustCompile("[a-z][A-Z]").ReplaceAllStringFunc(s, func(camel string) string {
  252. return camel[:1] + " " + camel[1:]
  253. })
  254. }
  255. func generateDiagram(s structInfo) {
  256. sn := s.Name
  257. fs := s.Fields
  258. fmt.Println(sn + " Structure:")
  259. fmt.Println()
  260. fmt.Println(" 0 1 2 3")
  261. 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")
  262. line := "+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+"
  263. fmt.Println(line)
  264. for _, f := range fs {
  265. tn := f.FieldType
  266. sl := f.IsSlice
  267. name := uncamelize(f.Name)
  268. if sl {
  269. fmt.Printf("| %s |\n", center("Number of "+name, 61))
  270. fmt.Println(line)
  271. }
  272. switch tn {
  273. case "bool":
  274. fmt.Printf("| %s |V|\n", center(name+" (V=0 or 1)", 59))
  275. fmt.Println(line)
  276. case "uint16":
  277. fmt.Printf("| %s | %s |\n", center("0x0000", 29), center(name, 29))
  278. fmt.Println(line)
  279. case "uint32":
  280. fmt.Printf("| %s |\n", center(name, 61))
  281. fmt.Println(line)
  282. case "int64", "uint64":
  283. fmt.Printf("| %-61s |\n", "")
  284. fmt.Printf("+ %s +\n", center(name+" (64 bits)", 61))
  285. fmt.Printf("| %-61s |\n", "")
  286. fmt.Println(line)
  287. case "string", "byte": // XXX We assume slice of byte!
  288. fmt.Printf("| %s |\n", center("Length of "+name, 61))
  289. fmt.Println(line)
  290. fmt.Printf("/ %61s /\n", "")
  291. fmt.Printf("\\ %s \\\n", center(name+" (variable length)", 61))
  292. fmt.Printf("/ %61s /\n", "")
  293. fmt.Println(line)
  294. default:
  295. if sl {
  296. tn = "Zero or more " + tn + " Structures"
  297. fmt.Printf("/ %s /\n", center("", 61))
  298. fmt.Printf("\\ %s \\\n", center(tn, 61))
  299. fmt.Printf("/ %s /\n", center("", 61))
  300. } else {
  301. fmt.Printf("| %s |\n", center(tn, 61))
  302. }
  303. fmt.Println(line)
  304. }
  305. }
  306. fmt.Println()
  307. fmt.Println()
  308. }
  309. func generateXdr(s structInfo) {
  310. sn := s.Name
  311. fs := s.Fields
  312. fmt.Printf("struct %s {\n", sn)
  313. for _, f := range fs {
  314. tn := f.FieldType
  315. fn := f.Name
  316. suf := ""
  317. l := ""
  318. if f.Max > 0 {
  319. l = strconv.Itoa(f.Max)
  320. }
  321. if f.IsSlice {
  322. suf = "<" + l + ">"
  323. }
  324. switch tn {
  325. case "uint16", "uint32":
  326. fmt.Printf("\tunsigned int %s%s;\n", fn, suf)
  327. case "int64":
  328. fmt.Printf("\thyper %s%s;\n", fn, suf)
  329. case "uint64":
  330. fmt.Printf("\tunsigned hyper %s%s;\n", fn, suf)
  331. case "string":
  332. fmt.Printf("\tstring %s<%s>;\n", fn, l)
  333. case "byte":
  334. fmt.Printf("\topaque %s<%s>;\n", fn, l)
  335. default:
  336. fmt.Printf("\t%s %s%s;\n", tn, fn, suf)
  337. }
  338. }
  339. fmt.Println("}")
  340. fmt.Println()
  341. }
  342. func center(s string, w int) string {
  343. w -= len(s)
  344. l := w / 2
  345. r := l
  346. if l+r < w {
  347. r++
  348. }
  349. return strings.Repeat(" ", l) + s + strings.Repeat(" ", r)
  350. }
  351. func inspector(structs *[]structInfo) func(ast.Node) bool {
  352. return func(n ast.Node) bool {
  353. switch n := n.(type) {
  354. case *ast.TypeSpec:
  355. switch t := n.Type.(type) {
  356. case *ast.StructType:
  357. name := n.Name.Name
  358. fs := handleStruct(t)
  359. *structs = append(*structs, structInfo{name, fs})
  360. }
  361. return false
  362. default:
  363. return true
  364. }
  365. }
  366. }
  367. func main() {
  368. flag.Parse()
  369. fname := flag.Arg(0)
  370. fset := token.NewFileSet()
  371. f, err := parser.ParseFile(fset, fname, nil, parser.ParseComments)
  372. if err != nil {
  373. panic(err)
  374. }
  375. var structs []structInfo
  376. i := inspector(&structs)
  377. ast.Inspect(f, i)
  378. headerTpl.Execute(os.Stdout, map[string]string{"Package": f.Name.Name})
  379. for _, s := range structs {
  380. fmt.Printf("\n/*\n\n")
  381. generateDiagram(s)
  382. generateXdr(s)
  383. fmt.Printf("*/\n")
  384. generateCode(s)
  385. }
  386. }