adding quickfix library

This commit is contained in:
Ramiro Paz
2026-03-12 12:08:34 -03:00
parent 9e55c5c562
commit c09a1fd21a
1311 changed files with 1887342 additions and 2 deletions

View File

@ -0,0 +1,194 @@
package main
import (
"bytes"
"flag"
"fmt"
"log"
"os"
"path"
"strconv"
"strings"
"sync"
"text/template"
"github.com/quickfixgo/quickfix/cmd/generate-fix/internal"
"github.com/quickfixgo/quickfix/datadictionary"
)
var (
waitGroup sync.WaitGroup
errors = make(chan error)
)
func usage() {
fmt.Fprintf(os.Stderr, "usage: %v [flags] <path to data dictionary> ... \n", os.Args[0])
flag.PrintDefaults()
os.Exit(2)
}
func getPackageName(fixSpec *datadictionary.DataDictionary) string {
pkg := strings.ToLower(fixSpec.FIXType) + strconv.Itoa(fixSpec.Major) + strconv.Itoa(fixSpec.Minor)
if fixSpec.ServicePack != 0 {
pkg += "sp" + strconv.Itoa(fixSpec.ServicePack)
}
return pkg
}
func getTransportPackageName(fixSpec *datadictionary.DataDictionary) string {
if fixSpec.Major >= 5 {
return "fixt11"
}
return getPackageName(fixSpec)
}
type component struct {
Package string
FIXPackage string
TransportPackage string
FIXSpec *datadictionary.DataDictionary
Name string
*datadictionary.MessageDef
}
func genHeader(pkg string, spec *datadictionary.DataDictionary) {
c := component{
Package: pkg,
Name: "Header",
MessageDef: spec.Header,
FIXSpec: spec,
}
gen(internal.HeaderTemplate, path.Join(pkg, "header.generated.go"), c)
}
func genTrailer(pkg string, spec *datadictionary.DataDictionary) {
c := component{
Package: pkg,
Name: "Trailer",
MessageDef: spec.Trailer,
}
gen(internal.TrailerTemplate, path.Join(pkg, "trailer.generated.go"), c)
}
func genMessage(fixPkg string, spec *datadictionary.DataDictionary, msg *datadictionary.MessageDef) {
pkgName := strings.ToLower(msg.Name)
transportPkg := getTransportPackageName(spec)
c := component{
Package: pkgName,
FIXPackage: fixPkg,
TransportPackage: transportPkg,
FIXSpec: spec,
Name: msg.Name,
MessageDef: msg,
}
gen(internal.MessageTemplate, path.Join(fixPkg, pkgName, msg.Name+".generated.go"), c)
}
func genTags() {
gen(internal.TagTemplate, "tag/tag_numbers.generated.go", internal.GlobalFieldTypes)
}
func genFields() {
gen(internal.FieldTemplate, "field/fields.generated.go", internal.GlobalFieldTypes)
}
func genEnums() {
gen(internal.EnumTemplate, "enum/enums.generated.go", internal.GlobalFieldTypes)
}
func gen(t *template.Template, fileOut string, data interface{}) {
defer waitGroup.Done()
writer := new(bytes.Buffer)
if err := t.Execute(writer, data); err != nil {
errors <- err
return
}
if err := internal.WriteFile(fileOut, writer.String()); err != nil {
errors <- err
}
}
func main() {
flag.Usage = usage
flag.Parse()
if flag.NArg() < 1 {
usage()
}
args := flag.Args()
if len(args) == 1 {
dictpath := args[0]
if strings.Contains(dictpath, "FIX50SP1") {
args = append(args, strings.Replace(dictpath, "FIX50SP1", "FIXT11", -1))
} else if strings.Contains(dictpath, "FIX50SP2") {
args = append(args, strings.Replace(dictpath, "FIX50SP2", "FIXT11", -1))
} else if strings.Contains(dictpath, "FIX50") {
args = append(args, strings.Replace(dictpath, "FIX50", "FIXT11", -1))
}
}
specs := []*datadictionary.DataDictionary{}
for _, dataDictPath := range args {
spec, err := datadictionary.Parse(dataDictPath)
if err != nil {
log.Fatalf("Error Parsing %v: %v", dataDictPath, err)
}
specs = append(specs, spec)
}
internal.BuildGlobalFieldTypes(specs)
waitGroup.Add(1)
go genTags()
waitGroup.Add(1)
go genFields()
waitGroup.Add(1)
go genEnums()
for _, spec := range specs {
pkg := getPackageName(spec)
if fi, err := os.Stat(pkg); os.IsNotExist(err) {
if err := os.Mkdir(pkg, os.ModePerm); err != nil {
log.Fatal(err)
}
} else if !fi.IsDir() {
log.Fatalf("%v/ is not a directory", pkg)
}
switch pkg {
// Uses fixt11 header/trailer.
case "fix50", "fix50sp1", "fix50sp2":
default:
waitGroup.Add(1)
go genHeader(pkg, spec)
waitGroup.Add(1)
go genTrailer(pkg, spec)
}
for _, m := range spec.Messages {
waitGroup.Add(1)
go genMessage(pkg, spec, m)
}
}
go func() {
waitGroup.Wait()
close(errors)
}()
var h internal.ErrorHandler
for err := range errors {
h.Handle(err)
}
os.Exit(h.ReturnCode)
}

