1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// Copyright 2016 James Bendig. See the COPYRIGHT file at the top-level
// directory of this distribution.
//
// Licensed under:
// the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>
// or the Apache License, Version 2.0
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>,
// at your option. This file may not be copied, modified, or distributed
// except according to those terms.
use field_tag::FieldTag;
use field_type::FieldType;
use fix_version::FIXVersion;
use message_version::MessageVersion;
use rule::Rule;
pub trait Field {
type Type;
fn rule() -> Rule;
fn tag_bytes() -> &'static [u8];
fn tag() -> FieldTag;
fn read(field: &<<Self as Field>::Type as FieldType>::Type,fix_version: FIXVersion,message_version: MessageVersion,buf: &mut Vec<u8>,required: bool) -> usize
where <Self as Field>::Type: FieldType;
}
#[macro_export]
macro_rules! define_fields {
( $( $field_name:ident : $field_type:ty = $tag:expr $( => $rule:expr )* ),* $(),* ) => { $(
#[derive(BuildField)]
pub struct $field_name {
#[tag=$tag]
_tag_gen: ::std::marker::PhantomData<()>,
}
impl $crate::field::Field for $field_name {
type Type = $field_type;
#[allow(unreachable_code)]
fn rule() -> $crate::rule::Rule {
//If a rule is provided, prefer it first.
$(
return $rule //A maximum of one rule may be specified.
)*;
//Next, check if the field type provides a rule. This way the BeginGroup rule
//can be specified automatically instead of using a nasty boilerplate in each field
//definition.
if let Some(rule) = <$field_type as $crate::field_type::FieldType>::rule() {
rule
}
//Otherwise, no rule was specified.
else {
$crate::rule::Rule::Nothing
}
}
fn tag_bytes() -> &'static [u8] {
Self::tag_bytes()
}
fn tag() -> $crate::field_tag::FieldTag {
Self::tag()
}
fn read(field: &<<Self as $crate::field::Field>::Type as $crate::field_type::FieldType>::Type,fix_version: $crate::fix_version::FIXVersion,message_version: $crate::message_version::MessageVersion,buf: &mut Vec<u8>,required: bool) -> usize {
use ::std::io::Write;
if !required && <$field_type as $crate::field_type::FieldType>::is_empty(field) {
return 0;
}
let mut result = 1;
match <$field_name as $crate::field::Field>::rule() {
//If this is the first part of a Rule::PrepareForBytes and Rule::ConfirmPreviousTag
//pair, skip the tag completely.
$crate::rule::Rule::PrepareForBytes{ .. } => {
return 0;
},
//If this is the second part of a Rule::PrepareForBytes and
//Rule::ConfirmPreviousTag pair, insert the length tag first.
$crate::rule::Rule::ConfirmPreviousTag{ previous_tag } => {
let previous_tag = previous_tag.to_bytes();
result += 2;
result += buf.write(&previous_tag[..]).unwrap();
buf.push($crate::constant::TAG_END);
result += buf.write(<$field_type as $crate::field_type::FieldType>::len(field).to_string().as_bytes()).unwrap();
buf.push($crate::constant::VALUE_END);
},
//If this tag should only be serialized with a different FIX version, skip the
//tag completely.
$crate::rule::Rule::RequiresFIXVersion{ fix_version: required_fix_version } => {
if fix_version != required_fix_version {
return 0;
}
},
_ => {},
};
//Write tag and value.
result += buf.write(Self::tag_bytes()).unwrap();
buf.push($crate::constant::TAG_END);
result += <$field_type as $crate::field_type::FieldType>::read(field,fix_version,message_version,buf);
//Avoid the VALUE_END symbol iff this is not a repeating group field. This is a
//hack, under the assumption that the field itself adds this symbol, so the field
//can append the remaining groups.
if let $crate::rule::Rule::BeginGroup{ .. } = <$field_name as $crate::field::Field>::rule() {}
else {
result += 1;
buf.push($crate::constant::VALUE_END);
}
result
}
}
)*};
}