hotfix_encoding/
encoder.rs

1use crate::dict::IsFieldDefinition;
2use crate::field_types::CheckSum;
3use crate::Config;
4use crate::{Buffer, BufferWriter, FieldType, GetConfig, TagU32};
5use std::fmt::Write;
6use std::ops::Range;
7
8/// Allows to write FIX fields.
9pub trait SetField<F> {
10    /// Writes a field with default [`FieldType::SerializeSettings`].
11    fn set<'a, V>(&'a mut self, field: F, value: V)
12    where
13        V: FieldType<'a>,
14    {
15        self.set_with(field, value, <V::SerializeSettings as Default>::default())
16    }
17
18    /// Writes a field with custom [`FieldType::SerializeSettings`].
19    fn set_with<'a, V>(&'a mut self, field: F, value: V, setting: V::SerializeSettings)
20    where
21        V: FieldType<'a>;
22}
23
24/// A buffered, content-agnostic FIX encoder.
25///
26/// [`Encoder`] is the fundamental building block for building higher-level
27/// FIX encoders. It allows for encoding of arbitrary payloads and takes care of
28/// `BodyLength (9)` and `CheckSum (10)`.
29///
30/// # Examples
31///
32/// ```
33/// use hotfix_encoding::{Config, Encoder, GetConfig};
34///
35/// let mut buffer = Vec::new();
36/// let mut encoder = Encoder::default();
37/// encoder.config_mut().separator = b'|';
38/// let msg = encoder.start_message(b"FIX.4.4", &mut buffer, b"A");
39/// let data = msg.done();
40/// ```
41#[derive(Debug, Clone, Default)]
42pub struct Encoder {
43    config: Config,
44}
45
46impl Encoder {
47    /// Creates a new [`Encoder`] with [`Default`] configuration options.
48    pub fn new() -> Self {
49        Self::default()
50    }
51
52    /// Creates a new [`EncoderHandle`] that allows to set the field values of a
53    /// new FIX message. The raw byte contents of the newly created FIX messages
54    /// are appended directly at the end of `buffer`.
55    pub fn start_message<'a, B>(
56        &'a mut self,
57        begin_string: &[u8],
58        buffer: &'a mut B,
59        msg_type: &[u8],
60    ) -> EncoderHandle<'a, B>
61    where
62        B: Buffer,
63    {
64        let initial_buffer_len = buffer.len();
65        let mut state = EncoderHandle {
66            encoder: self,
67            buffer,
68            initial_buffer_len,
69            body_start_i: 0,
70        };
71        state.set(8, begin_string);
72        // The second field is supposed to be `BodyLength(9)`, but obviously
73        // the length of the message is unknown until later in the
74        // serialization phase. This alone would usually require to
75        //
76        //  1. Serialize the rest of the message into an external buffer.
77        //  2. Calculate the length of the message.
78        //  3. Serialize `BodyLength(9)` to `buffer`.
79        //  4. Copy the contents of the external buffer into `buffer`.
80        //  5. ... go on with the serialization process.
81        //
82        // Luckily, FIX allows for zero-padded integer values and we can
83        // leverage this to reserve some space for the value. We waste
84        // some bytes but the benefits largely outweight the costs.
85        //
86        // Eight digits (~100MB) are enough for every message.
87        state.set(9, b"00000000" as &[u8]);
88        state.body_start_i = state.buffer.len();
89        state.set(35, msg_type);
90        state
91    }
92}
93
94impl GetConfig for Encoder {
95    type Config = Config;
96
97    fn config(&self) -> &Self::Config {
98        &self.config
99    }
100
101    fn config_mut(&mut self) -> &mut Self::Config {
102        &mut self.config
103    }
104}
105
106/// A type returned by [`Encoder::start_message`](Encoder::start_message) to
107/// actually encode data fields.
108#[derive(Debug)]
109pub struct EncoderHandle<'a, B> {
110    encoder: &'a mut Encoder,
111    buffer: &'a mut B,
112    initial_buffer_len: usize,
113    body_start_i: usize,
114}
115
116impl<'a, B> EncoderHandle<'a, B>
117where
118    B: Buffer,
119{
120    /// Closes the current message writing operation and returns its byte
121    /// representation, as well as its offset within the whole contents of the
122    /// [`Buffer`].
123    pub fn done(mut self) -> (&'a [u8], usize) {
124        self.write_body_length();
125        self.write_checksum();
126        (self.buffer.as_slice(), self.initial_buffer_len)
127    }
128
129    fn body_length_writable_range(&self) -> Range<usize> {
130        self.body_start_i - 9..self.body_start_i - 1
131    }
132
133    fn body_length(&self) -> usize {
134        self.buffer.as_slice().len() - self.body_start_i
135    }
136
137    fn write_body_length(&mut self) {
138        use std::io::Write;
139
140        let body_length = self.body_length();
141        let body_length_range = self.body_length_writable_range();
142        let mut slice = &mut self.buffer.as_mut_slice()[body_length_range];
143        write!(slice, "{:08}", body_length).unwrap();
144    }
145
146    fn write_checksum(&mut self) {
147        let checksum = CheckSum::compute(self.buffer.as_slice());
148        self.set(10, checksum);
149    }
150}
151
152impl<'a, B> SetField<u32> for EncoderHandle<'a, B>
153where
154    B: Buffer,
155{
156    fn set_with<'s, V>(&'s mut self, tag: u32, value: V, settings: V::SerializeSettings)
157    where
158        V: FieldType<'s>,
159    {
160        write!(BufferWriter(self.buffer), "{}=", tag).unwrap();
161        value.serialize_with(self.buffer, settings);
162        self.buffer
163            .extend_from_slice(&[self.encoder.config().separator]);
164    }
165}
166
167impl<'a, B> SetField<TagU32> for EncoderHandle<'a, B>
168where
169    B: Buffer,
170{
171    fn set_with<'s, V>(&'s mut self, tag: TagU32, value: V, settings: V::SerializeSettings)
172    where
173        V: FieldType<'s>,
174    {
175        self.set_with(tag.get(), value, settings)
176    }
177}
178
179impl<'a, B, F> SetField<&F> for EncoderHandle<'a, B>
180where
181    B: Buffer,
182    F: IsFieldDefinition,
183{
184    fn set_with<'s, V>(&'s mut self, field: &F, value: V, settings: V::SerializeSettings)
185    where
186        V: FieldType<'s>,
187    {
188        self.set_with(field.tag(), value, settings)
189    }
190}