...

Source file src/github.com/twmb/franz-go/generate/main.go

Documentation: github.com/twmb/franz-go/generate

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"sort"
    10  	"strconv"
    11  	"strings"
    12  )
    13  
    14  var maxKey int
    15  
    16  func die(why string, args ...any) {
    17  	fmt.Fprintf(os.Stderr, why+"\n", args...)
    18  	os.Exit(1)
    19  }
    20  
    21  type (
    22  	// LineWriter writes lines at a time.
    23  	LineWriter struct {
    24  		buf  *bytes.Buffer
    25  		line int
    26  	}
    27  
    28  	Type interface {
    29  		WriteAppend(*LineWriter)
    30  		WriteDecode(*LineWriter)
    31  		TypeName() string
    32  	}
    33  
    34  	Bool struct {
    35  		HasDefault bool
    36  		Default    bool
    37  	}
    38  	Int8 struct {
    39  		HasDefault bool
    40  		Default    int8
    41  	}
    42  	Int16 struct {
    43  		HasDefault bool
    44  		Default    int16
    45  	}
    46  	Uint16 struct {
    47  		HasDefault bool
    48  		Default    uint16
    49  	}
    50  	Int32 struct {
    51  		HasDefault bool
    52  		Default    int32
    53  	}
    54  	Int64 struct {
    55  		HasDefault bool
    56  		Default    int64
    57  	}
    58  	Float64 struct {
    59  		HasDefault bool
    60  		Default    float64
    61  	}
    62  	Uint32 struct {
    63  		HasDefault bool
    64  		Default    uint32
    65  	}
    66  	Varint struct {
    67  		HasDefault bool
    68  		Default    int32
    69  	}
    70  	Varlong struct {
    71  		HasDefault bool
    72  		Default    int64
    73  	}
    74  	Uuid         struct{}
    75  	VarintString struct{}
    76  	VarintBytes  struct{}
    77  
    78  	FieldLengthMinusBytes struct {
    79  		Field       string
    80  		LengthMinus int
    81  	}
    82  
    83  	// The following types can be encoded "compact"; this happens on
    84  	// flexible versions. If adding types here, be sure to add the
    85  	// AsFromFlexible method below.
    86  
    87  	String struct {
    88  		FromFlexible bool
    89  	}
    90  	NullableString struct {
    91  		HasDefault      bool
    92  		FromFlexible    bool
    93  		NullableVersion int
    94  	}
    95  	Bytes struct {
    96  		FromFlexible bool
    97  	}
    98  	NullableBytes struct {
    99  		HasDefault   bool
   100  		FromFlexible bool
   101  	}
   102  
   103  	Array struct {
   104  		Inner           Type
   105  		IsVarintArray   bool
   106  		IsNullableArray bool
   107  		NullableVersion int
   108  
   109  		HasDefault bool
   110  
   111  		// FromFlexible is true if this is inside a struct that has
   112  		// flexible versions.
   113  		FromFlexible bool
   114  	}
   115  
   116  	StructField struct {
   117  		Comment    string
   118  		MinVersion int
   119  		MaxVersion int
   120  		Tag        int
   121  		FieldName  string
   122  		Type       Type
   123  	}
   124  
   125  	Throttle struct {
   126  		Switchup int
   127  	}
   128  	Timeout struct {
   129  		Int32
   130  	}
   131  
   132  	Struct struct {
   133  		TopLevel         bool
   134  		WithVersionField bool // if not top level
   135  		WithNoEncoding   bool // if not top level
   136  		Anonymous        bool // if inner struct
   137  		Comment          string
   138  		Name             string
   139  
   140  		HasDefault bool
   141  
   142  		// FromFlexible tracks if this struct is either
   143  		// (a) top level and has flexible versions, or
   144  		// (b) nested in a top level struct that has flexible versions
   145  		FromFlexible bool
   146  		Nullable     bool
   147  
   148  		Fields []StructField
   149  
   150  		Key int // -1 if not top level
   151  
   152  		// Only TopLevel relevant fields:
   153  		Admin            bool
   154  		GroupCoordinator bool
   155  		TxnCoordinator   bool
   156  		MaxVersion       int
   157  		FlexibleAt       int
   158  		ResponseKind     string // for requests
   159  		RequestKind      string // for responses
   160  	}
   161  
   162  	EnumValue struct {
   163  		Comment string
   164  		Value   int
   165  		Word    string
   166  	}
   167  
   168  	Enum struct {
   169  		Comment string
   170  		Name    string
   171  		Type
   172  
   173  		HasZero   bool
   174  		CamelCase bool
   175  
   176  		Values []EnumValue
   177  	}
   178  )
   179  
   180  /////////////////////
   181  // DEFAULT SETTING //
   182  /////////////////////
   183  
   184  type Defaulter interface {
   185  	SetDefault(string) Type
   186  	GetDefault() (any, bool)
   187  	GetTypeDefault() any
   188  }
   189  
   190  func (e Enum) SetDefault(s string) Type {
   191  	e.Type = e.Type.(Defaulter).SetDefault(s)
   192  	return e
   193  }
   194  func (e Enum) GetDefault() (any, bool) { return e.Type.(Defaulter).GetDefault() }
   195  func (e Enum) GetTypeDefault() any     { return e.Type.(Defaulter).GetTypeDefault() }
   196  
   197  func (b Bool) SetDefault(s string) Type {
   198  	v, err := strconv.ParseBool(s)
   199  	if err != nil {
   200  		die("invalid bool default: %v", err)
   201  	}
   202  	b.Default = v
   203  	b.HasDefault = true
   204  	return b
   205  }
   206  func (b Bool) GetDefault() (any, bool) { return b.Default, b.HasDefault }
   207  func (Bool) GetTypeDefault() any       { return false }
   208  
   209  func (i Int8) SetDefault(s string) Type {
   210  	v, err := strconv.ParseInt(s, 0, 8)
   211  	if err != nil {
   212  		die("invalid int8 default: %v", err)
   213  	}
   214  	i.Default = int8(v)
   215  	i.HasDefault = true
   216  	return i
   217  }
   218  func (i Int8) GetDefault() (any, bool) { return i.Default, i.HasDefault }
   219  func (Int8) GetTypeDefault() any       { return 0 }
   220  
   221  func (i Int16) SetDefault(s string) Type {
   222  	v, err := strconv.ParseInt(s, 0, 16)
   223  	if err != nil {
   224  		die("invalid int16 default: %v", err)
   225  	}
   226  	i.Default = int16(v)
   227  	i.HasDefault = true
   228  	return i
   229  }
   230  func (i Int16) GetDefault() (any, bool) { return i.Default, i.HasDefault }
   231  func (Int16) GetTypeDefault() any       { return 0 }
   232  
   233  func (u Uint16) SetDefault(s string) Type {
   234  	v, err := strconv.ParseUint(s, 0, 16)
   235  	if err != nil {
   236  		die("invalid uint16 default: %v", err)
   237  	}
   238  	u.Default = uint16(v)
   239  	u.HasDefault = true
   240  	return u
   241  }
   242  func (u Uint16) GetDefault() (any, bool) { return u.Default, u.HasDefault }
   243  func (Uint16) GetTypeDefault() any       { return 0 }
   244  
   245  func (i Int32) SetDefault(s string) Type {
   246  	v, err := strconv.ParseInt(s, 0, 32)
   247  	if err != nil {
   248  		die("invalid int32 default: %v", err)
   249  	}
   250  	i.Default = int32(v)
   251  	i.HasDefault = true
   252  	return i
   253  }
   254  func (i Int32) GetDefault() (any, bool) { return i.Default, i.HasDefault }
   255  func (Int32) GetTypeDefault() any       { return 0 }
   256  
   257  func (t Timeout) SetDefault(s string) Type {
   258  	t.Int32 = t.Int32.SetDefault(s).(Int32)
   259  	return t
   260  }
   261  
   262  func (i Int64) SetDefault(s string) Type {
   263  	v, err := strconv.ParseInt(s, 0, 64)
   264  	if err != nil {
   265  		die("invalid int64 default: %v", err)
   266  	}
   267  	i.Default = v
   268  	i.HasDefault = true
   269  	return i
   270  }
   271  func (i Int64) GetDefault() (any, bool) { return i.Default, i.HasDefault }
   272  func (Int64) GetTypeDefault() any       { return 0 }
   273  
   274  func (f Float64) SetDefault(s string) Type {
   275  	v, err := strconv.ParseFloat(s, 64)
   276  	if err != nil {
   277  		die("invalid float64 default: %v", err)
   278  	}
   279  	f.Default = v
   280  	f.HasDefault = true
   281  	return f
   282  }
   283  func (f Float64) GetDefault() (any, bool) { return f.Default, f.HasDefault }
   284  func (Float64) GetTypeDefault() any       { return 0 }
   285  
   286  func (u Uint32) SetDefault(s string) Type {
   287  	v, err := strconv.ParseUint(s, 10, 32)
   288  	if err != nil {
   289  		die("invalid uint32 default: %v", err)
   290  	}
   291  	u.Default = uint32(v)
   292  	u.HasDefault = true
   293  	return u
   294  }
   295  func (u Uint32) GetDefault() (any, bool) { return u.Default, u.HasDefault }
   296  func (Uint32) GetTypeDefault() any       { return 0 }
   297  
   298  func (i Varint) SetDefault(s string) Type {
   299  	v, err := strconv.ParseInt(s, 0, 32)
   300  	if err != nil {
   301  		die("invalid varint default: %v", err)
   302  	}
   303  	i.Default = int32(v)
   304  	i.HasDefault = true
   305  	return i
   306  }
   307  func (i Varint) GetDefault() (any, bool) { return i.Default, i.HasDefault }
   308  func (Varint) GetTypeDefault() any       { return 0 }
   309  
   310  func (i Varlong) SetDefault(s string) Type {
   311  	v, err := strconv.ParseInt(s, 0, 64)
   312  	if err != nil {
   313  		die("invalid varlong default: %v", err)
   314  	}
   315  	i.Default = v
   316  	i.HasDefault = true
   317  	return i
   318  }
   319  func (i Varlong) GetDefault() (any, bool) { return i.Default, i.HasDefault }
   320  func (Varlong) GetTypeDefault() any       { return 0 }
   321  
   322  func (s NullableString) SetDefault(v string) Type {
   323  	if v != "null" {
   324  		die("unknown non-null default for nullable string")
   325  	}
   326  	s.HasDefault = true
   327  	return s
   328  }
   329  
   330  func (s NullableString) GetDefault() (any, bool) {
   331  	return "nil", s.HasDefault // we return the string so it is rendered correctly
   332  }
   333  func (NullableString) GetTypeDefault() any { return "nil" }
   334  
   335  func (b NullableBytes) SetDefault(v string) Type {
   336  	if v != "null" {
   337  		die("unknown non-null default for nullable string")
   338  	}
   339  	b.HasDefault = true
   340  	return b
   341  }
   342  
   343  func (b NullableBytes) GetDefault() (any, bool) {
   344  	return "nil", b.HasDefault
   345  }
   346  func (NullableBytes) GetTypeDefault() any { return "nil" }
   347  
   348  func (a Array) SetDefault(v string) Type {
   349  	if v != "null" {
   350  		die("unknown non-null default for array")
   351  	}
   352  	a.HasDefault = true
   353  	return a
   354  }
   355  
   356  func (a Array) GetDefault() (any, bool) {
   357  	return "nil", a.HasDefault
   358  }
   359  func (Array) GetTypeDefault() any { return "nil" }
   360  
   361  func (s Struct) SetDefault(string) Type {
   362  	die("cannot set default on a struct; we already have a default")
   363  	return s
   364  }
   365  
   366  func (Struct) GetDefault() (any, bool) {
   367  	return "", false // no GetDefault
   368  }
   369  
   370  func (s Struct) GetTypeDefault() any {
   371  	if s.Nullable {
   372  		return "nil"
   373  	}
   374  	// This will not work if a tagged type has its own arrays, but for now
   375  	// nothing has that.
   376  	return fmt.Sprintf("(func() %[1]s { var v %[1]s; v.Default(); return v })() ", s.Name)
   377  }
   378  
   379  type FlexibleSetter interface {
   380  	AsFromFlexible() Type
   381  }
   382  
   383  func (s String) AsFromFlexible() Type         { dup := s; dup.FromFlexible = true; return dup }
   384  func (s NullableString) AsFromFlexible() Type { dup := s; dup.FromFlexible = true; return dup }
   385  func (b Bytes) AsFromFlexible() Type          { dup := b; dup.FromFlexible = true; return dup }
   386  func (b NullableBytes) AsFromFlexible() Type  { dup := b; dup.FromFlexible = true; return dup }
   387  func (a Array) AsFromFlexible() Type          { dup := a; dup.FromFlexible = true; return dup }
   388  func (s Struct) AsFromFlexible() Type         { dup := s; dup.FromFlexible = true; return dup }
   389  
   390  func (l *LineWriter) Write(line string, args ...any) {
   391  	fmt.Fprintf(l.buf, line, args...)
   392  	l.buf.WriteByte('\n')
   393  	l.line++
   394  }
   395  
   396  //go:generate sh -c "go run . | gofumpt | gofumpt -lang 1.19 -extra > ../pkg/kmsg/generated.go"
   397  func main() {
   398  	const dir = "definitions"
   399  	const enums = "enums"
   400  	dirents, err := ioutil.ReadDir(dir)
   401  	if err != nil {
   402  		die("unable to read definitions dir %s: %v", dir, err)
   403  	}
   404  
   405  	{ // first parse all enums for use in definitions
   406  		f, err := ioutil.ReadFile(filepath.Join(dir, enums))
   407  		if err != nil {
   408  			die("unable to read %s/%s: %v", dir, enums, err)
   409  		}
   410  		ParseEnums(f)
   411  	}
   412  
   413  	for _, ent := range dirents {
   414  		if ent.Name() == enums || strings.HasPrefix(ent.Name(), ".") {
   415  			continue
   416  		}
   417  		f, err := ioutil.ReadFile(filepath.Join(dir, ent.Name()))
   418  		if err != nil {
   419  			die("unable to read %s/%s: %v", dir, ent.Name(), err)
   420  		}
   421  		Parse(f)
   422  	}
   423  
   424  	l := &LineWriter{buf: bytes.NewBuffer(make([]byte, 0, 300<<10))}
   425  	l.Write("package kmsg")
   426  	l.Write("import (")
   427  	l.Write(`"context"`)
   428  	l.Write(`"fmt"`)
   429  	l.Write(`"strings"`)
   430  	l.Write(`"reflect"`)
   431  	l.Write("")
   432  	l.Write(`"github.com/twmb/franz-go/pkg/kmsg/internal/kbin"`)
   433  	l.Write(")")
   434  	l.Write("// Code generated by franz-go/generate. DO NOT EDIT.\n")
   435  
   436  	l.Write("// MaxKey is the maximum key used for any messages in this package.")
   437  	l.Write("// Note that this value will change as Kafka adds more messages.")
   438  	l.Write("const MaxKey = %d\n", maxKey)
   439  
   440  	var name2structs []Struct
   441  
   442  	sort.SliceStable(newStructs, func(i, j int) bool { return newStructs[i].Key < newStructs[j].Key })
   443  	for _, s := range newStructs {
   444  		s.WriteDefn(l)
   445  		if s.TopLevel {
   446  			if s.ResponseKind != "" {
   447  				name2structs = append(name2structs, s)
   448  			}
   449  
   450  			s.WriteKeyFunc(l)
   451  			s.WriteMaxVersionFunc(l)
   452  			s.WriteSetVersionFunc(l)
   453  			s.WriteGetVersionFunc(l)
   454  			s.WriteIsFlexibleFunc(l)
   455  
   456  			for _, f := range s.Fields {
   457  				switch f.Type.(type) {
   458  				case Throttle:
   459  					s.WriteThrottleMillisFunc(f, l)
   460  					s.WriteSetThrottleMillisFunc(l)
   461  				case Timeout:
   462  					s.WriteTimeoutMillisFunc(l)
   463  					s.WriteSetTimeoutMillisFunc(l)
   464  				}
   465  			}
   466  
   467  			if s.ResponseKind != "" {
   468  				switch {
   469  				case s.Admin:
   470  					s.WriteAdminFunc(l)
   471  				case s.GroupCoordinator:
   472  					s.WriteGroupCoordinatorFunc(l)
   473  				case s.TxnCoordinator:
   474  					s.WriteTxnCoordinatorFunc(l)
   475  				}
   476  				s.WriteResponseKindFunc(l)
   477  				s.WriteRequestWithFunc(l)
   478  			}
   479  			if s.RequestKind != "" {
   480  				s.WriteRequestKindFunc(l)
   481  			}
   482  
   483  			l.Write("") // newline before append/decode func
   484  			s.WriteAppendFunc(l)
   485  			s.WriteDecodeFunc(l)
   486  			s.WriteNewPtrFunc(l)
   487  		} else if !s.Anonymous && !s.WithNoEncoding {
   488  			s.WriteAppendFunc(l)
   489  			s.WriteDecodeFunc(l)
   490  			if s.FromFlexible {
   491  				s.WriteIsFlexibleFunc(l)
   492  			}
   493  		}
   494  
   495  		// everything gets a default and new function
   496  		s.WriteDefaultFunc(l)
   497  		s.WriteNewFunc(l)
   498  	}
   499  
   500  	l.Write("// RequestForKey returns the request corresponding to the given request key")
   501  	l.Write("// or nil if the key is unknown.")
   502  	l.Write("func RequestForKey(key int16) Request {")
   503  	l.Write("switch key {")
   504  	l.Write("default: return nil")
   505  	for _, key2struct := range name2structs {
   506  		l.Write("case %d: return NewPtr%s()", key2struct.Key, key2struct.Name)
   507  	}
   508  	l.Write("}")
   509  	l.Write("}")
   510  
   511  	l.Write("// ResponseForKey returns the response corresponding to the given request key")
   512  	l.Write("// or nil if the key is unknown.")
   513  	l.Write("func ResponseForKey(key int16) Response {")
   514  	l.Write("switch key {")
   515  	l.Write("default: return nil")
   516  	for _, key2struct := range name2structs {
   517  		l.Write("case %d: return NewPtr%s()", key2struct.Key, strings.TrimSuffix(key2struct.Name, "Request")+"Response")
   518  	}
   519  	l.Write("}")
   520  	l.Write("}")
   521  
   522  	l.Write("// NameForKey returns the name (e.g., \"Fetch\") corresponding to a given request key")
   523  	l.Write("// or \"\" if the key is unknown.")
   524  	l.Write("func NameForKey(key int16) string {")
   525  	l.Write("switch key {")
   526  	l.Write("default: return \"Unknown\"")
   527  	for _, key2struct := range name2structs {
   528  		l.Write("case %d: return \"%s\"", key2struct.Key, strings.TrimSuffix(key2struct.Name, "Request"))
   529  	}
   530  	l.Write("}")
   531  	l.Write("}")
   532  
   533  	l.Write("// Key is a typed representation of a request key, with helper functions.")
   534  	l.Write("type Key int16")
   535  	l.Write("const (")
   536  	for _, key2struct := range name2structs {
   537  		l.Write("%s Key = %d", strings.TrimSuffix(key2struct.Name, "Request"), key2struct.Key)
   538  	}
   539  	l.Write(")")
   540  	l.Write("// Name returns the name for this key.")
   541  	l.Write("func (k Key) Name() string { return NameForKey(int16(k)) }")
   542  	l.Write("// Request returns a new request for this key if the key is known.")
   543  	l.Write("func (k Key) Request() Request { return RequestForKey(int16(k)) }")
   544  	l.Write("// Response returns a new response for this key if the key is known.")
   545  	l.Write("func (k Key) Response() Response { return ResponseForKey(int16(k)) }")
   546  	l.Write("// Int16 is an alias for int16(k).")
   547  	l.Write("func (k Key) Int16() int16 { return int16(k) }")
   548  
   549  	for _, e := range newEnums {
   550  		e.WriteDefn(l)
   551  		e.WriteStringFunc(l)
   552  		e.WriteStringsFunc(l)
   553  		e.WriteParseFunc(l)
   554  		e.WriteConsts(l)
   555  		e.WriteMarshalTextFunc(l)
   556  		e.WriteUnmarshalTextFunc(l)
   557  	}
   558  
   559  	writeStrnorm(l)
   560  
   561  	fmt.Println(l.buf.String())
   562  }
   563  

View as plain text