func (s *BaseElem) TypeName() string {
	if s.common.alias != "" {
		return s.common.alias
	}
	s.common.Alias(s.BaseType())
	return s.common.alias
}
TypeName returns the canonical Go type name for the base element.
package gen
import (
	"fmt"
	"strings"
)
var (
	identNext   = 0
	identPrefix = "za"
)
func resetIdent(prefix string) {
	identPrefix = prefix
	identNext = 0
}
func randIdent() string {
	identNext++
	return fmt.Sprintf("%s%04d", identPrefix, identNext)
}
type primitive uint8
const (
	Invalid primitive = iota
	Bytes
	String
	Float32
	Float64
	Complex64
	Complex128
	Uint
	Uint8
	Uint16
	Uint32
	Uint64
	Byte
	Int
	Int8
	Int16
	Int32
	Int64
	Bool
	Intf  
	Time  
	Ext   
	IDENT  
)
func (k primitive) String() string {
	switch k {
	case String:
		return "String"
	case Bytes:
		return "Bytes"
	case Float32:
		return "Float32"
	case Float64:
		return "Float64"
	case Complex64:
		return "Complex64"
	case Complex128:
		return "Complex128"
	case Uint:
		return "Uint"
	case Uint8:
		return "Uint8"
	case Uint16:
		return "Uint16"
	case Uint32:
		return "Uint32"
	case Uint64:
		return "Uint64"
	case Byte:
		return "Byte"
	case Int:
		return "Int"
	case Int8:
		return "Int8"
	case Int16:
		return "Int16"
	case Int32:
		return "Int32"
	case Int64:
		return "Int64"
	case Bool:
		return "Bool"
	case Intf:
		return "Intf"
	case Time:
		return "time.Time"
	case Ext:
		return "Extension"
	case IDENT:
		return "Ident"
	default:
		return "INVALID"
	}
}
var primitives = map[string]primitive{
	"[]byte":         Bytes,
	"string":         String,
	"float32":        Float32,
	"float64":        Float64,
	"complex64":      Complex64,
	"complex128":     Complex128,
	"uint":           Uint,
	"uint8":          Uint8,
	"uint16":         Uint16,
	"uint32":         Uint32,
	"uint64":         Uint64,
	"byte":           Byte,
	"rune":           Int32,
	"int":            Int,
	"int8":           Int8,
	"int16":          Int16,
	"int32":          Int32,
	"int64":          Int64,
	"bool":           Bool,
	"interface{}":    Intf,
	"time.Time":      Time,
	"msgp.Extension": Ext,
}
var builtIns = map[string]struct{}{
	"msgp.Raw":    {},
	"msgp.Number": {},
}
type common struct{ vname, alias string }
func (c *common) SetVarname(s string) { c.vname = s }
func (c *common) Varname() string     { return c.vname }
func (c *common) Alias(typ string)    { c.alias = typ }
func isPrintable(e Elem) bool {
	if be, ok := e.(*BaseElem); ok && !be.Printable() {
		return false
	}
	return true
}
type Elem interface {
	SetVarname(s string)
	Varname() string
	TypeName() string
	Alias(typ string)
	Copy() Elem
	Complexity() int
}
func Ident(id string) *BaseElem {
	p, ok := primitives[id]
	if ok {
		return &BaseElem{Value: p}
	}
	be := &BaseElem{Value: IDENT}
	be.Alias(id)
	return be
}
type Array struct {
	common
	Index string  
	Size  string  
	Els   Elem    
}
func (a *Array) SetVarname(s string) {
	a.common.SetVarname(s)
	for a.Index == "" || strings.Contains(a.Varname(), a.Index) {
		a.Index = randIdent()
	}
	a.Els.SetVarname(a.Varname() + "[" + a.Index + "]")
}
func (a *Array) TypeName() string {
	if a.common.alias != "" {
		return a.common.alias
	}
	a.common.Alias("[" + a.Size + "]" + a.Els.TypeName())
	return a.common.alias
}
func (a *Array) Copy() Elem {
	b := *a
	b.Els = a.Els.Copy()
	return &b
}
func (a *Array) Complexity() int { return 1 + a.Els.Complexity() }
type Map struct {
	common
	KeyIndx string  
	ValIndx string  
	Value   Elem    
}
func (m *Map) SetVarname(s string) {
	m.common.SetVarname(s)
	m.KeyIndx = randIdent()
	for m.ValIndx == "" || m.ValIndx == m.KeyIndx {
		m.ValIndx = randIdent()
	}
	m.Value.SetVarname(m.ValIndx)
}
func (m *Map) TypeName() string {
	if m.common.alias != "" {
		return m.common.alias
	}
	m.common.Alias("map[string]" + m.Value.TypeName())
	return m.common.alias
}
func (m *Map) Copy() Elem {
	g := *m
	g.Value = m.Value.Copy()
	return &g
}
func (m *Map) Complexity() int { return 2 + m.Value.Complexity() }
type Slice struct {
	common
	Index string
	Els   Elem  
}
func (s *Slice) SetVarname(n string) {
	s.common.SetVarname(n)
	s.Index = randIdent()
	vn := s.Varname()
	if vn[0] == '*' {
		vn = "(" + vn + ")"
	}
	s.Els.SetVarname(vn + "[" + s.Index + "]")
}
func (s *Slice) TypeName() string {
	if s.common.alias != "" {
		return s.common.alias
	}
	s.common.Alias("[]" + s.Els.TypeName())
	return s.common.alias
}
func (s *Slice) Copy() Elem {
	z := *s
	z.Els = s.Els.Copy()
	return &z
}
func (s *Slice) Complexity() int {
	return 1 + s.Els.Complexity()
}
type Ptr struct {
	common
	Value Elem
}
func (s *Ptr) SetVarname(n string) {
	s.common.SetVarname(n)
	switch x := s.Value.(type) {
	case *Struct:
		x.SetVarname(n)
		return
	case *BaseElem:
		if x.Value == IDENT {
			x.SetVarname(n)
		} else {
			x.SetVarname("*" + n)
		}
		return
	default:
		s.Value.SetVarname("*" + n)
		return
	}
}
func (s *Ptr) TypeName() string {
	if s.common.alias != "" {
		return s.common.alias
	}
	s.common.Alias("*" + s.Value.TypeName())
	return s.common.alias
}
func (s *Ptr) Copy() Elem {
	v := *s
	v.Value = s.Value.Copy()
	return &v
}
func (s *Ptr) Complexity() int { return 1 + s.Value.Complexity() }
func (s *Ptr) NeedsInit() bool {
	if be, ok := s.Value.(*BaseElem); ok && be.needsref {
		return false
	}
	return true
}
type Struct struct {
	common
	Fields  []structField  
	AsTuple bool           
}
func (s *Struct) TypeName() string {
	if s.common.alias != "" {
		return s.common.alias
	}
	str := "struct{\n"
	for i := range s.Fields {
		str += s.Fields[i].fieldName +
			" " + s.Fields[i].fieldElem.TypeName() +
			" " + s.Fields[i].rawTag + "\n"
	}
	str += "}"
	s.common.Alias(str)
	return s.common.alias
}
func (s *Struct) SetVarname(a string) {
	s.common.SetVarname(a)
	writeStructFields(s.Fields, a)
}
func (s *Struct) Copy() Elem {
	g := *s
	g.Fields = make([]structField, len(s.Fields))
	copy(g.Fields, s.Fields)
	for i := range s.Fields {
		g.Fields[i].fieldElem = s.Fields[i].fieldElem.Copy()
	}
	return &g
}
func (s *Struct) Complexity() int {
	c := 1
	for i := range s.Fields {
		c += s.Fields[i].fieldElem.Complexity()
	}
	return c
}
type structField struct {
	fieldTag  string  
	rawTag    string  
	fieldName string  
	fieldElem Elem    
}
func writeStructFields(s []structField, structName string) {
	for i := range s {
		s[i].fieldElem.SetVarname(fmt.Sprintf("%s.%s", structName, s[i].fieldName))
	}
}
type ShimMode uint8
const (
	Cast ShimMode = 0
	Convert ShimMode = 1
)
type BaseElem struct {
	common
	ShimMode     ShimMode   
	ShimToBase   string     
	ShimFromBase string     
	Value        primitive  
	Convert      bool       
	mustinline   bool       
	needsref     bool       
}
func (s *BaseElem) Printable() bool { return !s.mustinline }
func (s *BaseElem) Alias(typ string) {
	s.common.Alias(typ)
	if s.Value != IDENT {
		s.Convert = true
	}
	if strings.Contains(typ, ".") {
		s.mustinline = true
	}
}
func (s *BaseElem) SetVarname(a string) {
	if s.Value == Ext || s.needsref {
		if strings.HasPrefix(a, "*") {
			s.common.SetVarname(a[1:])
			return
		}
		s.common.SetVarname("&" + a)
		return
	}
	s.common.SetVarname(a)
}