View File

@ -0,0 +1,88 @@
package internal
import (
"flag"
"fmt"
"go/ast"
"go/parser"
"go/printer"
"go/token"
"os"
"path"
)
var (
useFloat = flag.Bool("use-float", false, "By default, FIX float fields are represented as arbitrary-precision fixed-point decimal numbers. Set to 'true' to instead generate FIX float fields as float64 values.")
useUDecimal = flag.Bool("use-udecimal", false, "By default, FIX uses the shopspring/decimal library for fixed-point decimal numbers. Set to 'true' to instead use the quagmt/udecimal library.")
pkgRoot = flag.String("pkg-root", "github.com/quickfixgo", "Set a string here to provide a custom import path for generated packages.")
tabWidth = 8
printerMode = printer.UseSpaces | printer.TabIndent
)
// ParseError indicates generated go source is invalid
type ParseError struct {
path string
err error
}
func (e ParseError) Error() string {
return fmt.Sprintf("Error parsing %v: %v", e.path, e.err)
}
// ErrorHandler is a convenience struct for interpretting generation Errors
type ErrorHandler struct {
ReturnCode int
}
// Handle interprets the generation error. Proceeds with setting returnCode, or panics depending on error type
func (h *ErrorHandler) Handle(err error) {
switch err := err.(type) {
case nil:
//do nothing
case ParseError:
fmt.Println(err)
h.ReturnCode = 1
default:
panic(err)
}
}
func write(filePath string, fset *token.FileSet, f *ast.File) error {
if parentdir := path.Dir(filePath); parentdir != "." {
if err := os.MkdirAll(parentdir, os.ModePerm); err != nil {
return err
}
}
file, err := os.Create(filePath)
if err != nil {
return err
}
ast.SortImports(fset, f)
err = (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(file, fset, f)
_ = file.Close()
return err
}
// WriteFile parses the generated code in fileOut and writes the code out to filePath.
// Function performs some import clean up and gofmts the code before writing
// Returns ParseError if the generated source is invalid but is written to filePath
func WriteFile(filePath, fileOut string) error {
fset := token.NewFileSet()
f, pErr := parser.ParseFile(fset, "", fileOut, parser.ParseComments)
if f == nil {
return pErr
}
//write out the file regardless of parseFile errors
if err := write(filePath, fset, f); err != nil {
return err
}
if pErr != nil {
return ParseError{path: filePath, err: pErr}
}
return nil
}

View File

@ -0,0 +1,74 @@
package internal
import (
"fmt"
"sort"
"github.com/quickfixgo/quickfix/datadictionary"
)
type fieldTypeMap map[string]*datadictionary.FieldType
var (
globalFieldTypesLookup fieldTypeMap
GlobalFieldTypes []*datadictionary.FieldType
)
// Sort fieldtypes by name.
type byFieldName []*datadictionary.FieldType
func (n byFieldName) Len() int { return len(n) }
func (n byFieldName) Swap(i, j int) { n[i], n[j] = n[j], n[i] }
func (n byFieldName) Less(i, j int) bool { return n[i].Name() < n[j].Name() }
func getGlobalFieldType(f *datadictionary.FieldDef) (t *datadictionary.FieldType, err error) {
var ok bool
t, ok = globalFieldTypesLookup[f.Name()]
if !ok {
err = fmt.Errorf("Unknown global type for %v", f.Name())
}
return
}
func BuildGlobalFieldTypes(specs []*datadictionary.DataDictionary) {
globalFieldTypesLookup = make(fieldTypeMap)
for _, spec := range specs {
for _, field := range spec.FieldTypeByTag {
if oldField, ok := globalFieldTypesLookup[field.Name()]; ok {
// Merge old enums with new.
if len(oldField.Enums) > 0 && field.Enums == nil {
field.Enums = make(map[string]datadictionary.Enum)
}
for enumVal, enum := range oldField.Enums {
if _, ok := field.Enums[enumVal]; !ok {
// Verify an existing enum doesn't have the same description. Keep newer enum.
okToKeepEnum := true
for _, newEnum := range field.Enums {
if newEnum.Description == enum.Description {
okToKeepEnum = false
break
}
}
if okToKeepEnum {
field.Enums[enumVal] = enum
}
}
}
}
globalFieldTypesLookup[field.Name()] = field
}
}
GlobalFieldTypes = make([]*datadictionary.FieldType, len(globalFieldTypesLookup))
i := 0
for _, fieldType := range globalFieldTypesLookup {
GlobalFieldTypes[i] = fieldType
i++
}
sort.Sort(byFieldName(GlobalFieldTypes))
}

View File

@ -0,0 +1,6 @@
package internal
// getImportPathRoot returns the root path to use in import statements.
func getImportPathRoot() string {
return *pkgRoot
}

View File

@ -0,0 +1,365 @@
package internal
import (
"fmt"
"github.com/quickfixgo/quickfix/datadictionary"
)
func isDecimalType(quickfixType string) bool {
switch quickfixType {
case "FIXDecimal", "FIXUDecimal":
return true
default:
return false
}
}
func checkIfDecimalImportRequiredForFields(fTypes []*datadictionary.FieldType) (ok bool, err error) {
var t string
for _, fType := range fTypes {
t, err = quickfixType(fType)
if err != nil {
return
}
if isDecimalType(t) {
return true, nil
}
}
return
}
func checkIfTimeImportRequiredForFields(fTypes []*datadictionary.FieldType) (ok bool, err error) {
var t string
for _, fType := range fTypes {
t, err = quickfixType(fType)
if err != nil {
return
}
var vt string
if vt, err = quickfixValueType(t); err != nil {
return
}
if vt == "time.Time" {
return true, nil
}
}
return
}
func checkFieldDecimalRequired(f *datadictionary.FieldDef) (required bool, err error) {
var globalType *datadictionary.FieldType
if globalType, err = getGlobalFieldType(f); err != nil {
return
}
var t string
if t, err = quickfixType(globalType); err != nil {
return
}
if isDecimalType(t) {
required = true
return
}
for _, groupField := range f.Fields {
if required, err = checkFieldDecimalRequired(groupField); required || err != nil {
return
}
}
return
}
func checkFieldTimeRequired(f *datadictionary.FieldDef) (required bool, err error) {
var globalType *datadictionary.FieldType
if globalType, err = getGlobalFieldType(f); err != nil {
return
}
var t string
if t, err = quickfixType(globalType); err != nil {
return
}
var vt string
if vt, err = quickfixValueType(t); err != nil {
return
}
if vt == "time.Time" {
required = true
return
}
for _, groupField := range f.Fields {
if required, err = checkFieldTimeRequired(groupField); required || err != nil {
return
}
}
return
}
func collectStandardImports(m *datadictionary.MessageDef) (imports []string, err error) {
var timeRequired bool
for _, f := range m.Fields {
if !timeRequired {
if timeRequired, err = checkFieldTimeRequired(f); err != nil {
return
}
}
if timeRequired {
break
}
}
if timeRequired {
imports = append(imports, "time")
}
return
}
func collectExtraImports(m *datadictionary.MessageDef) (imports []string, err error) {
var decimalRequired bool
importPath := "github.com/shopspring/decimal"
if *useUDecimal {
importPath = "github.com/quagmt/udecimal"
}
for _, f := range m.Fields {
if !decimalRequired {
if decimalRequired, err = checkFieldDecimalRequired(f); err != nil {
return
}
}
if decimalRequired {
break
}
}
if decimalRequired {
imports = append(imports, importPath)
}
return
}
func checkIfEnumImportRequired(m *datadictionary.MessageDef) (required bool, err error) {
for _, f := range m.Fields {
required, err = checkFieldEnumRequired(f)
if err != nil || required {
return
}
}
return
}
func checkFieldEnumRequired(f *datadictionary.FieldDef) (required bool, err error) {
var globalType *datadictionary.FieldType
if globalType, err = getGlobalFieldType(f); err != nil {
return
}
if globalType.Enums != nil && 0 < len(globalType.Enums) {
var t string
if t, err = quickfixType(globalType); err != nil {
return
}
if t != "FIXBoolean" {
required = true
return
}
}
for _, groupField := range f.Fields {
if required, err = checkFieldEnumRequired(groupField); required || err != nil {
return
}
}
return
}
func quickfixValueType(quickfixType string) (goType string, err error) {
switch quickfixType {
case "FIXString":
goType = "string"
case "FIXBoolean":
goType = "bool"
case "FIXInt":
goType = "int"
case "FIXUTCTimestamp":
goType = "time.Time"
case "FIXFloat":
goType = "float64"
case "FIXDecimal":
goType = "decimal.Decimal"
case "FIXUDecimal":
goType = "udecimal.Decimal"
default:
err = fmt.Errorf("Unknown QuickFIX Type: %v", quickfixType)
}
return
}
func quickfixType(field *datadictionary.FieldType) (quickfixType string, err error) {
switch field.Type {
case "MULTIPLESTRINGVALUE", "MULTIPLEVALUESTRING":
fallthrough
case "MULTIPLECHARVALUE":
fallthrough
case "CHAR":
fallthrough
case "CURRENCY":
fallthrough
case "DATA":
fallthrough
case "MONTHYEAR":
fallthrough
case "LOCALMKTTIME", "LOCALMKTDATE":
fallthrough
case "TIME":
fallthrough
case "DATE":
fallthrough
case "EXCHANGE":
fallthrough
case "LANGUAGE":
fallthrough
case "XMLDATA":
fallthrough
case "COUNTRY":
fallthrough
case "UTCTIMEONLY":
fallthrough
case "UTCDATE":
fallthrough
case "UTCDATEONLY":
fallthrough
case "TZTIMEONLY":
fallthrough
case "TZTIMESTAMP":
fallthrough
case "XID", "XIDREF":
fallthrough
case "STRING":
quickfixType = "FIXString"
case "BOOLEAN":
quickfixType = "FIXBoolean"
case "LENGTH":
fallthrough
case "DAYOFMONTH":
fallthrough
case "NUMINGROUP":
fallthrough
case "SEQNUM":
fallthrough
case "TAGNUM":
fallthrough
case "INT":
quickfixType = "FIXInt"
case "UTCTIMESTAMP":
quickfixType = "FIXUTCTimestamp"
case "QTY":
fallthrough
case "QUANTITY":
fallthrough
case "AMT":
fallthrough
case "PRICE":
fallthrough
case "PRICEOFFSET":
fallthrough
case "PERCENTAGE":
fallthrough
case "FLOAT":
if *useFloat {
quickfixType = "FIXFloat"
} else if *useUDecimal {
quickfixType = "FIXUDecimal"
} else {
quickfixType = "FIXDecimal"
}
default:
err = fmt.Errorf("Unknown type '%v' for tag '%v'\n", field.Type, field.Tag())
}
return
}
func requiredFields(m *datadictionary.MessageDef) (required []*datadictionary.FieldDef) {
for _, part := range m.RequiredParts() {
if part.Required() {
switch pType := part.(type) {
case *datadictionary.FieldDef:
if !pType.IsGroup() {
required = append(required, pType)
}
case *datadictionary.Component:
for _, f := range pType.RequiredFields() {
if !f.IsGroup() {
required = append(required, f)
}
}
}
}
}
return
}
func beginString(spec *datadictionary.DataDictionary) string {
if spec.FIXType == "FIXT" || spec.Major == 5 {
return "FIXT.1.1"
}
return fmt.Sprintf("FIX.%v.%v", spec.Major, spec.Minor)
}
func routerBeginString(spec *datadictionary.DataDictionary) (routerBeginString string) {
switch {
case spec.FIXType == "FIXT":
routerBeginString = "FIXT.1.1"
case spec.Major != 5 && spec.ServicePack == 0:
routerBeginString = fmt.Sprintf("FIX.%v.%v", spec.Major, spec.Minor)
// ApplVerID enums.
case spec.Major == 2:
routerBeginString = "0"
case spec.Major == 3:
routerBeginString = "1"
case spec.Major == 4 && spec.Minor == 0:
routerBeginString = "2"
case spec.Major == 4 && spec.Minor == 1:
routerBeginString = "3"
case spec.Major == 4 && spec.Minor == 2:
routerBeginString = "4"
case spec.Major == 4 && spec.Minor == 3:
routerBeginString = "5"
case spec.Major == 4 && spec.Minor == 4:
routerBeginString = "6"
case spec.Major == 5 && spec.Minor == 0 && spec.ServicePack == 0:
routerBeginString = "7"
case spec.Major == 5 && spec.Minor == 0 && spec.ServicePack == 1:
routerBeginString = "8"
case spec.Major == 5 && spec.Minor == 0 && spec.ServicePack == 2:
routerBeginString = "9"
}
return
}

View File

@ -0,0 +1,455 @@
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 }}
"github.com/quickfixgo/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 }}
"github.com/quickfixgo/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 }}
"github.com/quickfixgo/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 "github.com/quickfixgo/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 }}
"github.com/quickfixgo/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 }}
`))
}