mirror of
https://github.com/Mrs4s/go-cqhttp.git
synced 2025-05-05 03:23:49 +08:00
Two benefit below: * shrink go-cqhttp binary size about 200KiB * shrink database file from 2.8M to 1.56M compared with v2 database Also provide a tool to migrate v2 database: https://github.com/RomiChan/gocq-leveldb-migrate
130 lines
3.0 KiB
Go
130 lines
3.0 KiB
Go
//go:build ignore
|
|
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"go/ast"
|
|
"go/format"
|
|
"go/parser"
|
|
"go/token"
|
|
"os"
|
|
)
|
|
|
|
var output bytes.Buffer
|
|
|
|
func fprintf(format string, args ...interface{}) {
|
|
_, _ = fmt.Fprintf(&output, format, args...)
|
|
}
|
|
|
|
func main() {
|
|
f, _ := parser.ParseFile(token.NewFileSet(), "./../database.go", nil, 0)
|
|
fprintf("// Code generated by mkrw.go; DO NOT EDIT.\n\n")
|
|
fprintf("package leveldb\n\n")
|
|
fprintf("import \"github.com/Mrs4s/go-cqhttp/db\"\n\n")
|
|
ast.Inspect(f, func(node ast.Node) bool {
|
|
switch node := node.(type) {
|
|
case *ast.FuncDecl:
|
|
return false
|
|
case *ast.TypeSpec:
|
|
if !node.Name.IsExported() {
|
|
return false
|
|
}
|
|
x, ok := node.Type.(*ast.StructType)
|
|
if !ok {
|
|
return false
|
|
}
|
|
if x.Fields != nil && x.Fields.List != nil {
|
|
mkWrite(node)
|
|
mkRead(node)
|
|
}
|
|
}
|
|
return true
|
|
})
|
|
out, err := format.Source(output.Bytes())
|
|
if err != nil {
|
|
fmt.Println(string(output.Bytes()))
|
|
panic(err)
|
|
}
|
|
os.WriteFile("database_gen.go", out, 0o644)
|
|
}
|
|
|
|
func typeName(typ ast.Expr) string {
|
|
switch typ := typ.(type) {
|
|
case *ast.Ident:
|
|
return typ.Name
|
|
case *ast.ArrayType:
|
|
if typ.Len != nil {
|
|
panic("unexpected array type")
|
|
}
|
|
return "[]" + typeName(typ.Elt)
|
|
case *ast.SelectorExpr:
|
|
return typeName(typ.X) + "." + typ.Sel.Name
|
|
}
|
|
panic("unexpected type")
|
|
}
|
|
|
|
func mkWrite(node *ast.TypeSpec) {
|
|
typename := node.Name.String()
|
|
structType := node.Type.(*ast.StructType)
|
|
fprintf("func (w *writer) write%s(x *db.%s) {\n", typename, typename)
|
|
fprintf("if x == nil {\n")
|
|
fprintf("w.nil()\n")
|
|
fprintf("return\n")
|
|
fprintf("}\n")
|
|
fprintf("w.coder(coderStruct)\n")
|
|
for _, field := range structType.Fields.List {
|
|
switch typ := field.Type.(type) {
|
|
case *ast.Ident:
|
|
for _, name := range field.Names {
|
|
fprintf("w.%s(x.%s)\n", typ.Name, name.Name)
|
|
}
|
|
case *ast.ArrayType:
|
|
if typeName(typ) != "[]global.MSG" {
|
|
panic("unexpected array type")
|
|
}
|
|
for _, name := range field.Names {
|
|
fprintf("w.arrayMsg(x.%s)\n", name.Name)
|
|
}
|
|
case *ast.StarExpr:
|
|
for _, name := range field.Names {
|
|
fprintf("w.write%s(x.%s)\n", typeName(typ.X), name.Name)
|
|
}
|
|
}
|
|
}
|
|
fprintf("}\n\n")
|
|
}
|
|
|
|
func mkRead(node *ast.TypeSpec) {
|
|
typename := node.Name.String()
|
|
structType := node.Type.(*ast.StructType)
|
|
fprintf(`func (r *reader) read%s() *db.%s {
|
|
coder := r.coder()
|
|
if coder == coderNil {
|
|
return nil
|
|
}`+"\n", typename, typename)
|
|
fprintf("x := &db.%s{}\n", typename)
|
|
for _, field := range structType.Fields.List {
|
|
switch typ := field.Type.(type) {
|
|
case *ast.Ident:
|
|
for _, name := range field.Names {
|
|
fprintf("x.%s = r.%s()\n", name.Name, typ.Name)
|
|
}
|
|
case *ast.ArrayType:
|
|
if typeName(typ) != "[]global.MSG" {
|
|
panic("unexpected array type")
|
|
}
|
|
for _, name := range field.Names {
|
|
fprintf("x.%s = r.arrayMsg()\n", name.Name)
|
|
}
|
|
case *ast.StarExpr:
|
|
for _, name := range field.Names {
|
|
fprintf("x.%s = r.read%s()\n", name.Name, typeName(typ.X))
|
|
}
|
|
}
|
|
}
|
|
fprintf("return x\n")
|
|
fprintf("}\n\n")
|
|
}
|