main.go 10 KB

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