mirror of
https://github.com/speice-io/marketdata-shootout
synced 2024-11-21 15:39:07 -05:00
Add initial support for SBE
After having some time to review the code, I'm a huge fan.
This commit is contained in:
parent
0f241926ff
commit
df5198993b
17
build.rs
17
build.rs
@ -1,6 +1,7 @@
|
|||||||
extern crate capnpc;
|
extern crate capnpc;
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
capnpc::CompilerCommand::new()
|
capnpc::CompilerCommand::new()
|
||||||
@ -14,6 +15,18 @@ fn main() {
|
|||||||
inputs: &[Path::new("marketdata.fbs")],
|
inputs: &[Path::new("marketdata.fbs")],
|
||||||
out_dir: Path::new("src/"),
|
out_dir: Path::new("src/"),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
}).expect("Unable to compile flatc");
|
||||||
.expect("Unable to compile flatc");
|
|
||||||
|
// There's no Rust-style builder crate for SBE,
|
||||||
|
// so we need to run the command by hand.
|
||||||
|
// TODO: Automatically download the SBE JAR?
|
||||||
|
let _output = Command::new("java")
|
||||||
|
.arg("-Dsbe.output.dir=src")
|
||||||
|
.arg("-Dsbe.xinclude.aware=true")
|
||||||
|
.arg("-Dsbe.target.language=uk.co.real_logic.sbe.generation.rust.Rust")
|
||||||
|
.arg("-Dsbe.target.namespace=marketdata_sbe")
|
||||||
|
.arg("-jar").arg("sbe-all-1.13.2-all.jar")
|
||||||
|
.arg("marketdata.xml")
|
||||||
|
.output()
|
||||||
|
.expect("Unable to execute SBE compiler");
|
||||||
}
|
}
|
||||||
|
82
marketdata.xml
Normal file
82
marketdata.xml
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<sbe:messageSchema xmlns:sbe="http://fixprotocol.io/2016/sbe"
|
||||||
|
package="marketdata_sbe"
|
||||||
|
id="1"
|
||||||
|
version="0"
|
||||||
|
semanticVersion="5.2"
|
||||||
|
description="Trivial market data schema">
|
||||||
|
<types>
|
||||||
|
<!-- "common types" used by SBE -->
|
||||||
|
<composite name="messageHeader" description="Message identifiers and length of message root.">
|
||||||
|
<type name="blockLength" primitiveType="uint16"/>
|
||||||
|
<type name="templateId" primitiveType="uint16"/>
|
||||||
|
<type name="schemaId" primitiveType="uint16"/>
|
||||||
|
<type name="version" primitiveType="uint16"/>
|
||||||
|
</composite>
|
||||||
|
<composite name="groupSizeEncoding" description="Repeating group dimensions.">
|
||||||
|
<type name="blockLength" primitiveType="uint16"/>
|
||||||
|
<type name="numInGroup" primitiveType="uint16"/>
|
||||||
|
</composite>
|
||||||
|
<composite name="varStringEncoding" description="Variable length UTF-8 String.">
|
||||||
|
<type name="length" primitiveType="uint32" maxValue="1073741824"/>
|
||||||
|
<type name="varData" primitiveType="uint8" length="0" characterEncoding="UTF-8"/>
|
||||||
|
</composite>
|
||||||
|
<composite name="varAsciiEncoding" description="Variable length ASCII String.">
|
||||||
|
<type name="length" primitiveType="uint32" maxValue="1073741824"/>
|
||||||
|
<type name="varData" primitiveType="uint8" length="0" characterEncoding="ASCII"/>
|
||||||
|
</composite>
|
||||||
|
<composite name="varDataEncoding" description="Variable length binary blob.">
|
||||||
|
<type name="length" primitiveType="uint32" maxValue="1073741824"/>
|
||||||
|
<type name="varData" primitiveType="uint8" length="0"/>
|
||||||
|
</composite>
|
||||||
|
|
||||||
|
<!-- types we're actually interested in implementing -->
|
||||||
|
<composite name="Trade">
|
||||||
|
<type name="price" primitiveType="uint64"/>
|
||||||
|
<type name="size" primitiveType="uint32"/>
|
||||||
|
</composite>
|
||||||
|
<composite name="Quote">
|
||||||
|
<type name="price" primitiveType="uint64"/>
|
||||||
|
<type name="size" primitiveType="uint32"/>
|
||||||
|
<type name="flags" primitiveType="uint8"/>
|
||||||
|
<ref name="side" type="Side"/>
|
||||||
|
</composite>
|
||||||
|
<enum name="Side" encodingType="uint8">
|
||||||
|
<validValue name="Buy">0</validValue>
|
||||||
|
<validValue name="Sell">1</validValue>
|
||||||
|
</enum>
|
||||||
|
<enum name="MsgType" encodingType="uint8">
|
||||||
|
<validValue name="Trade">0</validValue>
|
||||||
|
<validValue name="Quote">1</validValue>
|
||||||
|
</enum>
|
||||||
|
</types>
|
||||||
|
<sbe:message name="MultiMessage" id="1" description="Wrapper for sending multiple message chunks at a time">
|
||||||
|
<field name="sequence_number" id="1" type="uint64"/>
|
||||||
|
<group name="messages" id="2">
|
||||||
|
<!--
|
||||||
|
Can't embed messages within each other, so the "MultiMessage" block
|
||||||
|
actually includes each `message` via a group
|
||||||
|
-->
|
||||||
|
<field name="timestamp" id="3" type="int64"/>
|
||||||
|
<!--
|
||||||
|
SBE specifically doesn't have "union" types, so we include both a `trade` and `quote`
|
||||||
|
here and the tag to identify.
|
||||||
|
https://github.com/real-logic/simple-binary-encoding/issues/232
|
||||||
|
|
||||||
|
In the future, there are a couple options:
|
||||||
|
1. Create a "payload header" type and promote "trade" and "quote" to <sbe:message>,
|
||||||
|
since the SBE message header is already able to distinguish between message types
|
||||||
|
2. Create a "group" for each message type, and just include no elements of that type.
|
||||||
|
Uses a `u16` for each message type, instead of padding bytes for the message size.
|
||||||
|
3. Split up the message components and use "session types" to chain things together,
|
||||||
|
as in https://polysync.io/blog/session-types-for-hearty-codecs
|
||||||
|
|
||||||
|
For now, this message format was chosen to approximate the schemas of Cap'n Proto and Flatbuffers
|
||||||
|
-->
|
||||||
|
<field name="msg_type" id="4" type="MsgType"/>
|
||||||
|
<field name="trade" id="5" type="Trade"/>
|
||||||
|
<field name="quote" id="6" type="Quote"/>
|
||||||
|
<data name="symbol" id="100" type="varAsciiEncoding"/>
|
||||||
|
</group>
|
||||||
|
</sbe:message>
|
||||||
|
</sbe:messageSchema>
|
BIN
sbe-all-1.13.2-all.jar
Normal file
BIN
sbe-all-1.13.2-all.jar
Normal file
Binary file not shown.
390
sbe.xsd
Normal file
390
sbe.xsd
Normal file
@ -0,0 +1,390 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xs:schema xmlns:sbe="http://fixprotocol.io/2016/sbe" xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||||
|
targetNamespace="http://fixprotocol.io/2016/sbe" elementFormDefault="unqualified"
|
||||||
|
version="1.0 Draft Standard">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
Message schema for FIX Simple Binary Encoding
|
||||||
|
Version: 1.0 Draft Standard
|
||||||
|
© Copyright 2014-2016 FIX Protocol Limited
|
||||||
|
License: Creative Commons Attribution-NoDerivatives 4.0 International Public License
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:element name="messageSchema">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
Root of XML document, holds all message templates
|
||||||
|
and their elements
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="types" maxOccurs="unbounded">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
More than one set of types may be provided.
|
||||||
|
Names must be unique across all encoding
|
||||||
|
types.
|
||||||
|
Encoding types may appear in any order.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:choice maxOccurs="unbounded">
|
||||||
|
<xs:element name="type" type="sbe:encodedDataType"/>
|
||||||
|
<xs:element name="composite" type="sbe:compositeDataType"/>
|
||||||
|
<xs:element name="enum" type="sbe:enumType"/>
|
||||||
|
<xs:element name="set" type="sbe:setType"/>
|
||||||
|
</xs:choice>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element ref="sbe:message" maxOccurs="unbounded"/>
|
||||||
|
</xs:sequence>
|
||||||
|
<xs:attribute name="package" type="xs:string"/>
|
||||||
|
<xs:attribute name="id" type="xs:unsignedShort">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>Unique ID of a message schema
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attribute name="version" type="xs:nonNegativeInteger" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>The version of a message schema. Initial version
|
||||||
|
is 0.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attribute name="semanticVersion" type="xs:string" use="optional">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>Application layer specification version, such as
|
||||||
|
FIX version 'FIX.5.0SP2'
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attribute name="description" type="xs:string" use="optional"/>
|
||||||
|
<xs:attribute name="byteOrder" default="littleEndian">
|
||||||
|
<xs:simpleType>
|
||||||
|
<xs:restriction base="xs:token">
|
||||||
|
<xs:enumeration value="bigEndian"/>
|
||||||
|
<xs:enumeration value="littleEndian"/>
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attribute name="headerType" type="sbe:symbolicName_t" default="messageHeader">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
Name of the encoding type of the message header,
|
||||||
|
which is the same for all messages in a schema. The name has a
|
||||||
|
default, but an encoding of that name must be present under a
|
||||||
|
'types' element.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="message" type="sbe:blockType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
A message type, also known as a message template
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:element>
|
||||||
|
<xs:complexType name="blockType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>Base type of message and repeating group entry
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="field" type="sbe:fieldType" minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>Fixed-length fields</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="group" type="sbe:groupType" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
<xs:element name="data" type="sbe:fieldType" minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>Variable-length fields</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:element>
|
||||||
|
</xs:sequence>
|
||||||
|
<xs:attribute name="name" type="sbe:symbolicName_t" use="required"/>
|
||||||
|
<xs:attribute name="id" type="xs:unsignedShort" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>Unique ID of a message template
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attribute name="blockLength" type="xs:nonNegativeInteger" use="optional">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>Space reserved for root level of message, not
|
||||||
|
include groups or variable-length
|
||||||
|
data elements.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attributeGroup ref="sbe:semanticAttributes"/>
|
||||||
|
<xs:attributeGroup ref="sbe:versionAttributes"/>
|
||||||
|
</xs:complexType>
|
||||||
|
<xs:complexType name="groupType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
A repeating group contains an array of entries
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:complexContent>
|
||||||
|
<xs:extension base="sbe:blockType">
|
||||||
|
<xs:attribute name="dimensionType" type="sbe:symbolicName_t" default="groupSizeEncoding"/>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:complexContent>
|
||||||
|
</xs:complexType>
|
||||||
|
<xs:complexType name="encodedDataType" mixed="true">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
Simple wire encoding consisting of a primitive type
|
||||||
|
or array of primitives
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:simpleContent>
|
||||||
|
<xs:extension base="xs:token">
|
||||||
|
<xs:attribute name="name" type="sbe:symbolicName_t" use="required"/>
|
||||||
|
<xs:attribute name="nullValue" type="xs:string" use="optional">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>Override of default null indicator for the data
|
||||||
|
type in SBE specification,
|
||||||
|
as a string.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attribute name="minValue" type="xs:string" use="optional"/>
|
||||||
|
<xs:attribute name="maxValue" type="xs:string" use="optional"/>
|
||||||
|
<xs:attribute name="length" type="xs:nonNegativeInteger" default="1"/>
|
||||||
|
<xs:attribute name="primitiveType" use="required">
|
||||||
|
<xs:simpleType>
|
||||||
|
<xs:restriction base="xs:token">
|
||||||
|
<xs:enumeration value="char"/>
|
||||||
|
<xs:enumeration value="int8"/>
|
||||||
|
<xs:enumeration value="int16"/>
|
||||||
|
<xs:enumeration value="int32"/>
|
||||||
|
<xs:enumeration value="int64"/>
|
||||||
|
<xs:enumeration value="uint8"/>
|
||||||
|
<xs:enumeration value="uint16"/>
|
||||||
|
<xs:enumeration value="uint32"/>
|
||||||
|
<xs:enumeration value="uint64"/>
|
||||||
|
<xs:enumeration value="float"/>
|
||||||
|
<xs:enumeration value="double"/>
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attribute name="characterEncoding" type="xs:string" use="optional"/>
|
||||||
|
<xs:attributeGroup ref="sbe:alignmentAttributes"/>
|
||||||
|
<xs:attributeGroup ref="sbe:presenceAttributes"/>
|
||||||
|
<xs:attributeGroup ref="sbe:semanticAttributes"/>
|
||||||
|
<xs:attributeGroup ref="sbe:versionAttributes"/>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:simpleContent>
|
||||||
|
</xs:complexType>
|
||||||
|
<xs:complexType name="compositeDataType" mixed="true">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
A wire encoding composed of multiple parts
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:choice maxOccurs="unbounded">
|
||||||
|
<xs:element name="type" type="sbe:encodedDataType"/>
|
||||||
|
<xs:element name="enum" type="sbe:enumType"/>
|
||||||
|
<xs:element name="set" type="sbe:setType"/>
|
||||||
|
<xs:element name="composite" type="sbe:compositeDataType"/>
|
||||||
|
<xs:element name="ref" type="sbe:refType"/>
|
||||||
|
</xs:choice>
|
||||||
|
<xs:attribute name="name" type="sbe:symbolicName_t" use="required"/>
|
||||||
|
<xs:attributeGroup ref="sbe:alignmentAttributes"/>
|
||||||
|
<xs:attributeGroup ref="sbe:semanticAttributes"/>
|
||||||
|
<xs:attributeGroup ref="sbe:versionAttributes"/>
|
||||||
|
</xs:complexType>
|
||||||
|
<xs:complexType name="enumType" mixed="true">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
An enumeration of valid values
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="validValue" type="sbe:validValue" maxOccurs="unbounded"/>
|
||||||
|
</xs:sequence>
|
||||||
|
<xs:attribute name="name" type="sbe:symbolicName_t" use="required"/>
|
||||||
|
<xs:attribute name="encodingType" type="sbe:symbolicName_t" use="required"/>
|
||||||
|
<xs:attributeGroup ref="sbe:alignmentAttributes"/>
|
||||||
|
<xs:attributeGroup ref="sbe:semanticAttributes"/>
|
||||||
|
<xs:attributeGroup ref="sbe:versionAttributes"/>
|
||||||
|
</xs:complexType>
|
||||||
|
<xs:complexType name="validValue">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
Valid value as a string
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:simpleContent>
|
||||||
|
<xs:extension base="xs:token">
|
||||||
|
<xs:attribute name="name" type="sbe:symbolicName_t" use="required"/>
|
||||||
|
<xs:attribute name="description" type="xs:string" use="optional"/>
|
||||||
|
<xs:attributeGroup ref="sbe:versionAttributes"/>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:simpleContent>
|
||||||
|
</xs:complexType>
|
||||||
|
<xs:complexType name="refType" mixed="true">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
A reference to any existing encoding type (simple type, enum or set)
|
||||||
|
to reuse as a member of a composite type
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:attribute name="name" type="sbe:symbolicName_t" use="required"/>
|
||||||
|
<xs:attribute name="type" type="sbe:symbolicName_t" use="required"/>
|
||||||
|
<xs:attributeGroup ref="sbe:alignmentAttributes"/>
|
||||||
|
<xs:attributeGroup ref="sbe:versionAttributes"/>
|
||||||
|
</xs:complexType>
|
||||||
|
<xs:complexType name="setType" mixed="true">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
A multi value choice (encoded as a bitset)
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="choice" type="sbe:choice" maxOccurs="64"/>
|
||||||
|
</xs:sequence>
|
||||||
|
<xs:attribute name="name" type="sbe:symbolicName_t" use="required"/>
|
||||||
|
<xs:attribute name="encodingType" type="sbe:symbolicName_t" use="required"/>
|
||||||
|
<xs:attributeGroup ref="sbe:alignmentAttributes"/>
|
||||||
|
<xs:attributeGroup ref="sbe:semanticAttributes"/>
|
||||||
|
<xs:attributeGroup ref="sbe:versionAttributes"/>
|
||||||
|
</xs:complexType>
|
||||||
|
<xs:complexType name="choice">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
A choice within a multi value set. Value is the
|
||||||
|
position within a bitset (zero-based index).
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:simpleContent>
|
||||||
|
<xs:extension base="xs:nonNegativeInteger">
|
||||||
|
<xs:attribute name="name" type="sbe:symbolicName_t" use="required"/>
|
||||||
|
<xs:attribute name="description" type="xs:string" use="optional"/>
|
||||||
|
<xs:attributeGroup ref="sbe:versionAttributes"/>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:simpleContent>
|
||||||
|
</xs:complexType>
|
||||||
|
<xs:complexType name="fieldType">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
A field of a message of a specified dataType
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:attribute name="name" type="sbe:symbolicName_t" use="required"/>
|
||||||
|
<xs:attribute name="id" type="xs:unsignedShort" use="required"/>
|
||||||
|
<xs:attribute name="type" type="sbe:symbolicName_t" use="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>Must match the name of an encoding contained by
|
||||||
|
'types' element
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attribute name="epoch" type="xs:string" default="unix"/>
|
||||||
|
<xs:attribute name="timeUnit" type="xs:string" default="nanosecond">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>Deprecated - only for back compatibility with RC2
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attributeGroup ref="sbe:alignmentAttributes"/>
|
||||||
|
<xs:attributeGroup ref="sbe:presenceAttributes"/>
|
||||||
|
<xs:attributeGroup ref="sbe:semanticAttributes"/>
|
||||||
|
<xs:attributeGroup ref="sbe:versionAttributes"/>
|
||||||
|
<!-- start of time period - default is UNIX epoch -->
|
||||||
|
</xs:complexType>
|
||||||
|
<xs:attributeGroup name="semanticAttributes">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
Application layer class. Maps a field or encoding
|
||||||
|
to a FIX data type.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:attribute name="semanticType" type="xs:token" use="optional"/>
|
||||||
|
<xs:attribute name="description" type="xs:string" use="optional"/>
|
||||||
|
</xs:attributeGroup>
|
||||||
|
<xs:attributeGroup name="versionAttributes">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
Schema versioning supports message extension
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:attribute name="sinceVersion" type="xs:nonNegativeInteger" default="0">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
The schema version in which an element was added
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attribute name="deprecated" type="xs:nonNegativeInteger" use="optional">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
The version of the schema in which an element was
|
||||||
|
deprecated. It is retained for back compatibility but should no
|
||||||
|
longer be used by updated applications.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:attributeGroup>
|
||||||
|
<xs:attributeGroup name="alignmentAttributes">
|
||||||
|
<xs:attribute name="offset" type="xs:unsignedInt" use="optional">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>Offset from start of a composite type or block
|
||||||
|
as a zero-based index.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:attributeGroup>
|
||||||
|
<xs:attributeGroup name="presenceAttributes">
|
||||||
|
<xs:attribute name="presence" default="required">
|
||||||
|
<xs:simpleType>
|
||||||
|
<xs:restriction base="xs:token">
|
||||||
|
<xs:enumeration value="required">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>The value must always be populated
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:enumeration>
|
||||||
|
<xs:enumeration value="optional">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>Value may be set to nullValue for its data type
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:enumeration>
|
||||||
|
<xs:enumeration value="constant">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>Value does not vary so it need not be
|
||||||
|
serialized on the wire
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:enumeration>
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attribute name="valueRef" type="sbe:qualifiedName_t" use="optional">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>A constant value as valid value of an enum
|
||||||
|
in the form enum-name.valid-value-name
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:attributeGroup>
|
||||||
|
<xs:simpleType name="symbolicName_t">
|
||||||
|
<xs:restriction base="xs:string">
|
||||||
|
<xs:minLength value="1"/>
|
||||||
|
<xs:maxLength value="64"/>
|
||||||
|
<xs:pattern value="([A-Z]|[a-z]|_)([0-9]|[A-Z]|[a-z]|_)*"/>
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
<xs:simpleType name="qualifiedName_t">
|
||||||
|
<xs:restriction base="xs:string">
|
||||||
|
<xs:pattern value="([A-Z]|[a-z]|_)([0-9]|[A-Z]|[a-z]|_)*\.([A-Z]|[a-z]|_)([0-9]|[A-Z]|[a-z]|_)*"/>
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
</xs:schema>
|
583
src/marketdata_sbe.rs
Normal file
583
src/marketdata_sbe.rs
Normal file
@ -0,0 +1,583 @@
|
|||||||
|
/// Generated code for SBE package marketdata_sbe
|
||||||
|
|
||||||
|
|
||||||
|
/// Imports core rather than std to broaden usable environments.
|
||||||
|
extern crate core;
|
||||||
|
|
||||||
|
/// Result types for error handling
|
||||||
|
|
||||||
|
/// Errors that may occur during the course of encoding or decoding.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum CodecErr {
|
||||||
|
/// Too few bytes in the byte-slice to read or write the data structure relevant
|
||||||
|
/// to the current state of the codec
|
||||||
|
NotEnoughBytes,
|
||||||
|
|
||||||
|
/// Groups and vardata are constrained by the numeric type chosen to represent their
|
||||||
|
/// length as well as optional maxima imposed by the schema
|
||||||
|
SliceIsLongerThanAllowedBySchema,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type CodecResult<T> = core::result::Result<T, CodecErr>;
|
||||||
|
|
||||||
|
/// Scratch Decoder Data Wrapper - codec internal use only
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ScratchDecoderData<'d> {
|
||||||
|
data: &'d [u8],
|
||||||
|
pos: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> ScratchDecoderData<'d> {
|
||||||
|
/// Create a struct reference overlaid atop the data buffer
|
||||||
|
/// such that the struct's contents directly reflect the buffer.
|
||||||
|
/// Advances the `pos` index by the size of the struct in bytes.
|
||||||
|
#[inline]
|
||||||
|
fn read_type<T>(&mut self, num_bytes: usize) -> CodecResult<&'d T> {
|
||||||
|
let end = self.pos + num_bytes;
|
||||||
|
if end <= self.data.len() {
|
||||||
|
let s = self.data[self.pos..end].as_ptr() as *mut T;
|
||||||
|
let v: &'d T = unsafe { &*s };
|
||||||
|
self.pos = end;
|
||||||
|
Ok(v)
|
||||||
|
} else {
|
||||||
|
Err(CodecErr::NotEnoughBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Advances the `pos` index by a set number of bytes.
|
||||||
|
#[inline]
|
||||||
|
fn skip_bytes(&mut self, num_bytes: usize) -> CodecResult<()> {
|
||||||
|
let end = self.pos + num_bytes;
|
||||||
|
if end <= self.data.len() {
|
||||||
|
self.pos = end;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(CodecErr::NotEnoughBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a slice reference overlaid atop the data buffer
|
||||||
|
/// such that the slice's members' contents directly reflect the buffer.
|
||||||
|
/// Advances the `pos` index by the size of the slice contents in bytes.
|
||||||
|
#[inline]
|
||||||
|
fn read_slice<T>(&mut self, count: usize, bytes_per_item: usize) -> CodecResult<&'d [T]> {
|
||||||
|
let num_bytes = bytes_per_item * count;
|
||||||
|
let end = self.pos + num_bytes;
|
||||||
|
if end <= self.data.len() {
|
||||||
|
let v: &'d [T] = unsafe {
|
||||||
|
core::slice::from_raw_parts(self.data[self.pos..end].as_ptr() as *const T, count)
|
||||||
|
};
|
||||||
|
self.pos = end;
|
||||||
|
Ok(v)
|
||||||
|
} else {
|
||||||
|
Err(CodecErr::NotEnoughBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Scratch Encoder Data Wrapper - codec internal use only
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ScratchEncoderData<'d> {
|
||||||
|
data: &'d mut [u8],
|
||||||
|
pos: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> ScratchEncoderData<'d> {
|
||||||
|
/// Copy the bytes of a value into the data buffer
|
||||||
|
/// Advances the `pos` index to after the newly-written bytes.
|
||||||
|
#[inline]
|
||||||
|
fn write_type<T>(&mut self, t: &T, num_bytes: usize) -> CodecResult<()> {
|
||||||
|
let end = self.pos + num_bytes;
|
||||||
|
if end <= self.data.len() {
|
||||||
|
let source_bytes: &[u8] = unsafe {
|
||||||
|
core::slice::from_raw_parts(t as *const T as *const u8, num_bytes)
|
||||||
|
};
|
||||||
|
(&mut self.data[self.pos..end]).copy_from_slice(source_bytes);
|
||||||
|
self.pos = end;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(CodecErr::NotEnoughBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Advances the `pos` index by a set number of bytes.
|
||||||
|
#[inline]
|
||||||
|
fn skip_bytes(&mut self, num_bytes: usize) -> CodecResult<()> {
|
||||||
|
let end = self.pos + num_bytes;
|
||||||
|
if end <= self.data.len() {
|
||||||
|
self.pos = end;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(CodecErr::NotEnoughBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a struct reference overlaid atop the data buffer
|
||||||
|
/// such that changes to the struct directly edit the buffer.
|
||||||
|
/// Note that the initial content of the struct's fields may be garbage.
|
||||||
|
/// Advances the `pos` index to after the newly-written bytes.
|
||||||
|
#[inline]
|
||||||
|
fn writable_overlay<T>(&mut self, num_bytes: usize) -> CodecResult<&'d mut T> {
|
||||||
|
let end = self.pos + num_bytes;
|
||||||
|
if end <= self.data.len() {
|
||||||
|
let v: &'d mut T = unsafe {
|
||||||
|
let s = self.data.as_ptr().offset(self.pos as isize) as *mut T;
|
||||||
|
&mut *s
|
||||||
|
};
|
||||||
|
self.pos = end;
|
||||||
|
Ok(v)
|
||||||
|
} else {
|
||||||
|
Err(CodecErr::NotEnoughBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copy the bytes of a value into the data buffer at a specific position
|
||||||
|
/// Does **not** alter the `pos` index.
|
||||||
|
#[inline]
|
||||||
|
fn write_at_position<T>(&mut self, position: usize, t: &T, num_bytes: usize) -> CodecResult<()> {
|
||||||
|
let end = position + num_bytes;
|
||||||
|
if end <= self.data.len() {
|
||||||
|
let source_bytes: &[u8] = unsafe {
|
||||||
|
core::slice::from_raw_parts(t as *const T as *const u8, num_bytes)
|
||||||
|
};
|
||||||
|
(&mut self.data[position..end]).copy_from_slice(source_bytes);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(CodecErr::NotEnoughBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Create a mutable slice overlaid atop the data buffer directly
|
||||||
|
/// such that changes to the slice contents directly edit the buffer
|
||||||
|
/// Note that the initial content of the slice's members' fields may be garbage.
|
||||||
|
/// Advances the `pos` index to after the region representing the slice.
|
||||||
|
#[inline]
|
||||||
|
fn writable_slice<T>(&mut self, count: usize, bytes_per_item: usize) -> CodecResult<&'d mut [T]> {
|
||||||
|
let end = self.pos + (count * bytes_per_item);
|
||||||
|
if end <= self.data.len() {
|
||||||
|
let v: &'d mut [T] = unsafe {
|
||||||
|
core::slice::from_raw_parts_mut(self.data[self.pos..end].as_mut_ptr() as *mut T, count)
|
||||||
|
};
|
||||||
|
self.pos = end;
|
||||||
|
Ok(v)
|
||||||
|
} else {
|
||||||
|
Err(CodecErr::NotEnoughBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copy the raw bytes of a slice's contents into the data buffer
|
||||||
|
/// Does **not** encode the length of the slice explicitly into the buffer.
|
||||||
|
/// Advances the `pos` index to after the newly-written slice bytes.
|
||||||
|
#[inline]
|
||||||
|
fn write_slice_without_count<T>(&mut self, t: &[T], bytes_per_item: usize) -> CodecResult<()> {
|
||||||
|
let content_bytes_size = bytes_per_item * t.len();
|
||||||
|
let end = self.pos + content_bytes_size;
|
||||||
|
if end <= self.data.len() {
|
||||||
|
let source_bytes: &[u8] = unsafe {
|
||||||
|
core::slice::from_raw_parts(t.as_ptr() as *const u8, content_bytes_size)
|
||||||
|
};
|
||||||
|
(&mut self.data[self.pos..end]).copy_from_slice(source_bytes);
|
||||||
|
self.pos = end;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(CodecErr::NotEnoughBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convenience Either enum
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
|
pub enum Either<L, R> {
|
||||||
|
Left(L),
|
||||||
|
Right(R),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enum Side
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum Side {
|
||||||
|
Buy = 0u8,
|
||||||
|
Sell = 1u8,
|
||||||
|
NullVal = 255u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Side {
|
||||||
|
fn default() -> Self { Side::NullVal }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enum MsgType
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum MsgType {
|
||||||
|
Trade = 0u8,
|
||||||
|
Quote = 1u8,
|
||||||
|
NullVal = 255u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MsgType {
|
||||||
|
fn default() -> Self { MsgType::NullVal }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Quote
|
||||||
|
#[repr(C, packed)]
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Quote {
|
||||||
|
pub price: u64,
|
||||||
|
pub size: u32,
|
||||||
|
pub flags: u8,
|
||||||
|
pub side: Side,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Quote {}
|
||||||
|
|
||||||
|
/// Trade
|
||||||
|
#[repr(C, packed)]
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Trade {
|
||||||
|
pub price: u64,
|
||||||
|
pub size: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trade {}
|
||||||
|
|
||||||
|
/// MessageHeader
|
||||||
|
#[repr(C, packed)]
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct MessageHeader {
|
||||||
|
pub block_length: u16,
|
||||||
|
pub template_id: u16,
|
||||||
|
pub schema_id: u16,
|
||||||
|
pub version: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MessageHeader {}
|
||||||
|
|
||||||
|
/// GroupSizeEncoding
|
||||||
|
#[repr(C, packed)]
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct GroupSizeEncoding {
|
||||||
|
pub block_length: u16,
|
||||||
|
pub num_in_group: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GroupSizeEncoding {}
|
||||||
|
|
||||||
|
/// VarAsciiEncoding
|
||||||
|
#[repr(C, packed)]
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct VarAsciiEncoding {
|
||||||
|
pub length: u32,
|
||||||
|
pub var_data: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VarAsciiEncoding {}
|
||||||
|
|
||||||
|
/// MessageHeader Decoder entry point
|
||||||
|
pub fn start_decoding_message_header<'d>(data: &'d [u8]) -> CodecResult<(&'d MessageHeader, ScratchDecoderData<'d>)> {
|
||||||
|
let mut scratch = ScratchDecoderData { data: data, pos: 0 };
|
||||||
|
let v = scratch.read_type::<MessageHeader>(8)?;
|
||||||
|
Ok((v, scratch))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// MultiMessage Fixed-size Fields (8 bytes)
|
||||||
|
#[repr(C, packed)]
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct MultiMessageFields {
|
||||||
|
pub sequence_number: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl MultiMessageFields {}
|
||||||
|
|
||||||
|
/// MultiMessage specific Message Header
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct MultiMessageMessageHeader {
|
||||||
|
pub message_header: MessageHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MultiMessageMessageHeader {
|
||||||
|
pub const BLOCK_LENGTH: u16 = 8;
|
||||||
|
pub const TEMPLATE_ID: u16 = 1;
|
||||||
|
pub const SCHEMA_ID: u16 = 1;
|
||||||
|
pub const VERSION: u16 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MultiMessageMessageHeader {
|
||||||
|
fn default() -> MultiMessageMessageHeader {
|
||||||
|
MultiMessageMessageHeader {
|
||||||
|
message_header: MessageHeader {
|
||||||
|
block_length: 8u16,
|
||||||
|
template_id: 1u16,
|
||||||
|
schema_id: 1u16,
|
||||||
|
version: 0u16,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Group fixed-field member representations
|
||||||
|
#[repr(C, packed)]
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct MultiMessageMessagesMember {
|
||||||
|
pub timestamp: i64,
|
||||||
|
pub msg_type: MsgType,
|
||||||
|
pub trade: Trade,
|
||||||
|
pub quote: Quote,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MultiMessageMessagesMember {}
|
||||||
|
|
||||||
|
/// MultiMessageDecoderDone
|
||||||
|
pub struct MultiMessageDecoderDone<'d> {
|
||||||
|
scratch: ScratchDecoderData<'d>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> MultiMessageDecoderDone<'d> {
|
||||||
|
/// Returns the number of bytes decoded
|
||||||
|
pub fn unwrap(self) -> usize {
|
||||||
|
self.scratch.pos
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wrap(scratch: ScratchDecoderData<'d>) -> MultiMessageDecoderDone<'d> {
|
||||||
|
MultiMessageDecoderDone { scratch: scratch }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// symbol variable-length data
|
||||||
|
pub struct MultiMessageMessagesSymbolDecoder<'d> {
|
||||||
|
parent: MultiMessageMessagesMemberDecoder<'d>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> MultiMessageMessagesSymbolDecoder<'d> {
|
||||||
|
fn wrap(parent: MultiMessageMessagesMemberDecoder<'d>) -> Self {
|
||||||
|
MultiMessageMessagesSymbolDecoder { parent: parent }
|
||||||
|
}
|
||||||
|
pub fn symbol(mut self) -> CodecResult<(&'d [u8], Either<MultiMessageMessagesMemberDecoder<'d>, MultiMessageDecoderDone<'d>>)> {
|
||||||
|
let count = *self.parent.scratch.read_type::<u32>(4)?;
|
||||||
|
Ok((self.parent.scratch.read_slice::<u8>(count as usize, 1)?, self.parent.after_member()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// MultiMessageMessages Decoder for fields and header
|
||||||
|
pub struct MultiMessageMessagesMemberDecoder<'d> {
|
||||||
|
scratch: ScratchDecoderData<'d>,
|
||||||
|
max_index: u16,
|
||||||
|
index: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> MultiMessageMessagesMemberDecoder<'d> {
|
||||||
|
fn new(scratch: ScratchDecoderData<'d>, count: u16) -> Self {
|
||||||
|
assert!(count > 0u16);
|
||||||
|
MultiMessageMessagesMemberDecoder {
|
||||||
|
scratch: scratch,
|
||||||
|
max_index: count - 1,
|
||||||
|
index: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next_messages_member(mut self) -> CodecResult<(&'d MultiMessageMessagesMember, MultiMessageMessagesSymbolDecoder<'d>)> {
|
||||||
|
let v = self.scratch.read_type::<MultiMessageMessagesMember>(35)?;
|
||||||
|
self.index += 1;
|
||||||
|
Ok((v, MultiMessageMessagesSymbolDecoder::wrap(self)))
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn after_member(self) -> Either<MultiMessageMessagesMemberDecoder<'d>, MultiMessageDecoderDone<'d>> {
|
||||||
|
if self.index <= self.max_index {
|
||||||
|
Either::Left(self)
|
||||||
|
} else {
|
||||||
|
Either::Right(MultiMessageDecoderDone::wrap(self.scratch))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MultiMessageMessagesHeaderDecoder<'d> {
|
||||||
|
scratch: ScratchDecoderData<'d>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> MultiMessageMessagesHeaderDecoder<'d> {
|
||||||
|
fn wrap(scratch: ScratchDecoderData<'d>) -> Self {
|
||||||
|
MultiMessageMessagesHeaderDecoder { scratch: scratch }
|
||||||
|
}
|
||||||
|
pub fn messages_individually(mut self) -> CodecResult<Either<MultiMessageMessagesMemberDecoder<'d>, MultiMessageDecoderDone<'d>>> {
|
||||||
|
let dim = self.scratch.read_type::<GroupSizeEncoding>(4)?;
|
||||||
|
if dim.num_in_group > 0 {
|
||||||
|
Ok(Either::Left(MultiMessageMessagesMemberDecoder::new(self.scratch, dim.num_in_group)))
|
||||||
|
} else {
|
||||||
|
Ok(Either::Right(MultiMessageDecoderDone::wrap(self.scratch)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// MultiMessage Fixed fields Decoder
|
||||||
|
pub struct MultiMessageFieldsDecoder<'d> {
|
||||||
|
scratch: ScratchDecoderData<'d>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> MultiMessageFieldsDecoder<'d> {
|
||||||
|
pub fn wrap(scratch: ScratchDecoderData<'d>) -> MultiMessageFieldsDecoder<'d> {
|
||||||
|
MultiMessageFieldsDecoder { scratch: scratch }
|
||||||
|
}
|
||||||
|
pub fn multi_message_fields(mut self) -> CodecResult<(&'d MultiMessageFields, MultiMessageMessagesHeaderDecoder<'d>)> {
|
||||||
|
let v = self.scratch.read_type::<MultiMessageFields>(8)?;
|
||||||
|
Ok((v, MultiMessageMessagesHeaderDecoder::wrap(self.scratch)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// MultiMessageMessageHeaderDecoder
|
||||||
|
pub struct MultiMessageMessageHeaderDecoder<'d> {
|
||||||
|
scratch: ScratchDecoderData<'d>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> MultiMessageMessageHeaderDecoder<'d> {
|
||||||
|
pub fn wrap(scratch: ScratchDecoderData<'d>) -> MultiMessageMessageHeaderDecoder<'d> {
|
||||||
|
MultiMessageMessageHeaderDecoder { scratch: scratch }
|
||||||
|
}
|
||||||
|
pub fn header(mut self) -> CodecResult<(&'d MessageHeader, MultiMessageFieldsDecoder<'d>)> {
|
||||||
|
let v = self.scratch.read_type::<MessageHeader>(8)?;
|
||||||
|
Ok((v, MultiMessageFieldsDecoder::wrap(self.scratch)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// MultiMessage Decoder entry point
|
||||||
|
pub fn start_decoding_multi_message<'d>(data: &'d [u8]) -> MultiMessageMessageHeaderDecoder<'d> {
|
||||||
|
MultiMessageMessageHeaderDecoder::wrap(ScratchDecoderData { data: data, pos: 0 })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// MultiMessageEncoderDone
|
||||||
|
pub struct MultiMessageEncoderDone<'d> {
|
||||||
|
scratch: ScratchEncoderData<'d>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> MultiMessageEncoderDone<'d> {
|
||||||
|
/// Returns the number of bytes encoded
|
||||||
|
pub fn unwrap(self) -> usize {
|
||||||
|
self.scratch.pos
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wrap(scratch: ScratchEncoderData<'d>) -> MultiMessageEncoderDone<'d> {
|
||||||
|
MultiMessageEncoderDone { scratch: scratch }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// symbol variable-length data
|
||||||
|
pub struct MultiMessageMessagesSymbolEncoder<'d> {
|
||||||
|
parent: MultiMessageMessagesMemberEncoder<'d>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> MultiMessageMessagesSymbolEncoder<'d> {
|
||||||
|
fn wrap(parent: MultiMessageMessagesMemberEncoder<'d>) -> Self {
|
||||||
|
MultiMessageMessagesSymbolEncoder { parent: parent }
|
||||||
|
}
|
||||||
|
pub fn symbol(mut self, s: &'d [u8]) -> CodecResult<MultiMessageMessagesMemberEncoder> {
|
||||||
|
let l = s.len();
|
||||||
|
if l > 4294967294 {
|
||||||
|
return Err(CodecErr::SliceIsLongerThanAllowedBySchema);
|
||||||
|
}
|
||||||
|
// Write data length
|
||||||
|
self.parent.scratch.write_type::<u32>(&(l as u32), 4)?; // group length
|
||||||
|
self.parent.scratch.write_slice_without_count::<u8>(s, 1)?;
|
||||||
|
Ok(self.parent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// MultiMessageMessages Encoder for fields and header
|
||||||
|
pub struct MultiMessageMessagesMemberEncoder<'d> {
|
||||||
|
scratch: ScratchEncoderData<'d>,
|
||||||
|
count_write_pos: usize,
|
||||||
|
count: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> MultiMessageMessagesMemberEncoder<'d> {
|
||||||
|
#[inline]
|
||||||
|
fn new(scratch: ScratchEncoderData<'d>, count_write_pos: usize) -> Self {
|
||||||
|
MultiMessageMessagesMemberEncoder {
|
||||||
|
scratch: scratch,
|
||||||
|
count_write_pos: count_write_pos,
|
||||||
|
count: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn next_messages_member(mut self, fields: &MultiMessageMessagesMember) -> CodecResult<MultiMessageMessagesSymbolEncoder<'d>> {
|
||||||
|
self.scratch.write_type::<MultiMessageMessagesMember>(fields, 35)?; // block length
|
||||||
|
self.count += 1;
|
||||||
|
Ok(MultiMessageMessagesSymbolEncoder::wrap(self))
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn done_with_messages(mut self) -> CodecResult<MultiMessageEncoderDone<'d>> {
|
||||||
|
self.scratch.write_at_position::<u16>(self.count_write_pos, &self.count, 2)?;
|
||||||
|
Ok(MultiMessageEncoderDone::wrap(self.scratch))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MultiMessageMessagesHeaderEncoder<'d> {
|
||||||
|
scratch: ScratchEncoderData<'d>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> MultiMessageMessagesHeaderEncoder<'d> {
|
||||||
|
#[inline]
|
||||||
|
fn wrap(scratch: ScratchEncoderData<'d>) -> Self {
|
||||||
|
MultiMessageMessagesHeaderEncoder { scratch: scratch }
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn messages_individually(mut self) -> CodecResult<MultiMessageMessagesMemberEncoder<'d>> {
|
||||||
|
self.scratch.write_type::<u16>(&35u16, 2)?; // block length
|
||||||
|
let count_pos = self.scratch.pos;
|
||||||
|
self.scratch.write_type::<u16>(&0, 2)?; // preliminary group member count
|
||||||
|
Ok(MultiMessageMessagesMemberEncoder::new(self.scratch, count_pos))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// MultiMessage Fixed fields Encoder
|
||||||
|
pub struct MultiMessageFieldsEncoder<'d> {
|
||||||
|
scratch: ScratchEncoderData<'d>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> MultiMessageFieldsEncoder<'d> {
|
||||||
|
pub fn wrap(scratch: ScratchEncoderData<'d>) -> MultiMessageFieldsEncoder<'d> {
|
||||||
|
MultiMessageFieldsEncoder { scratch: scratch }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a mutable struct reference overlaid atop the data buffer
|
||||||
|
/// such that changes to the struct directly edit the buffer.
|
||||||
|
/// Note that the initial content of the struct's fields may be garbage.
|
||||||
|
pub fn multi_message_fields(mut self) -> CodecResult<(&'d mut MultiMessageFields, MultiMessageMessagesHeaderEncoder<'d>)> {
|
||||||
|
let v = self.scratch.writable_overlay::<MultiMessageFields>(8 + 0)?;
|
||||||
|
Ok((v, MultiMessageMessagesHeaderEncoder::wrap(self.scratch)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copy the bytes of a value into the data buffer
|
||||||
|
pub fn multi_message_fields_copy(mut self, t: &MultiMessageFields) -> CodecResult<MultiMessageMessagesHeaderEncoder<'d>> {
|
||||||
|
self.scratch.write_type::<MultiMessageFields>(t, 8)?;
|
||||||
|
Ok(MultiMessageMessagesHeaderEncoder::wrap(self.scratch))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// MultiMessageMessageHeaderEncoder
|
||||||
|
pub struct MultiMessageMessageHeaderEncoder<'d> {
|
||||||
|
scratch: ScratchEncoderData<'d>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> MultiMessageMessageHeaderEncoder<'d> {
|
||||||
|
pub fn wrap(scratch: ScratchEncoderData<'d>) -> MultiMessageMessageHeaderEncoder<'d> {
|
||||||
|
MultiMessageMessageHeaderEncoder { scratch: scratch }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a mutable struct reference overlaid atop the data buffer
|
||||||
|
/// such that changes to the struct directly edit the buffer.
|
||||||
|
/// Note that the initial content of the struct's fields may be garbage.
|
||||||
|
pub fn header(mut self) -> CodecResult<(&'d mut MessageHeader, MultiMessageFieldsEncoder<'d>)> {
|
||||||
|
let v = self.scratch.writable_overlay::<MessageHeader>(8 + 0)?;
|
||||||
|
Ok((v, MultiMessageFieldsEncoder::wrap(self.scratch)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copy the bytes of a value into the data buffer
|
||||||
|
pub fn header_copy(mut self, t: &MessageHeader) -> CodecResult<MultiMessageFieldsEncoder<'d>> {
|
||||||
|
self.scratch.write_type::<MessageHeader>(t, 8)?;
|
||||||
|
Ok(MultiMessageFieldsEncoder::wrap(self.scratch))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// MultiMessage Encoder entry point
|
||||||
|
pub fn start_encoding_multi_message<'d>(data: &'d mut [u8]) -> MultiMessageMessageHeaderEncoder<'d> {
|
||||||
|
MultiMessageMessageHeaderEncoder::wrap(ScratchEncoderData { data: data, pos: 0 })
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user