Documentation ¶
Overview ¶
Package fast implements FAST (FIX Adapted for STreaming) encoder/decoder.
Example (ReceiverDecode) ¶
package main import ( "bytes" "fmt" "strings" "github.com/co11ter/goFAST" ) var xmlDecodeTemplate = ` <?xml version="1.0" encoding="UTF-8"?> <templates xmlns="http://www.fixprotocol.org/ns/fast/td/1.1"> <template name="Done" id="1" xmlns="http://www.fixprotocol.org/ns/fast/td/1.1"> <string name="Type" id="15"> <constant value="99"/> </string> <string name="Test" id="131" presence="optional"/> <uInt64 name="Time" id="20" presence="optional"/> <int32 name="Equal" id="271"/> <sequence name="Sequence"> <length name="SeqLength" id="146"/> <uInt64 name="SomeField" id="38"/> </sequence> </template> </templates>` type ReceiverSeq struct { SomeField uint64 } type ReceiverMsg struct { TemplateID uint Type string Test string Time uint64 Equal int32 Sequence []ReceiverSeq seqLocked bool seqIndex int } func (br *ReceiverMsg) SetTemplateID(tid uint) { br.TemplateID = tid } func (br *ReceiverMsg) SetLength(field *fast.Field) { if field.Name == "Sequence" && len(br.Sequence) < field.Value.(int) { br.Sequence = make([]ReceiverSeq, field.Value.(int)) } } func (br *ReceiverMsg) Lock(field *fast.Field) bool { br.seqLocked = field.Name == "Sequence" if br.seqLocked { br.seqIndex = field.Value.(int) } return br.seqLocked } func (br *ReceiverMsg) Unlock() { br.seqLocked = false br.seqIndex = 0 } func (br *ReceiverMsg) SetValue(field *fast.Field) { switch field.ID { case 15: br.Type = field.Value.(string) case 131: br.Test = field.Value.(string) case 20: br.Time = field.Value.(uint64) case 271: br.Equal = field.Value.(int32) case 38: br.Sequence[br.seqIndex].SomeField = field.Value.(uint64) } } func main() { var msg ReceiverMsg reader := bytes.NewReader( []byte{0xc0, 0x81, 0x74, 0x65, 0x73, 0xf4, 0x80, 0x80, 0x81, 0x80, 0x82}, ) tpls, err := fast.ParseXMLTemplate(strings.NewReader(xmlDecodeTemplate)) if err != nil { panic(err) } decoder := fast.NewDecoder( reader, tpls..., ) if err := decoder.Decode(&msg); err != nil { panic(err) } fmt.Print(msg) }
Output: {1 99 test 0 0 [{0}] false 0}
Example (SenderEncode) ¶
package main import ( "bytes" "fmt" "strings" "github.com/co11ter/goFAST" ) var xmlEncodeTemplate = ` <?xml version="1.0" encoding="UTF-8"?> <templates xmlns="http://www.fixprotocol.org/ns/fast/td/1.1"> <template name="Done" id="1" xmlns="http://www.fixprotocol.org/ns/fast/td/1.1"> <string name="Type" id="15"> <constant value="99"/> </string> <string name="Test" id="131" presence="optional"/> <uInt64 name="Time" id="20" presence="optional"/> <int32 name="Equal" id="271"/> <sequence name="Sequence"> <length name="SeqLength" id="146"/> <uInt64 name="SomeField" id="38"/> </sequence> </template> <template name="Skip" id="999" xmlns="http://www.fixprotocol.org/ns/fast/td/1.1"> <string name="Str" id="15"> <constant value="99"/> </string> </template> </templates>` type SenderSeq struct { SomeField uint64 } type SenderMsg struct { TemplateID uint Type string Test string Time uint64 Equal int32 Sequence []SenderSeq seqLocked bool seqIndex int } func (br *SenderMsg) GetTemplateID() uint { return br.TemplateID } func (br *SenderMsg) GetLength(field *fast.Field) { if field.Name == "Sequence" { field.Value = len(br.Sequence) } } func (br *SenderMsg) Lock(field *fast.Field) bool { br.seqLocked = field.Name == "Sequence" if br.seqLocked { br.seqIndex = field.Value.(int) } return br.seqLocked } func (br *SenderMsg) Unlock() { br.seqLocked = false br.seqIndex = 0 } func (br *SenderMsg) GetValue(field *fast.Field) { switch field.ID { case 131: field.Value = br.Test case 38: field.Value = br.Sequence[br.seqIndex].SomeField } } func main() { var buf bytes.Buffer var msg = SenderMsg{ TemplateID: 1, Test: "test", Sequence: []SenderSeq{ {SomeField: 2}, }, } tpls, err := fast.ParseXMLTemplate(strings.NewReader(xmlEncodeTemplate)) if err != nil { panic(err) } encoder := fast.NewEncoder(&buf, tpls...) if err := encoder.Encode(&msg); err != nil { panic(err) } fmt.Printf("%x", buf.Bytes()) }
Output: c081746573f480808182
Index ¶
Examples ¶
Constants ¶
const ( // TypeNull mark type of instruction null. TypeNull InstructionType = iota TypeUint32 TypeInt32 TypeUint64 TypeInt64 TypeLength TypeExponent TypeMantissa TypeDecimal TypeASCIIString TypeUnicodeString TypeByteVector TypeSequence TypeGroup OperatorNone InstructionOperator = iota OperatorConstant OperatorDelta OperatorDefault OperatorCopy OperatorIncrement // It's applicable to integer field types OperatorTail // It's applicable to string and byte vector field types PresenceMandatory InstructionPresence = iota PresenceOptional )
Instructions type, operator and presence
Variables ¶
var ( // ErrS1 is a static error if templates encoded in the concrete XML syntax are in // fact not well-formed, do not follow the rules of XML namespaces or are invalid // with respect to the schema in Appendix 1 in FAST 1.1 specification. // TODO have to find native lib to check xml syntax ErrS1 = errors.New("static error: S1") // ErrS2 is a static error if an operator is specified for a field of a type to // which the operator is not applicable. ErrS2 = errors.New("static error: S2") // ErrS3 is a static error if an initial value specified by the value attribute // in the concrete syntax can not be converted to a value of the type of the field. ErrS3 = errors.New("static error: S3") // ErrS4 is a static error if no initial value is specified for a constant operator. ErrS4 = errors.New("static error: S4") // ErrS5 is a static error if no initial value is specified for a default operator // on a mandatory field. ErrS5 = errors.New("static error: S5") // ErrD1 is a dynamic error if type of a field in a template can not be converted // to or from the type of the corresponding application field. ErrD1 = errors.New("dynamic error: D1") // ErrD2 is a dynamic error if an integer in the stream does not fall within the // bounds of the specifies integer type specified on the corresponding field. ErrD2 = errors.New("dynamic error: D2") // ErrD3 is a dynamic error if a decimal value can not be encoded due to limitation // introduced by using individual operators on exponent and mantissa. ErrD3 = errors.New("dynamic error: D3") // ErrD4 is a dynamic error if the type of the previous value is not the same as // the type of the field of the current operator. ErrD4 = errors.New("dynamic error: D4") // ErrD5 is a dynamic error if a mandatory field is not present in the stream, has // an undefined previous value and there is no initial value in the instruction // context. ErrD5 = errors.New("dynamic error: D5") // ErrD6 is a dynamic error if a mandatory field is not present in the stream and // has an empty previous value. ErrD6 = errors.New("dynamic error: D6") // ErrD7 is a dynamic error if the subtraction length exceeds the length of the base // value or if it does not fall in the value rang of an int32. ErrD7 = errors.New("dynamic error: D7") // ErrD8 is a dynamic error if the name specified on a static template reference // does not point to a template known be the encoder or decoder. ErrD8 = errors.New("dynamic error: D8") // ErrD9 is a dynamic error if a decoder can not find a template associated with a // template identifier appearing in the stream. ErrD9 = errors.New("dynamic error: D9") // ErrD10 is a dynamic error to convert byte vectors to and from other types // than string. ErrD10 = errors.New("dynamic error: D10") // ErrD11 is a dynamic error if the syntax of a string does not follow the rules for // the type converted to. ErrD11 = errors.New("dynamic error: D11") // ErrD12 is a dynamic error if a block length preamble is zero. ErrD12 = errors.New("dynamic error: D12") // ErrR1 is a reportable error if a decimal can not be represented by an exponent in // the range [-63 ... 63] of if the mantissa does not fit in an int64. ErrR1 = errors.New("reportable error: R1") // ErrR2 is a reportable error if the combined value after applying a tail or delta // operator to a Unicode string is not a valid UTF-8 sequence. ErrR2 = errors.New("reportable error: R2") // ErrR3 is a reportable error if a Unicode string that is being converted to an // ASCII string contains characters that are outside the ASCII character set. ErrR3 = errors.New("reportable error: R3") // ErrR4 is a reportable error if a value of an integer cannot be represented in the // target integer type in a conversion. ErrR4 = errors.New("reportable error: R4") // ErrR5 is a reportable error if a decimal being converted to an integer has a // negative exponent or if the resulting integer does not fit the target integer // type. ErrR5 = errors.New("reportable error: R5") // ErrR6 is a reportable error if an integer appears in an overlong encoding. ErrR6 = errors.New("reportable error: R6") // ErrR7 is a reportable error if a presence map is overlong. ErrR7 = errors.New("reportable error: R7") // ErrR8 is a reportable error if a presence map contains more bits than required. ErrR8 = errors.New("reportable error: R8") // ErrR9 is a reportable error if a string appears in an overlong encoding. ErrR9 = errors.New("reportable error: R9") )
Functions ¶
This section is empty.
Types ¶
type Decoder ¶
type Decoder struct {
// contains filtered or unexported fields
}
A Decoder reads and decodes FAST-encoded message from an io.Reader. You may need buffered reader since decoder reads data byte by byte.
func NewDecoder ¶
NewDecoder returns a new decoder that reads from reader.
func (*Decoder) Decode ¶
Decode reads the next FAST-encoded message from reader and stores it in the value pointed to by msg. If an encountered data implements the Receiver interface and is not a nil pointer, Decode will use methods of Receiver for set decoded data.
Example (Reflection) ¶
var xmlData = ` <?xml version="1.0" encoding="UTF-8"?> <templates xmlns="http://www.fixprotocol.org/ns/fast/td/1.1"> <template name="Done" id="1" xmlns="http://www.fixprotocol.org/ns/fast/td/1.1"> <string name="Type" id="15"> <constant value="99"/> </string> <string name="Test" id="131" presence="optional"/> <uInt64 name="Time" id="20" presence="optional"/> <int32 name="Equal" id="271"/> <sequence name="Sequence"> <length name="SeqLength" id="146"/> <uInt64 name="SomeField" id="38"/> </sequence> </template> </templates>` type Seq struct { SomeField uint64 } type ReflectMsg struct { TemplateID uint `fast:"*"` // template id FieldByID string `fast:"15"` // assign value by instruction id FieldByName string `fast:"Test"` // assign value by instruction name Equal int32 // name of field is default value for assign Nullable *uint64 `fast:"20"` // nullable - will skip, if field data is absent Skip int `fast:"-"` // skip Sequence []Seq } var msg ReflectMsg reader := bytes.NewReader( []byte{0xc0, 0x81, 0x74, 0x65, 0x73, 0xf4, 0x80, 0x80, 0x81, 0x80, 0x82}, ) tpls, err := fast.ParseXMLTemplate(strings.NewReader(xmlData)) if err != nil { panic(err) } decoder := fast.NewDecoder( reader, tpls..., ) if err := decoder.Decode(&msg); err != nil { panic(err) } fmt.Print(msg)
Output: {1 99 test 0 <nil> 0 [{0}]}
type Encoder ¶
type Encoder struct {
// contains filtered or unexported fields
}
A Encoder encodes and writes data to io.Writer.
func NewEncoder ¶
NewEncoder returns a new encoder that writes FAST-encoded message to writer.
func (*Encoder) Encode ¶
Encode encodes msg struct to writer. If an encountered value implements the Sender interface and is not a nil pointer, Encode calls method of Sender to produce encoded message.
Example (Reflection) ¶
var xmlData = ` <?xml version="1.0" encoding="UTF-8"?> <templates xmlns="http://www.fixprotocol.org/ns/fast/td/1.1"> <template name="Done" id="1" xmlns="http://www.fixprotocol.org/ns/fast/td/1.1"> <string name="Type" id="15"> <constant value="99"/> </string> <string name="Test" id="131" presence="optional"/> <uInt64 name="Time" id="20" presence="optional"/> <int32 name="Equal" id="271"/> <sequence name="Sequence"> <length name="SeqLength" id="146"/> <uInt64 name="SomeField" id="38"/> </sequence> </template> </templates>` type Seq struct { SomeField uint64 } type ReflectMsg struct { TemplateID uint `fast:"*"` // template id FieldByID string `fast:"15"` // assign value by instruction id FieldByName string `fast:"Test"` // assign value by instruction name Equal int32 // name of field is default value for assign Nullable *uint64 `fast:"20"` // nullable - will skip, if field data is absent Skip int `fast:"-"` // skip Sequence []Seq } var buf bytes.Buffer var msg = ReflectMsg{ TemplateID: 1, FieldByName: "test", Sequence: []Seq{ {SomeField: 2}, }, } tpls, err := fast.ParseXMLTemplate(strings.NewReader(xmlData)) if err != nil { panic(err) } encoder := fast.NewEncoder(&buf, tpls...) if err := encoder.Encode(&msg); err != nil { panic(err) } fmt.Printf("%x", buf.Bytes())
Output: c081746573f4808182
type Field ¶
type Field struct { ID uint Name string Value interface{} // contains filtered or unexported fields }
Field contains value for decoding/encoding
type Instruction ¶
type Instruction struct { ID uint Name string Presence InstructionPresence Type InstructionType Operator InstructionOperator Instructions []*Instruction Value interface{} // contains filtered or unexported fields }
Instruction contains rules for encoding/decoding field.
type InstructionOperator ¶
type InstructionOperator int
InstructionOperator specifies ways to optimize the encoding of the field.
type InstructionPresence ¶
type InstructionPresence int
InstructionPresence specifies presence of the field.
type InstructionType ¶
type InstructionType int
InstructionType specifies the basic encoding of the field.
type Receiver ¶
type Receiver interface { // SetTemplateID indicates template id for message. SetTemplateID(uint) // SetValue indicates actual Field.Value for Field.Name or Field.ID. SetValue(*Field) // SetLength indicates length of sequence. SetLength(*Field) // Lock indicates a group or sequence. Field.Value will contain index of sequence Lock(*Field) bool Unlock() }
Receiver is interface for setting data avoid reflection.
type Sender ¶
type Sender interface { // GetTemplateID must return template id for message. GetTemplateID() uint // GetValue must set actual value to Field.Value for Field.Name or Field.ID. GetValue(*Field) // GetLength must set actual sequence length to Field.Value for Field.Name or Field.ID. GetLength(*Field) // Lock indicates a group or sequence. Field.Value will contain index of sequence Lock(*Field) bool Unlock() }
Sender is interface for getting data avoid reflection.