Files
qfixpt/quickfix/cmd/generate-fix/internal/templates.go
2026-03-12 12:14:13 -03:00

456 lines
14 KiB
Go

package internal
import (
"strings"
"text/template"
)
var (
HeaderTemplate *template.Template
TrailerTemplate *template.Template
MessageTemplate *template.Template
TagTemplate *template.Template
FieldTemplate *template.Template
EnumTemplate *template.Template
)
func init() {
tmplFuncs := template.FuncMap{
"toLower": strings.ToLower,
"requiredFields": requiredFields,
"beginString": beginString,
"routerBeginString": routerBeginString,
"importRootPath": getImportPathRoot,
"quickfixType": quickfixType,
"quickfixValueType": quickfixValueType,
"getGlobalFieldType": getGlobalFieldType,
"collectStandardImports": collectStandardImports,
"collectExtraImports": collectExtraImports,
"checkIfDecimalImportRequiredForFields": checkIfDecimalImportRequiredForFields,
"decimalImport": func() string {
if *useUDecimal {
return "github.com/quagmt/udecimal"
}
return "github.com/shopspring/decimal"
},
"checkIfTimeImportRequiredForFields": checkIfTimeImportRequiredForFields,
"checkIfEnumImportRequired": checkIfEnumImportRequired,
}
baseTemplate := template.Must(template.New("Base").Funcs(tmplFuncs).Parse(`
{{ define "receiver" }}RECEIVER{{ end }}
{{ define "fieldsetter" -}}
{{- $field_type := getGlobalFieldType . -}}
{{- $qfix_type := quickfixType $field_type -}}
{{- if and ($field_type.Enums) (ne $qfix_type "FIXBoolean") -}}
Set{{ .Name }}(v enum.{{ .Name }}) {
{{ template "receiver" }}.Set(field.New{{ .Name }}(v))
}
{{- else if eq $qfix_type "FIXDecimal" -}}
Set{{ .Name }}(value decimal.Decimal, scale int32) {
{{ template "receiver" }}.Set(field.New{{ .Name }}(value, scale))
}
{{- else if eq $qfix_type "FIXUDecimal" -}}
Set{{ .Name }}(value udecimal.Decimal, scale uint8) {
{{ template "receiver" }}.Set(field.New{{ .Name }}(value, scale))
}
{{- else -}}
Set{{ .Name }}(v {{ quickfixValueType $qfix_type }}) {
{{ template "receiver" }}.Set(field.New{{ .Name }}(v))
}
{{- end }}{{ end }}
{{ define "groupsetter" -}}
Set{{ .Name }}(f {{ .Name }}RepeatingGroup){
{{ template "receiver" }}.SetGroup(f)
}
{{- end }}
{{ define "setters" }}
{{ range .Fields }}
// Set{{ .Name }} sets {{ .Name }}, Tag {{ .Tag }}.
func ({{ template "receiver" }} {{ $.Name }}) {{ if .IsGroup }}{{ template "groupsetter" . }}{{ else }}{{ template "fieldsetter" . }}{{ end }}
{{ end }}{{ end }}
{{ define "fieldgetter" -}}
Get{{ .Name }}() (f field.{{ .Name }}Field, err quickfix.MessageRejectError) {
err = {{ template "receiver" }}.Get(&f)
return
}
{{- end }}
{{ define "fieldvaluegetter" -}}
{{- $ft := getGlobalFieldType . -}}
{{- $bt := quickfixType $ft -}}
{{- if and $ft.Enums (ne $bt "FIXBoolean") -}}
Get{{ .Name }}() (v enum.{{ .Name }}, err quickfix.MessageRejectError) {
{{- else if eq $bt "FIXDecimal" -}}
Get{{ .Name }}() (v decimal.Decimal, err quickfix.MessageRejectError) {
{{- else if eq $bt "FIXUDecimal" -}}
Get{{ .Name }}() (v udecimal.Decimal, err quickfix.MessageRejectError) {
{{- else -}}
Get{{ .Name }}() (v {{ quickfixValueType $bt }}, err quickfix.MessageRejectError) {
{{- end }}
var f field.{{ .Name }}Field
if err = {{ template "receiver" }}.Get(&f); err == nil {
v = f.Value()
}
return
}
{{- end }}
{{ define "groupgetter" -}}
Get{{ .Name }}() ({{ .Name }}RepeatingGroup, quickfix.MessageRejectError) {
f := New{{ .Name }}RepeatingGroup()
err := {{ template "receiver" }}.GetGroup(f)
return f, err
}
{{- end }}
{{ define "getters" }}
{{ range .Fields }}
// Get{{ .Name }} gets {{ .Name }}, Tag {{ .Tag }}.
func ({{ template "receiver" }} {{ $.Name }}) {{if .IsGroup}}{{ template "groupgetter" . }}{{ else }}{{ template "fieldvaluegetter" .}}{{ end }}
{{ end }}{{ end }}
{{ define "hasers" }}
{{range .Fields}}
// Has{{ .Name}} returns true if {{ .Name}} is present, Tag {{ .Tag}}.
func ({{ template "receiver" }} {{ $.Name }}) Has{{ .Name}}() bool {
return {{ template "receiver" }}.Has(tag.{{ .Name}})
}
{{end}}{{ end }}
{{ define "group_template" }}
quickfix.GroupTemplate{
{{- range $index, $field := . }}
{{- if $field.IsGroup }}
New{{ $field.Name }}RepeatingGroup(),
{{- else}}
quickfix.GroupElement(tag.{{$field.Name}}),
{{- end }}
{{- end }}
}
{{- end }}
{{ define "field_args" }}
{{- range $index, $field := . }}{{if $index}},{{end}}{{toLower $field.Name}} field.{{ .Name }}Field{{ end }}
{{- end }}
{{ define "groups" }}
{{ range .Fields }}
{{ if .IsGroup }}
// {{ .Name }} is a repeating group element, Tag {{ .Tag }}.
type {{ .Name }} struct {
*quickfix.Group
}
{{ template "setters" .}}
{{ template "getters" . }}
{{ template "hasers" . }}
{{ template "groups" . }}
// {{ .Name }}RepeatingGroup is a repeating group, Tag {{ .Tag }}.
type {{ .Name }}RepeatingGroup struct {
*quickfix.RepeatingGroup
}
// New{{ .Name }}RepeatingGroup returns an initialized, {{ .Name }}RepeatingGroup.
func New{{ .Name }}RepeatingGroup() {{ .Name }}RepeatingGroup {
return {{ .Name }}RepeatingGroup{
quickfix.NewRepeatingGroup(
tag.{{ .Name }},
{{- template "group_template" .Fields }},
),
}
}
// Add create and append a new {{ .Name }} to this group.
func ({{ template "receiver" }} {{ .Name }}RepeatingGroup) Add() {{ .Name }} {
g := {{ template "receiver" }}.RepeatingGroup.Add()
return {{ .Name }}{g}
}
// Get returns the ith {{ .Name }} in the {{ .Name }}RepeatinGroup.
func ({{ template "receiver" }} {{ .Name}}RepeatingGroup) Get(i int) {{ .Name }} {
return {{ .Name }}{ {{ template "receiver" }}.RepeatingGroup.Get(i) }
}
{{ end }}{{ end }}{{ end }}
`))
HeaderTemplate = template.Must(template.Must(baseTemplate.Clone()).Parse(`
{{ define "receiver" }}h{{ end }}
// Code generated by quickfix. DO NOT EDIT.
package {{ .Package }}
import (
{{- if collectStandardImports .MessageDef }}
{{- range collectStandardImports .MessageDef }}
"{{ . }}"
{{- end }}{{ "\n" }}
{{- end }}
{{- if collectExtraImports .MessageDef }}
{{- range collectExtraImports .MessageDef }}
"{{ . }}"
{{- end }}{{ "\n" }}
{{- end }}
"quantex.com/qfixpt/quickfix"
{{- if checkIfEnumImportRequired .MessageDef}}
"{{ importRootPath }}/enum"
{{- end }}
"{{ importRootPath }}/field"
"{{ importRootPath }}/tag"
)
// Header is the {{ .Package }} Header type.
type Header struct {
*quickfix.Header
}
// NewHeader returns a new, initialized Header instance.
func NewHeader(header *quickfix.Header) (h Header) {
h.Header = header
h.SetBeginString("{{ beginString .FIXSpec }}")
return
}
{{ template "setters" .}}
{{ template "getters" . }}
{{ template "hasers" . }}
{{ template "groups" . }}
`))
TrailerTemplate = template.Must(template.Must(baseTemplate.Clone()).Parse(`
{{ define "receiver" }}t{{ end }}
// Code generated by quickfix. DO NOT EDIT.
package {{ .Package }}
import (
{{- if collectStandardImports .MessageDef }}
{{- range collectStandardImports .MessageDef }}
"{{ . }}"
{{- end }}{{ "\n" }}
{{- end }}
{{- if collectExtraImports .MessageDef }}
{{- range collectExtraImports .MessageDef }}
"{{ . }}"
{{- end }}{{ "\n" }}
{{- end }}
"quantex.com/qfixpt/quickfix"
{{- if checkIfEnumImportRequired .MessageDef}}
"{{ importRootPath }}/enum"
{{- end }}
"{{ importRootPath }}/field"
"{{ importRootPath }}/tag"
)
// Trailer is the {{ .Package }} Trailer type.
type Trailer struct {
*quickfix.Trailer
}
{{ template "setters" .}}
{{ template "getters" . }}
{{ template "hasers" . }}
{{ template "groups" . }}
`))
MessageTemplate = template.Must(baseTemplate.Parse(`
{{ define "receiver" }}m{{ end }}
// Code generated by quickfix. DO NOT EDIT.
package {{ .Package }}
import (
{{- if collectStandardImports .MessageDef }}
{{- range collectStandardImports .MessageDef }}
"{{ . }}"
{{- end }}{{ "\n" }}
{{- end }}
{{- if collectExtraImports .MessageDef }}
{{- range collectExtraImports .MessageDef }}
"{{ . }}"
{{- end }}{{ "\n" }}
{{- end }}
"quantex.com/qfixpt/quickfix"
{{- if checkIfEnumImportRequired .MessageDef}}
"{{ importRootPath }}/enum"
{{- end }}
"{{ importRootPath }}/field"
"{{ importRootPath }}/{{ .TransportPackage }}"
"{{ importRootPath }}/tag"
)
// {{ .Name }} is the {{ .FIXPackage }} {{ .Name }} type, MsgType = {{ .MsgType }}.
type {{ .Name }} struct {
{{ .TransportPackage }}.Header
*quickfix.Body
{{ .TransportPackage }}.Trailer
Message *quickfix.Message
}
// FromMessage creates a {{ .Name }} from a quickfix.Message instance.
func FromMessage(m *quickfix.Message) {{ .Name }} {
return {{ .Name }}{
Header: {{ .TransportPackage}}.Header{Header: &m.Header},
Body: &m.Body,
Trailer: {{ .TransportPackage}}.Trailer{Trailer: &m.Trailer},
Message: m,
}
}
// ToMessage returns a quickfix.Message instance.
func (m {{ .Name }}) ToMessage() *quickfix.Message {
return m.Message
}
{{ $required_fields := requiredFields .MessageDef -}}
// New returns a {{ .Name }} initialized with the required fields for {{ .Name }}.
func New({{template "field_args" $required_fields }}) (m {{ .Name }}) {
m.Message = quickfix.NewMessage()
m.Header = {{ .TransportPackage }}.NewHeader(&m.Message.Header)
m.Body = &m.Message.Body
m.Trailer.Trailer = &m.Message.Trailer
m.Header.Set(field.NewMsgType("{{ .MessageDef.MsgType }}"))
{{- range $required_fields }}
m.Set({{ toLower .Name }})
{{- end }}
return
}
// A RouteOut is the callback type that should be implemented for routing Message.
type RouteOut func(msg {{ .Name }}, sessionID quickfix.SessionID) quickfix.MessageRejectError
// Route returns the beginstring, message type, and MessageRoute for this Message type.
func Route(router RouteOut) (string, string, quickfix.MessageRoute) {
r:=func(msg *quickfix.Message, sessionID quickfix.SessionID) quickfix.MessageRejectError {
return router(FromMessage(msg), sessionID)
}
return "{{ routerBeginString .FIXSpec }}", "{{ .MessageDef.MsgType }}", r
}
{{ template "setters" . }}
{{ template "getters" . }}
{{ template "hasers" . }}
{{ template "groups" . }}
`))
TagTemplate = template.Must(template.New("Tag").Parse(`
// Code generated by quickfix. DO NOT EDIT.
package tag
import "quantex.com/qfixpt/quickfix"
const (
{{- range .}}
{{ .Name }} quickfix.Tag = {{ .Tag }}
{{- end }}
)
`))
FieldTemplate = template.Must(template.New("Field").Funcs(tmplFuncs).Parse(`
// Code generated by quickfix. DO NOT EDIT.
package field
import (
{{ if checkIfTimeImportRequiredForFields . }}"time"{{ end }}
{{ if checkIfDecimalImportRequiredForFields . }}"{{ decimalImport }}"{{ end }}
"quantex.com/qfixpt/quickfix"
"{{ importRootPath }}/enum"
"{{ importRootPath }}/tag"
)
{{ range . }}
{{- $base_type := quickfixType . -}}
{{ if and .Enums (ne $base_type "FIXBoolean") }}
// {{ .Name }}Field is a enum.{{ .Name }} field.
type {{ .Name }}Field struct { quickfix.FIXString }
{{ else }}
// {{ .Name }}Field is a {{ .Type }} field.
type {{ .Name }}Field struct { quickfix.{{ $base_type }} }
{{ end }}
// Tag returns tag.{{ .Name }} ({{ .Tag }}).
func (f {{ .Name }}Field) Tag() quickfix.Tag { return tag.{{ .Name }} }
{{ if eq $base_type "FIXUTCTimestamp" }}
// New{{ .Name }} returns a new {{ .Name }}Field initialized with val.
func New{{ .Name }}(val time.Time) {{ .Name }}Field {
return New{{ .Name }}WithPrecision(val, quickfix.Millis)
}
// New{{ .Name }}NoMillis returns a new {{ .Name }}Field initialized with val without millisecs.
func New{{ .Name }}NoMillis(val time.Time) {{ .Name }}Field {
return New{{ .Name }}WithPrecision(val, quickfix.Seconds)
}
// New{{ .Name }}WithPrecision returns a new {{ .Name }}Field initialized with val of specified precision.
func New{{ .Name }}WithPrecision(val time.Time, precision quickfix.TimestampPrecision) {{ .Name }}Field {
return {{ .Name }}Field{ quickfix.FIXUTCTimestamp{ Time: val, Precision: precision } }
}
{{ else if and .Enums (ne $base_type "FIXBoolean") }}
func New{{ .Name }}(val enum.{{ .Name }}) {{ .Name }}Field {
return {{ .Name }}Field{ quickfix.FIXString(val) }
}
{{ else if eq $base_type "FIXDecimal" }}
// New{{ .Name }} returns a new {{ .Name }}Field initialized with val and scale.
func New{{ .Name }}(val decimal.Decimal, scale int32) {{ .Name }}Field {
return {{ .Name }}Field{ quickfix.FIXDecimal{ Decimal: val, Scale: scale} }
}
{{ else if eq $base_type "FIXUDecimal" }}
// New{{ .Name }} returns a new {{ .Name }}Field initialized with val and scale.
func New{{ .Name }}(val udecimal.Decimal, scale uint8) {{ .Name }}Field {
return {{ .Name }}Field{ quickfix.FIXUDecimal{ Decimal: val, Scale: scale} }
}
{{ else }}
// New{{ .Name }} returns a new {{ .Name }}Field initialized with val.
func New{{ .Name }}(val {{ quickfixValueType $base_type }}) {{ .Name }}Field {
return {{ .Name }}Field{ quickfix.{{ $base_type }}(val) }
}
{{ end }}
{{ if and .Enums (ne $base_type "FIXBoolean") }}
func (f {{ .Name }}Field) Value() enum.{{ .Name }} { return enum.{{ .Name }}(f.String()) }
{{ else if eq $base_type "FIXDecimal" }}
func (f {{ .Name }}Field) Value() (val decimal.Decimal) { return f.Decimal }
{{ else if eq $base_type "FIXUDecimal" }}
func (f {{ .Name }}Field) Value() (val udecimal.Decimal) { return f.Decimal }
{{ else }}
func (f {{ .Name }}Field) Value() ({{ quickfixValueType $base_type }}) {
{{- if eq $base_type "FIXString" -}}
return f.String() }
{{- else if eq $base_type "FIXBoolean" -}}
return f.Bool() }
{{- else if eq $base_type "FIXInt" -}}
return f.Int() }
{{- else if eq $base_type "FIXUTCTimestamp" -}}
return f.Time }
{{- else if eq $base_type "FIXFloat" -}}
return f.Float() }
{{- else -}}
TEMPLATE ERROR: Value() for {{ $base_type }}
{{ end }}{{ end }}{{ end }}
`))
EnumTemplate = template.Must(template.New("Enum").Parse(`
// Code generated by quickfix. DO NOT EDIT.
package enum
{{ range $ft := . }}
{{ if $ft.Enums }}
// {{ $ft.Name }} field enumeration values.
type {{ $ft.Name }} string
const(
{{ range $ft.Enums }}
{{ $ft.Name }}_{{ .Description }} {{ $ft.Name }} = "{{ .Value }}"
{{- end }}
)
{{ end }}{{ end }}
`))
}