diff --git a/field_map.go b/field_map.go index 2b2f285e8f9d502e6cfb0c7da8e8537c080ef5c4..0a95f2b0103440842cebac63bbf0ac24fabac3a2 100644 --- a/field_map.go +++ b/field_map.go @@ -2,7 +2,6 @@ package quickfix import ( "bytes" - "math" "sort" ) @@ -24,50 +23,14 @@ func (t tagSort) Len() int { return len(t.tags) } func (t tagSort) Swap(i, j int) { t.tags[i], t.tags[j] = t.tags[j], t.tags[i] } func (t tagSort) Less(i, j int) bool { return t.compare(t.tags[i], t.tags[j]) } -//in the message header, the first 3 tags in the message header must be 8,9,35 -func headerFieldOrder(i, j Tag) bool { - var ordering = func(t Tag) uint32 { - switch t { - case tagBeginString: - return 1 - case tagBodyLength: - return 2 - case tagMsgType: - return 3 - } - - return math.MaxUint32 - } - - orderi := ordering(i) - orderj := ordering(j) - - switch { - case orderi < orderj: - return true - case orderi > orderj: - return false - } - - return i < j -} - -// In the body, ascending tags +// ascending tags func normalFieldOrder(i, j Tag) bool { return i < j } -// In the trailer, CheckSum (tag 10) must be last -func trailerFieldOrder(i, j Tag) bool { - switch { - case i == tagCheckSum: - return false - case j == tagCheckSum: - return true - } - - return i < j +func (m *FieldMap) init() { + m.initWithOrdering(normalFieldOrder) } -func (m *FieldMap) init(ordering tagOrder) { +func (m *FieldMap) initWithOrdering(ordering tagOrder) { m.tagLookup = make(map[Tag]TagValues) m.tagOrder = ordering } diff --git a/field_map_test.go b/field_map_test.go index 822a64412039cefd9c7de56046e3d433307a58ba..2f73e3b58d98c2e6c8b811d0b93be4bab9e30973 100644 --- a/field_map_test.go +++ b/field_map_test.go @@ -5,8 +5,8 @@ import ( ) func TestFieldMap_Clear(t *testing.T) { - fMap := FieldMap{} - fMap.init(normalFieldOrder) + var fMap FieldMap + fMap.init() fMap.SetField(1, FIXString("hello")) fMap.SetField(2, FIXString("world")) @@ -19,8 +19,8 @@ func TestFieldMap_Clear(t *testing.T) { } func TestFieldMap_SetAndGet(t *testing.T) { - fMap := FieldMap{} - fMap.init(normalFieldOrder) + var fMap FieldMap + fMap.init() fMap.SetField(1, FIXString("hello")) fMap.SetField(2, FIXString("world")) @@ -57,8 +57,8 @@ func TestFieldMap_SetAndGet(t *testing.T) { } func TestFieldMap_Length(t *testing.T) { - fMap := FieldMap{} - fMap.init(normalFieldOrder) + var fMap FieldMap + fMap.init() fMap.SetField(1, FIXString("hello")) fMap.SetField(2, FIXString("world")) fMap.SetField(8, FIXString("FIX.4.4")) @@ -72,8 +72,8 @@ func TestFieldMap_Length(t *testing.T) { func TestFieldMap_Total(t *testing.T) { - fMap := FieldMap{} - fMap.init(normalFieldOrder) + var fMap FieldMap + fMap.init() fMap.SetField(1, FIXString("hello")) fMap.SetField(2, FIXString("world")) fMap.SetField(8, FIXString("FIX.4.4")) diff --git a/marshal.go b/marshal.go index 58289693985f82b4b3c6176b2aec5d561dae7855..e4b6351b822ef5065709b1e775fcf410ef242257 100644 --- a/marshal.go +++ b/marshal.go @@ -105,11 +105,11 @@ func Marshal(v interface{}) Message { } continue case "Header": - e.FieldMap = m.Header + e.FieldMap = m.Header.FieldMap case "Trailer": - e.FieldMap = m.Trailer + e.FieldMap = m.Trailer.FieldMap default: - e.FieldMap = m.Body + e.FieldMap = m.Body.FieldMap } e.encodeField(sf, sf.Type, reflectValue.Field(i)) diff --git a/marshal_test.go b/marshal_test.go index 38384b6b65c1583e439108238498b3e299552bd0..4935026b8400d6647525dc8d0e57ddebd426d393 100644 --- a/marshal_test.go +++ b/marshal_test.go @@ -351,10 +351,10 @@ func TestMarshal_HeaderTrailer(t *testing.T) { fixMsgPart quickfix.FieldMap expected []byte }{ - {quickfix.Tag(35), new(quickfix.FIXString), fixMsg.Header, []byte("0")}, - {quickfix.Tag(49), new(quickfix.FIXString), fixMsg.Header, []byte("hello")}, - {quickfix.Tag(112), new(quickfix.FIXString), fixMsg.Body, []byte("world")}, - {quickfix.Tag(89), new(quickfix.FIXInt), fixMsg.Trailer, []byte("3")}, + {quickfix.Tag(35), new(quickfix.FIXString), fixMsg.Header.FieldMap, []byte("0")}, + {quickfix.Tag(49), new(quickfix.FIXString), fixMsg.Header.FieldMap, []byte("hello")}, + {quickfix.Tag(112), new(quickfix.FIXString), fixMsg.Body.FieldMap, []byte("world")}, + {quickfix.Tag(89), new(quickfix.FIXInt), fixMsg.Trailer.FieldMap, []byte("3")}, } for _, test := range tests { diff --git a/message.go b/message.go index 40a37cdf3adee012b814c197d28013f728f7e839..b898d7ad53aa43eb499544eb5197f254dbeef21b 100644 --- a/message.go +++ b/message.go @@ -3,16 +3,77 @@ package quickfix import ( "bytes" "fmt" + "math" "time" "github.com/quickfixgo/quickfix/enum" ) +//Header is first section of a FIX Message +type Header struct{ FieldMap } + +//Init initializes the Header instance +func (h *Header) Init() { + //in the message header, the first 3 tags in the message header must be 8,9,35 + h.initWithOrdering(func(i, j Tag) bool { + var ordering = func(t Tag) uint32 { + switch t { + case tagBeginString: + return 1 + case tagBodyLength: + return 2 + case tagMsgType: + return 3 + } + + return math.MaxUint32 + } + + orderi := ordering(i) + orderj := ordering(j) + + switch { + case orderi < orderj: + return true + case orderi > orderj: + return false + } + + return i < j + }) +} + +//Body is the primary application section of a FIX message +type Body struct{ FieldMap } + +//Init initializes the FIX message +func (b *Body) Init() { + b.init() +} + +//Trailer is the last section of a FIX message +type Trailer struct{ FieldMap } + +//Init initializes the FIX message +func (t *Trailer) Init() { + // In the trailer, CheckSum (tag 10) must be last + t.initWithOrdering(func(i, j Tag) bool { + switch { + case i == tagCheckSum: + return false + case j == tagCheckSum: + return true + } + + return i < j + }) +} + //Message is a FIX Message abstraction. type Message struct { - Header FieldMap - Trailer FieldMap - Body FieldMap + Header Header + Trailer Trailer + Body Body //ReceiveTime is the time that this message was read from the socket connection ReceiveTime time.Time @@ -38,15 +99,11 @@ func (e parseError) Error() string { return fmt.Sprintf("error parsing message: //NewMessage returns a newly initialized Message instance func NewMessage() (m Message) { - m.Init() - return -} + m.Header.Init() + m.Body.Init() + m.Trailer.Init() -//Init initializes the Message instance -func (m *Message) Init() { - m.Header.init(headerFieldOrder) - m.Body.init(normalFieldOrder) - m.Trailer.init(trailerFieldOrder) + return } //ParseMessage constructs a Message from a byte slice wrapping a FIX message. diff --git a/repeating_group.go b/repeating_group.go index 79fc9402d65f1a5d08c98edf14efdb3bc4914f53..f494ffce7b6931bcc108b795d852259d1bb100dc 100644 --- a/repeating_group.go +++ b/repeating_group.go @@ -77,7 +77,7 @@ func (f RepeatingGroup) Get(i int) Group { //Add appends a new group to the RepeatingGroup and returns the new Group func (f *RepeatingGroup) Add() Group { var g Group - g.init(f.groupTagOrder()) + g.initWithOrdering(f.groupTagOrder()) f.groups = append(f.groups, g) return g @@ -157,7 +157,7 @@ func (f *RepeatingGroup) Read(tv TagValues) (TagValues, error) { tv = tv[1:cap(tv)] tagOrdering := f.groupTagOrder() var group Group - group.init(tagOrdering) + group.initWithOrdering(tagOrdering) for len(tv) > 0 { field, ok := f.findItemInGroupTemplate(tv[0].tag) if !ok { @@ -171,7 +171,7 @@ func (f *RepeatingGroup) Read(tv TagValues) (TagValues, error) { if f.isDelimiter(field.Tag()) { group = Group{} - group.init(tagOrdering) + group.initWithOrdering(tagOrdering) f.groups = append(f.groups, group) } diff --git a/session.go b/session.go index e64238d793ed294dcfa36c25d01fd9bc12ce27f4..dbaf6d8f3fb4413b01f6a35cfcf1321aaa8a5dcf 100644 --- a/session.go +++ b/session.go @@ -2,11 +2,12 @@ package quickfix import ( "fmt" + "sync" + "time" + "github.com/quickfixgo/quickfix/config" "github.com/quickfixgo/quickfix/datadictionary" "github.com/quickfixgo/quickfix/enum" - "sync" - "time" ) //The Session is the primary FIX abstraction for message communication @@ -152,7 +153,7 @@ func (s *session) onDisconnect() { s.log.OnEvent("Disconnected") } -func (s *session) insertSendingTime(header FieldMap) { +func (s *session) insertSendingTime(header Header) { sendingTime := time.Now().UTC() if s.sessionID.BeginString >= enum.BeginStringFIX42 { diff --git a/session_test.go b/session_test.go index 3989fc3703274cea77f4706bb9774415644be8e6..15d4db287b77409aaabb6296d8a94c855b66ae24 100644 --- a/session_test.go +++ b/session_test.go @@ -1,14 +1,14 @@ package quickfix import ( - "github.com/quickfixgo/quickfix/enum" "testing" "time" + + "github.com/quickfixgo/quickfix/enum" ) func buildMessage() Message { - builder := Message{} - builder.Init() + builder := NewMessage() builder.Header.SetField(tagBeginString, FIXString(enum.BeginStringFIX40)) builder.Header.SetField(tagMsgType, FIXString("D")) return builder diff --git a/unmarshal.go b/unmarshal.go index 92093f82013431fb9696db1cd63fdce63b75d4c0..6b705a78b6b2cb47838225f2ed079d23ba8f1eb6 100644 --- a/unmarshal.go +++ b/unmarshal.go @@ -124,11 +124,11 @@ func Unmarshal(m Message, v interface{}) MessageRejectError { case "FIXMsgType": continue case "Header": - d.FieldMap = m.Header + d.FieldMap = m.Header.FieldMap case "Trailer": - d.FieldMap = m.Trailer + d.FieldMap = m.Trailer.FieldMap default: - d.FieldMap = m.Body + d.FieldMap = m.Body.FieldMap } if err := d.decodeField(sf, sf.Type, sv); err != nil { diff --git a/validation.go b/validation.go index 6a9029021f0c97b102d8118b0d50c549e305051d..b71a9b54113b5a63a1c3c2ebe17c2015ea6cffb3 100644 --- a/validation.go +++ b/validation.go @@ -242,15 +242,15 @@ func validateOrder(msg Message) MessageRejectError { } func validateRequired(transportDD *datadictionary.DataDictionary, appDD *datadictionary.DataDictionary, msgType string, message Message) MessageRejectError { - if err := validateRequiredFieldMap(message, transportDD.Header.RequiredTags, message.Header); err != nil { + if err := validateRequiredFieldMap(message, transportDD.Header.RequiredTags, message.Header.FieldMap); err != nil { return err } - if err := validateRequiredFieldMap(message, appDD.Messages[msgType].RequiredTags, message.Body); err != nil { + if err := validateRequiredFieldMap(message, appDD.Messages[msgType].RequiredTags, message.Body.FieldMap); err != nil { return err } - if err := validateRequiredFieldMap(message, transportDD.Trailer.RequiredTags, message.Trailer); err != nil { + if err := validateRequiredFieldMap(message, transportDD.Trailer.RequiredTags, message.Trailer.FieldMap); err != nil { return err }