chore: migrate to gitea
This commit is contained in:
586
vendor/github.com/ugorji/go/codec/gen_mono.go
generated
vendored
Normal file
586
vendor/github.com/ugorji/go/codec/gen_mono.go
generated
vendored
Normal file
@@ -0,0 +1,586 @@
|
||||
// Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||
|
||||
//go:build codec.build
|
||||
|
||||
package codec
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/format"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// This tool will monomorphize types scoped to a specific format.
|
||||
//
|
||||
// This tool only monomorphized the type Name, and not a function Name.
|
||||
// Explicitly, generic functions are not supported, as they cannot be monomorphized
|
||||
// to a specific format without a corresponding name change.
|
||||
//
|
||||
// However, for types constrained to encWriter or decReader,
|
||||
// which are shared across formats, there's no place to put them without duplication.
|
||||
|
||||
const genMonoParserMode = parser.AllErrors | parser.SkipObjectResolution
|
||||
|
||||
var genMonoSpecialFieldTypes = []string{"helperDecReader"}
|
||||
|
||||
// These functions should take the address of first param when monomorphized
|
||||
var genMonoSpecialFunc4Addr = []string{} // {"decByteSlice"}
|
||||
|
||||
var genMonoImportsToSkip = []string{`"errors"`, `"fmt"`, `"net/rpc"`}
|
||||
|
||||
var genMonoRefImportsVia_ = [][2]string{
|
||||
// {"errors", "New"},
|
||||
}
|
||||
|
||||
var genMonoCallsToSkip = []string{"callMake"}
|
||||
|
||||
type genMonoFieldState uint
|
||||
|
||||
const (
|
||||
genMonoFieldRecv genMonoFieldState = iota << 1
|
||||
genMonoFieldParamsResult
|
||||
genMonoFieldStruct
|
||||
)
|
||||
|
||||
type genMonoImports struct {
|
||||
set map[string]struct{}
|
||||
specs []*ast.ImportSpec
|
||||
}
|
||||
|
||||
type genMono struct {
|
||||
files map[string][]byte
|
||||
typParam map[string]*ast.Field
|
||||
typParamTransient map[string]*ast.Field
|
||||
}
|
||||
|
||||
func (x *genMono) init() {
|
||||
x.files = make(map[string][]byte)
|
||||
x.typParam = make(map[string]*ast.Field)
|
||||
x.typParamTransient = make(map[string]*ast.Field)
|
||||
}
|
||||
|
||||
func (x *genMono) reset() {
|
||||
clear(x.typParam)
|
||||
clear(x.typParamTransient)
|
||||
}
|
||||
|
||||
func (m *genMono) hdl(hname string) {
|
||||
m.reset()
|
||||
m.do(hname, []string{"encode.go", "decode.go", hname + ".go"}, []string{"base.notfastpath.go", "base.notfastpath.notmono.go"}, "", "")
|
||||
m.do(hname, []string{"base.notfastpath.notmono.go"}, nil, ".notfastpath", ` && (notfastpath || codec.notfastpath)`)
|
||||
m.do(hname, []string{"base.fastpath.notmono.generated.go"}, []string{"base.fastpath.generated.go"}, ".fastpath", ` && !notfastpath && !codec.notfastpath`)
|
||||
}
|
||||
|
||||
func (m *genMono) do(hname string, fnames, tnames []string, fnameInfx string, buildTagsSfx string) {
|
||||
// keep m.typParams across whole call, as all others use it
|
||||
const fnameSfx = ".mono.generated.go"
|
||||
fname := hname + fnameInfx + fnameSfx
|
||||
|
||||
var imports = genMonoImports{set: make(map[string]struct{})}
|
||||
|
||||
r1, fset := m.merge(fnames, tnames, &imports)
|
||||
m.trFile(r1, hname, true)
|
||||
|
||||
r2, fset := m.merge(fnames, tnames, &imports)
|
||||
m.trFile(r2, hname, false)
|
||||
|
||||
r0 := genMonoOutInit(imports.specs, fname)
|
||||
r0.Decls = append(r0.Decls, r1.Decls...)
|
||||
r0.Decls = append(r0.Decls, r2.Decls...)
|
||||
|
||||
// output r1 to a file
|
||||
f, err := os.Create(fname)
|
||||
halt.onerror(err)
|
||||
defer f.Close()
|
||||
|
||||
var s genMonoStrBuilder
|
||||
s.s(`//go:build !notmono && !codec.notmono `).s(buildTagsSfx).s(`
|
||||
|
||||
// Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||||
|
||||
`)
|
||||
_, err = f.Write(s.v)
|
||||
halt.onerror(err)
|
||||
err = format.Node(f, fset, r0)
|
||||
halt.onerror(err)
|
||||
}
|
||||
|
||||
func (x *genMono) file(fname string) (b []byte) {
|
||||
b = x.files[fname]
|
||||
if b == nil {
|
||||
var err error
|
||||
b, err = os.ReadFile(fname)
|
||||
halt.onerror(err)
|
||||
x.files[fname] = b
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (x *genMono) merge(fNames, tNames []string, imports *genMonoImports) (dst *ast.File, fset *token.FileSet) {
|
||||
// typParams used in fnLoadTyps
|
||||
var typParams map[string]*ast.Field
|
||||
var loadTyps bool
|
||||
fnLoadTyps := func(node ast.Node) bool {
|
||||
var ok bool
|
||||
switch n := node.(type) {
|
||||
case *ast.GenDecl:
|
||||
if n.Tok == token.TYPE {
|
||||
for _, v := range n.Specs {
|
||||
nn := v.(*ast.TypeSpec)
|
||||
ok = genMonoTypeParamsOk(nn.TypeParams)
|
||||
if ok {
|
||||
// each decl will have only 1 var/type
|
||||
typParams[nn.Name.Name] = nn.TypeParams.List[0]
|
||||
if loadTyps {
|
||||
dst.Decls = append(dst.Decls, &ast.GenDecl{Tok: n.Tok, Specs: []ast.Spec{v}})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// we only merge top-level methods and types
|
||||
fnIdX := func(n *ast.FuncDecl, n2 *ast.IndexExpr) (ok bool) {
|
||||
n9, ok9 := n2.Index.(*ast.Ident)
|
||||
n3, ok := n2.X.(*ast.Ident) // n3 = type name
|
||||
ok = ok && ok9 && n9.Name == "T"
|
||||
if ok {
|
||||
_, ok = x.typParam[n3.Name]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fnLoadMethodsAndImports := func(node ast.Node) bool {
|
||||
var ok bool
|
||||
switch n := node.(type) {
|
||||
case *ast.FuncDecl:
|
||||
// TypeParams is nil for methods, as it is defined at the type node
|
||||
// instead, look at the name, and
|
||||
// if IndexExpr.Index=T, and IndexExpr.X matches a type name seen already
|
||||
// then ok = true
|
||||
if n.Recv == nil || len(n.Recv.List) != 1 {
|
||||
return false
|
||||
}
|
||||
ok = false
|
||||
switch nn := n.Recv.List[0].Type.(type) {
|
||||
case *ast.IndexExpr:
|
||||
ok = fnIdX(n, nn)
|
||||
case *ast.StarExpr:
|
||||
switch nn2 := nn.X.(type) {
|
||||
case *ast.IndexExpr:
|
||||
ok = fnIdX(n, nn2)
|
||||
}
|
||||
}
|
||||
if ok {
|
||||
dst.Decls = append(dst.Decls, n)
|
||||
}
|
||||
return false
|
||||
case *ast.GenDecl:
|
||||
if n.Tok == token.IMPORT {
|
||||
for _, v := range n.Specs {
|
||||
nn := v.(*ast.ImportSpec)
|
||||
if slices.Contains(genMonoImportsToSkip, nn.Path.Value) {
|
||||
continue
|
||||
}
|
||||
if _, ok = imports.set[nn.Path.Value]; !ok {
|
||||
imports.specs = append(imports.specs, nn)
|
||||
imports.set[nn.Path.Value] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fset = token.NewFileSet()
|
||||
fnLoadAsts := func(names []string) (asts []*ast.File) {
|
||||
for _, fname := range names {
|
||||
fsrc := x.file(fname)
|
||||
f, err := parser.ParseFile(fset, fname, fsrc, genMonoParserMode)
|
||||
halt.onerror(err)
|
||||
asts = append(asts, f)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
clear(x.typParamTransient)
|
||||
|
||||
dst = &ast.File{
|
||||
Name: &ast.Ident{Name: "codec"},
|
||||
}
|
||||
|
||||
fs := fnLoadAsts(fNames)
|
||||
ts := fnLoadAsts(tNames)
|
||||
|
||||
loadTyps = true
|
||||
typParams = x.typParam
|
||||
for _, v := range fs {
|
||||
ast.Inspect(v, fnLoadTyps)
|
||||
}
|
||||
loadTyps = false
|
||||
typParams = x.typParamTransient
|
||||
for _, v := range ts {
|
||||
ast.Inspect(v, fnLoadTyps)
|
||||
}
|
||||
typParams = nil
|
||||
for _, v := range fs {
|
||||
ast.Inspect(v, fnLoadMethodsAndImports)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (x *genMono) trFile(r *ast.File, hname string, isbytes bool) {
|
||||
fn := func(node ast.Node) bool {
|
||||
switch n := node.(type) {
|
||||
case *ast.TypeSpec:
|
||||
// type x[T encDriver] struct { ... }
|
||||
if !genMonoTypeParamsOk(n.TypeParams) {
|
||||
return false
|
||||
}
|
||||
x.trType(n, hname, isbytes)
|
||||
return false
|
||||
case *ast.FuncDecl:
|
||||
if n.Recv == nil || len(n.Recv.List) != 1 {
|
||||
return false
|
||||
}
|
||||
if _, ok := n.Recv.List[0].Type.(*ast.Ident); ok {
|
||||
return false
|
||||
}
|
||||
tp := x.trMethodSign(n, hname, isbytes) // receiver, params, results
|
||||
// handle the body
|
||||
x.trMethodBody(n.Body, tp, hname, isbytes)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
ast.Inspect(r, fn)
|
||||
|
||||
// set type params to nil, and Pos to NoPos
|
||||
fn = func(node ast.Node) bool {
|
||||
switch n := node.(type) {
|
||||
case *ast.FuncType:
|
||||
if genMonoTypeParamsOk(n.TypeParams) {
|
||||
n.TypeParams = nil
|
||||
}
|
||||
case *ast.TypeSpec: // for type ...
|
||||
if genMonoTypeParamsOk(n.TypeParams) {
|
||||
n.TypeParams = nil
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
ast.Inspect(r, fn)
|
||||
}
|
||||
|
||||
func (x *genMono) trType(n *ast.TypeSpec, hname string, isbytes bool) {
|
||||
sfx, _, _, hnameUp := genMonoIsBytesVals(hname, isbytes)
|
||||
tp := n.TypeParams.List[0]
|
||||
switch tp.Type.(*ast.Ident).Name {
|
||||
case "encDriver", "decDriver":
|
||||
n.Name.Name += hnameUp + sfx
|
||||
case "encWriter", "decReader":
|
||||
n.Name.Name += sfx
|
||||
}
|
||||
|
||||
// handle the Struct and Array types
|
||||
switch nn := n.Type.(type) {
|
||||
case *ast.StructType:
|
||||
x.trStruct(nn, tp, hname, isbytes)
|
||||
case *ast.ArrayType:
|
||||
x.trArray(nn, tp, hname, isbytes)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *genMono) trMethodSign(n *ast.FuncDecl, hname string, isbytes bool) (tp *ast.Field) {
|
||||
// check if recv type is not parameterized
|
||||
tp = x.trField(n.Recv.List[0], nil, hname, isbytes, genMonoFieldRecv)
|
||||
// handle params and results
|
||||
x.trMethodSignNonRecv(n.Type.Params, tp, hname, isbytes)
|
||||
x.trMethodSignNonRecv(n.Type.Results, tp, hname, isbytes)
|
||||
return
|
||||
}
|
||||
|
||||
func (x *genMono) trMethodSignNonRecv(r *ast.FieldList, tp *ast.Field, hname string, isbytes bool) {
|
||||
if r == nil || len(r.List) == 0 {
|
||||
return
|
||||
}
|
||||
for _, v := range r.List {
|
||||
x.trField(v, tp, hname, isbytes, genMonoFieldParamsResult)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *genMono) trStruct(r *ast.StructType, tp *ast.Field, hname string, isbytes bool) {
|
||||
// search for fields, and update accordingly
|
||||
// type x[T encDriver] struct { w T }
|
||||
// var x *A[T]
|
||||
// A[T]
|
||||
if r == nil || r.Fields == nil || len(r.Fields.List) == 0 {
|
||||
return
|
||||
}
|
||||
for _, v := range r.Fields.List {
|
||||
x.trField(v, tp, hname, isbytes, genMonoFieldStruct)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *genMono) trArray(n *ast.ArrayType, tp *ast.Field, hname string, isbytes bool) {
|
||||
sfx, _, _, hnameUp := genMonoIsBytesVals(hname, isbytes)
|
||||
// type fastpathEs[T encDriver] [56]fastpathE[T]
|
||||
// p := tp.Names[0].Name
|
||||
switch elt := n.Elt.(type) {
|
||||
// case *ast.InterfaceType:
|
||||
case *ast.IndexExpr:
|
||||
if elt.Index.(*ast.Ident).Name == "T" { // generic
|
||||
n.Elt = ast.NewIdent(elt.X.(*ast.Ident).Name + hnameUp + sfx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (x *genMono) trMethodBody(r *ast.BlockStmt, tp *ast.Field, hname string, isbytes bool) {
|
||||
// find the parent node for an indexExpr, or a T/*T, and set the value back in there
|
||||
|
||||
fn := func(pnode ast.Node) bool {
|
||||
var pn *ast.Ident
|
||||
fnUp := func() {
|
||||
x.updateIdentForT(pn, hname, tp, isbytes, false)
|
||||
}
|
||||
switch n := pnode.(type) {
|
||||
// case *ast.SelectorExpr:
|
||||
// case *ast.TypeAssertExpr:
|
||||
// case *ast.IndexExpr:
|
||||
case *ast.StarExpr:
|
||||
if genMonoUpdateIndexExprT(&pn, n.X) {
|
||||
n.X = pn
|
||||
fnUp()
|
||||
}
|
||||
case *ast.CallExpr:
|
||||
for i4, n4 := range n.Args {
|
||||
if genMonoUpdateIndexExprT(&pn, n4) {
|
||||
n.Args[i4] = pn
|
||||
fnUp()
|
||||
}
|
||||
}
|
||||
if n4, ok4 := n.Fun.(*ast.Ident); ok4 && slices.Contains(genMonoSpecialFunc4Addr, n4.Name) {
|
||||
n.Args[0] = &ast.UnaryExpr{Op: token.AND, X: n.Args[0].(*ast.SelectorExpr)}
|
||||
}
|
||||
case *ast.CompositeLit:
|
||||
if genMonoUpdateIndexExprT(&pn, n.Type) {
|
||||
n.Type = pn
|
||||
fnUp()
|
||||
}
|
||||
case *ast.ArrayType:
|
||||
if genMonoUpdateIndexExprT(&pn, n.Elt) {
|
||||
n.Elt = pn
|
||||
fnUp()
|
||||
}
|
||||
case *ast.ValueSpec:
|
||||
for i2, n2 := range n.Values {
|
||||
if genMonoUpdateIndexExprT(&pn, n2) {
|
||||
n.Values[i2] = pn
|
||||
fnUp()
|
||||
}
|
||||
}
|
||||
if genMonoUpdateIndexExprT(&pn, n.Type) {
|
||||
n.Type = pn
|
||||
fnUp()
|
||||
}
|
||||
case *ast.BinaryExpr:
|
||||
// early return here, since the 2 things can apply
|
||||
if genMonoUpdateIndexExprT(&pn, n.X) {
|
||||
n.X = pn
|
||||
fnUp()
|
||||
}
|
||||
if genMonoUpdateIndexExprT(&pn, n.Y) {
|
||||
n.Y = pn
|
||||
fnUp()
|
||||
}
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
ast.Inspect(r, fn)
|
||||
}
|
||||
|
||||
func (x *genMono) trField(f *ast.Field, tpt *ast.Field, hname string, isbytes bool, state genMonoFieldState) (tp *ast.Field) {
|
||||
var pn *ast.Ident
|
||||
switch nn := f.Type.(type) {
|
||||
case *ast.IndexExpr:
|
||||
if genMonoUpdateIndexExprT(&pn, nn) {
|
||||
f.Type = pn
|
||||
}
|
||||
case *ast.StarExpr:
|
||||
if genMonoUpdateIndexExprT(&pn, nn.X) {
|
||||
nn.X = pn
|
||||
}
|
||||
case *ast.FuncType:
|
||||
x.trMethodSignNonRecv(nn.Params, tpt, hname, isbytes)
|
||||
x.trMethodSignNonRecv(nn.Results, tpt, hname, isbytes)
|
||||
return
|
||||
case *ast.ArrayType:
|
||||
x.trArray(nn, tpt, hname, isbytes)
|
||||
return
|
||||
case *ast.Ident:
|
||||
if state == genMonoFieldRecv || nn.Name != "T" {
|
||||
return
|
||||
}
|
||||
pn = nn // "T"
|
||||
if state == genMonoFieldParamsResult {
|
||||
f.Type = &ast.StarExpr{X: pn}
|
||||
}
|
||||
}
|
||||
if pn == nil {
|
||||
return
|
||||
}
|
||||
|
||||
tp = x.updateIdentForT(pn, hname, tpt, isbytes, true)
|
||||
return
|
||||
}
|
||||
|
||||
func (x *genMono) updateIdentForT(pn *ast.Ident, hname string, tp *ast.Field,
|
||||
isbytes bool, lookupTP bool) (tp2 *ast.Field) {
|
||||
sfx, writer, reader, hnameUp := genMonoIsBytesVals(hname, isbytes)
|
||||
// handle special ones e.g. helperDecReader et al
|
||||
if slices.Contains(genMonoSpecialFieldTypes, pn.Name) {
|
||||
pn.Name += sfx
|
||||
return
|
||||
}
|
||||
|
||||
if pn.Name != "T" && lookupTP {
|
||||
tp = x.typParam[pn.Name]
|
||||
if tp == nil {
|
||||
tp = x.typParamTransient[pn.Name]
|
||||
}
|
||||
}
|
||||
|
||||
paramtyp := tp.Type.(*ast.Ident).Name
|
||||
if pn.Name == "T" {
|
||||
switch paramtyp {
|
||||
case "encDriver", "decDriver":
|
||||
pn.Name = hname + genMonoTitleCase(paramtyp) + sfx
|
||||
case "encWriter":
|
||||
pn.Name = writer
|
||||
case "decReader":
|
||||
pn.Name = reader
|
||||
}
|
||||
} else {
|
||||
switch paramtyp {
|
||||
case "encDriver", "decDriver":
|
||||
pn.Name += hnameUp + sfx
|
||||
case "encWriter", "decReader":
|
||||
pn.Name += sfx
|
||||
}
|
||||
}
|
||||
return tp
|
||||
}
|
||||
|
||||
func genMonoUpdateIndexExprT(pn **ast.Ident, node ast.Node) (pnok bool) {
|
||||
*pn = nil
|
||||
if n2, ok := node.(*ast.IndexExpr); ok {
|
||||
n9, ok9 := n2.Index.(*ast.Ident)
|
||||
n3, ok := n2.X.(*ast.Ident)
|
||||
if ok && ok9 && n9.Name == "T" {
|
||||
*pn, pnok = ast.NewIdent(n3.Name), true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func genMonoTitleCase(s string) string {
|
||||
return strings.ToUpper(s[:1]) + s[1:]
|
||||
}
|
||||
|
||||
func genMonoIsBytesVals(hName string, isbytes bool) (suffix, writer, reader, hNameUp string) {
|
||||
hNameUp = genMonoTitleCase(hName)
|
||||
if isbytes {
|
||||
return "Bytes", "bytesEncAppender", "bytesDecReader", hNameUp
|
||||
}
|
||||
return "IO", "bufioEncWriter", "ioDecReader", hNameUp
|
||||
}
|
||||
|
||||
func genMonoTypeParamsOk(v *ast.FieldList) (ok bool) {
|
||||
if v == nil || v.List == nil || len(v.List) != 1 {
|
||||
return false
|
||||
}
|
||||
pn := v.List[0]
|
||||
if len(pn.Names) != 1 {
|
||||
return false
|
||||
}
|
||||
pnName := pn.Names[0].Name
|
||||
if pnName != "T" {
|
||||
return false
|
||||
}
|
||||
// ignore any nodes which are not idents e.g. cmp.orderedRv
|
||||
vv, ok := pn.Type.(*ast.Ident)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
switch vv.Name {
|
||||
case "encDriver", "decDriver", "encWriter", "decReader":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func genMonoCopy(src *ast.File) (dst *ast.File) {
|
||||
dst = &ast.File{
|
||||
Name: &ast.Ident{Name: "codec"},
|
||||
}
|
||||
dst.Decls = append(dst.Decls, src.Decls...)
|
||||
return
|
||||
}
|
||||
|
||||
type genMonoStrBuilder struct {
|
||||
v []byte
|
||||
}
|
||||
|
||||
func (x *genMonoStrBuilder) s(v string) *genMonoStrBuilder {
|
||||
x.v = append(x.v, v...)
|
||||
return x
|
||||
}
|
||||
|
||||
func genMonoOutInit(importSpecs []*ast.ImportSpec, fname string) (f *ast.File) {
|
||||
// ParseFile seems to skip the //go:build stanza
|
||||
// it should be written directly into the file
|
||||
var s genMonoStrBuilder
|
||||
s.s(`
|
||||
package codec
|
||||
|
||||
import (
|
||||
`)
|
||||
for _, v := range importSpecs {
|
||||
s.s("\t").s(v.Path.Value).s("\n")
|
||||
}
|
||||
s.s(")\n")
|
||||
for _, v := range genMonoRefImportsVia_ {
|
||||
s.s("var _ = ").s(v[0]).s(".").s(v[1]).s("\n")
|
||||
}
|
||||
f, err := parser.ParseFile(token.NewFileSet(), fname, s.v, genMonoParserMode)
|
||||
halt.onerror(err)
|
||||
return
|
||||
}
|
||||
|
||||
func genMonoAll() {
|
||||
// hdls := []Handle{
|
||||
// (*SimpleHandle)(nil),
|
||||
// (*JsonHandle)(nil),
|
||||
// (*CborHandle)(nil),
|
||||
// (*BincHandle)(nil),
|
||||
// (*MsgpackHandle)(nil),
|
||||
// }
|
||||
hdls := []string{"simple", "json", "cbor", "binc", "msgpack"}
|
||||
var m genMono
|
||||
m.init()
|
||||
for _, v := range hdls {
|
||||
m.hdl(v)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user