1use smallvec::SmallVec;
2
3use crate::checksum::compute_checksum;
4use crate::error::FixError;
5use crate::field::FIELD_SEPARATOR;
6use crate::message::Message;
7use crate::tag;
8
9const DEFAULT_CAPACITY: usize = 512;
12
13pub struct Encoder {
25 body: SmallVec<[u8; DEFAULT_CAPACITY]>,
28 disable_auto_calculate_body_length: bool,
31 disable_auto_calculate_checksum: bool,
34}
35
36impl Default for Encoder {
37 fn default() -> Self {
38 Self::new()
39 }
40}
41
42impl Encoder {
43 pub fn new() -> Self {
45 Self {
46 body: SmallVec::new(),
47 disable_auto_calculate_body_length: false,
48 disable_auto_calculate_checksum: false,
49 }
50 }
51
52 pub fn with_capacity(capacity: usize) -> Self {
54 Self {
55 body: SmallVec::with_capacity(capacity),
56 disable_auto_calculate_body_length: false,
57 disable_auto_calculate_checksum: false,
58 }
59 }
60
61 pub fn disable_auto_calculate_body_length(&mut self, disable: bool) -> &mut Self {
67 self.disable_auto_calculate_body_length = disable;
68 self
69 }
70
71 pub fn disable_auto_calculate_checksum(&mut self, disable: bool) -> &mut Self {
77 self.disable_auto_calculate_checksum = disable;
78 self
79 }
80
81 pub fn encode(&mut self, msg: &Message<'_>, out: &mut Vec<u8>) -> Result<(), FixError> {
89 const DEFAULT_VERSION: &[u8] = b"FIX.4.4";
90 let version = msg
91 .find(tag::BEGIN_STRING)
92 .map(|f| f.value)
93 .unwrap_or(DEFAULT_VERSION);
94
95 self.body.clear();
97 for field in msg.fields() {
98 if field.tag == tag::BEGIN_STRING
99 || field.tag == tag::BODY_LENGTH
100 || field.tag == tag::CHECK_SUM
101 {
102 continue;
103 }
104 let (digits, pos) = u32_to_ascii(field.tag);
105 self.body.extend_from_slice(&digits[pos..]);
106 self.body.push(b'=');
107 self.body.extend_from_slice(field.value);
108 self.body.push(FIELD_SEPARATOR);
109 }
110
111 out.clear();
113
114 out.extend_from_slice(b"8=");
115 out.extend_from_slice(version);
116 out.push(FIELD_SEPARATOR);
117
118 if self.disable_auto_calculate_body_length {
119 if let Some(f) = msg.find(tag::BODY_LENGTH) {
120 out.extend_from_slice(b"9=");
121 out.extend_from_slice(f.value);
122 out.push(FIELD_SEPARATOR);
123 }
124 } else {
125 out.extend_from_slice(b"9=");
126 let (digits, pos) = u32_to_ascii(self.body.len() as u32);
127 out.extend_from_slice(&digits[pos..]);
128 out.push(FIELD_SEPARATOR);
129 }
130
131 out.extend_from_slice(&self.body);
132
133 if self.disable_auto_calculate_checksum {
134 if let Some(f) = msg.find(tag::CHECK_SUM) {
135 out.extend_from_slice(b"10=");
136 out.extend_from_slice(f.value);
137 out.push(FIELD_SEPARATOR);
138 }
139 } else {
140 let checksum = compute_checksum(out);
141 out.extend_from_slice(b"10=");
142 out.extend_from_slice(&checksum_to_ascii(checksum));
143 out.push(FIELD_SEPARATOR);
144 }
145
146 Ok(())
147 }
148}
149
150#[inline]
153fn u32_to_ascii(n: u32) -> ([u8; 10], usize) {
154 let mut buf = [0u8; 10];
155 let mut pos = 10usize;
156 let mut v = n;
157 loop {
158 pos -= 1;
159 buf[pos] = b'0' + (v % 10) as u8;
160 v /= 10;
161 if v == 0 {
162 break;
163 }
164 }
165 (buf, pos)
166}
167
168#[inline]
171fn checksum_to_ascii(n: u8) -> [u8; 3] {
172 [b'0' + n / 100, b'0' + (n / 10) % 10, b'0' + n % 10]
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178 use crate::decoder::Decoder;
179
180 #[test]
181 fn encode_single_body_field() {
182 let raw = b"8=FIX.4.2\x019=5\x0135=D\x0110=181\x01";
183 let mut dec = Decoder::new();
184 let msg = dec.decode(raw).unwrap();
185 let mut enc = Encoder::new();
186 let mut out = Vec::new();
187 enc.encode(&msg, &mut out).unwrap();
188 assert_eq!(out.as_slice(), raw.as_ref());
189 }
190
191 #[test]
192 fn encode_validates_body_length_and_checksum() {
193 let raw = b"8=FIX.4.2\x019=5\x0135=D\x0110=181\x01";
194 let mut dec = Decoder::new();
195 let msg = dec.decode(raw).unwrap();
196 let mut enc = Encoder::new();
197 let mut out = Vec::new();
198 enc.encode(&msg, &mut out).unwrap();
199 let mut dec2 = Decoder::new();
200 let msg2 = dec2.decode(&out).unwrap();
201 assert!(msg2.validate_body_length().is_ok());
202 assert!(msg2.validate_checksum().is_ok());
203 }
204
205 #[test]
206 fn encode_multiple_body_fields() {
207 let raw = b"8=FIX.4.2\x019=20\x0135=D\x0149=SENDER\x0156=TARGET\x0110=100\x01";
208 let mut dec = Decoder::new();
209 let msg = dec.decode(raw).unwrap();
210 let mut enc = Encoder::new();
211 let mut out = Vec::new();
212 enc.encode(&msg, &mut out).unwrap();
213 let mut dec2 = Decoder::new();
214 let msg2 = dec2.decode(&out).unwrap();
215 assert!(msg2.validate_body_length().is_ok());
216 assert!(msg2.validate_checksum().is_ok());
217 }
218
219 #[test]
220 fn encode_missing_tag8_defaults_to_fix44() {
221 let raw = b"35=D\x01";
222 let mut dec = Decoder::new();
223 let msg = dec.decode(raw).unwrap();
224 let mut enc = Encoder::new();
225 let mut out = Vec::new();
226 enc.encode(&msg, &mut out).unwrap();
227 assert!(out.starts_with(b"8=FIX.4.4\x01"));
228 let mut dec2 = Decoder::new();
229 let msg2 = dec2.decode(&out).unwrap();
230 assert!(msg2.validate_body_length().is_ok());
231 assert!(msg2.validate_checksum().is_ok());
232 }
233
234 #[test]
235 fn encode_clears_existing_out_buffer() {
236 let raw = b"8=FIX.4.2\x019=5\x0135=D\x0110=181\x01";
237 let mut dec = Decoder::new();
238 let msg = dec.decode(raw).unwrap();
239 let mut enc = Encoder::new();
240 let mut out = b"stale_data".to_vec();
241 enc.encode(&msg, &mut out).unwrap();
242 assert!(!out.starts_with(b"stale_data"));
243 assert!(out.starts_with(b"8="));
244 }
245
246 #[test]
247 fn encode_reuse_encode_twice() {
248 let raw1 = b"8=FIX.4.2\x019=5\x0135=D\x0110=181\x01";
250 let raw2 = b"8=FIX.4.2\x019=20\x0135=D\x0149=SENDER\x0156=TARGET\x0110=100\x01";
251 let mut dec = Decoder::new();
252 let mut enc = Encoder::new();
253 let mut out = Vec::new();
254
255 let msg1 = dec.decode(raw1).unwrap();
256 enc.encode(&msg1, &mut out).unwrap();
257 let encoded1 = out.clone();
258
259 let msg2 = dec.decode(raw2).unwrap();
260 enc.encode(&msg2, &mut out).unwrap();
261
262 let mut dec2 = Decoder::new();
264 let m1 = dec2.decode(&encoded1).unwrap();
265 assert!(m1.validate_body_length().is_ok());
266 assert!(m1.validate_checksum().is_ok());
267
268 let m2 = dec2.decode(&out).unwrap();
270 assert!(m2.validate_body_length().is_ok());
271 assert!(m2.validate_checksum().is_ok());
272 }
273
274 #[test]
275 fn encode_disable_auto_body_length_uses_message_value() {
276 let raw = b"8=FIX.4.2\x019=5\x0135=D\x0110=181\x01";
278 let mut dec = Decoder::new();
279 let msg = dec.decode(raw).unwrap();
280 let mut enc = Encoder::new();
281 enc.disable_auto_calculate_body_length(true);
282 let mut out = Vec::new();
283 enc.encode(&msg, &mut out).unwrap();
284 assert!(out.windows(4).any(|w| w == b"9=5\x01"));
286 }
287
288 #[test]
289 fn encode_disable_auto_body_length_omits_tag9_when_absent() {
290 let raw = b"35=D\x01";
293 let mut dec = Decoder::new();
294 let msg = dec.decode(raw).unwrap();
295 let mut enc = Encoder::new();
296 enc.disable_auto_calculate_body_length(true);
297 let mut out = Vec::new();
298 enc.encode(&msg, &mut out).unwrap();
299 assert!(!out.windows(2).any(|w| w == b"9="));
300 }
301
302 #[test]
303 fn encode_disable_auto_checksum_uses_message_value() {
304 let raw = b"8=FIX.4.2\x019=5\x0135=D\x0110=181\x01";
306 let mut dec = Decoder::new();
307 let msg = dec.decode(raw).unwrap();
308 let mut enc = Encoder::new();
309 enc.disable_auto_calculate_checksum(true);
310 let mut out = Vec::new();
311 enc.encode(&msg, &mut out).unwrap();
312 assert!(out.windows(7).any(|w| w == b"10=181\x01"));
314 }
315
316 #[test]
317 fn encode_disable_auto_checksum_omits_tag10_when_absent() {
318 let raw = b"35=D\x01";
321 let mut dec = Decoder::new();
322 let msg = dec.decode(raw).unwrap();
323 let mut enc = Encoder::new();
324 enc.disable_auto_calculate_checksum(true);
325 let mut out = Vec::new();
326 enc.encode(&msg, &mut out).unwrap();
327 assert!(!out.windows(3).any(|w| w == b"10="));
328 }
329
330 #[test]
331 fn encode_disable_both_preserves_original_bytes() {
332 let raw = b"8=FIX.4.2\x019=5\x0135=D\x0110=181\x01";
334 let mut dec = Decoder::new();
335 let msg = dec.decode(raw).unwrap();
336 let mut enc = Encoder::new();
337 enc.disable_auto_calculate_body_length(true);
338 enc.disable_auto_calculate_checksum(true);
339 let mut out = Vec::new();
340 enc.encode(&msg, &mut out).unwrap();
341 assert_eq!(out.as_slice(), raw.as_ref());
342 }
343
344 #[test]
345 fn encode_disable_body_length_re_enable_auto_calculates_correctly() {
346 let raw = b"8=FIX.4.2\x019=5\x0135=D\x0110=181\x01";
348 let mut dec = Decoder::new();
349 let msg = dec.decode(raw).unwrap();
350 let mut enc = Encoder::new();
351 enc.disable_auto_calculate_body_length(true);
352 enc.disable_auto_calculate_body_length(false);
353 let mut out = Vec::new();
354 enc.encode(&msg, &mut out).unwrap();
355 let mut dec2 = Decoder::new();
356 let msg2 = dec2.decode(&out).unwrap();
357 assert!(msg2.validate_body_length().is_ok());
358 }
359
360 #[test]
361 fn encode_disable_checksum_re_enable_auto_calculates_correctly() {
362 let raw = b"8=FIX.4.2\x019=5\x0135=D\x0110=181\x01";
364 let mut dec = Decoder::new();
365 let msg = dec.decode(raw).unwrap();
366 let mut enc = Encoder::new();
367 enc.disable_auto_calculate_checksum(true);
368 enc.disable_auto_calculate_checksum(false);
369 let mut out = Vec::new();
370 enc.encode(&msg, &mut out).unwrap();
371 let mut dec2 = Decoder::new();
372 let msg2 = dec2.decode(&out).unwrap();
373 assert!(msg2.validate_checksum().is_ok());
374 }
375
376 #[test]
377 fn encode_disable_body_length_passes_wrong_value_verbatim() {
378 let raw = b"8=FIX.4.2\x019=999\x0135=D\x0110=181\x01";
381 let mut dec = Decoder::new();
382 let msg = dec.decode(raw).unwrap();
383 let mut enc = Encoder::new();
384 enc.disable_auto_calculate_body_length(true);
385 let mut out = Vec::new();
386 enc.encode(&msg, &mut out).unwrap();
387 assert!(out.windows(6).any(|w| w == b"9=999\x01"));
388 let mut dec2 = Decoder::new();
389 let msg2 = dec2.decode(&out).unwrap();
390 assert!(msg2.validate_body_length().is_err());
391 }
392
393 #[test]
394 fn encode_disable_checksum_passes_wrong_value_verbatim() {
395 let raw = b"8=FIX.4.2\x019=5\x0135=D\x0110=000\x01";
398 let mut dec = Decoder::new();
399 let msg = dec.decode(raw).unwrap();
400 let mut enc = Encoder::new();
401 enc.disable_auto_calculate_checksum(true);
402 let mut out = Vec::new();
403 enc.encode(&msg, &mut out).unwrap();
404 assert!(out.windows(7).any(|w| w == b"10=000\x01"));
405 let mut dec2 = Decoder::new();
406 let msg2 = dec2.decode(&out).unwrap();
407 assert!(msg2.validate_checksum().is_err());
408 }
409
410 #[test]
411 fn encode_auto_body_length_ignores_wrong_value_in_message() {
412 let raw = b"8=FIX.4.2\x019=999\x0135=D\x0110=181\x01";
414 let mut dec = Decoder::new();
415 let msg = dec.decode(raw).unwrap();
416 let mut enc = Encoder::new();
417 let mut out = Vec::new();
419 enc.encode(&msg, &mut out).unwrap();
420 let mut dec2 = Decoder::new();
421 let msg2 = dec2.decode(&out).unwrap();
422 assert!(msg2.validate_body_length().is_ok());
423 }
424
425 #[test]
426 fn encode_auto_checksum_ignores_wrong_value_in_message() {
427 let raw = b"8=FIX.4.2\x019=5\x0135=D\x0110=000\x01";
429 let mut dec = Decoder::new();
430 let msg = dec.decode(raw).unwrap();
431 let mut enc = Encoder::new();
432 let mut out = Vec::new();
434 enc.encode(&msg, &mut out).unwrap();
435 let mut dec2 = Decoder::new();
436 let msg2 = dec2.decode(&out).unwrap();
437 assert!(msg2.validate_checksum().is_ok());
438 }
439
440 #[test]
441 fn encode_disable_body_length_only_does_not_affect_checksum() {
442 let raw = b"8=FIX.4.2\x019=5\x0135=D\x0110=181\x01";
444 let mut dec = Decoder::new();
445 let msg = dec.decode(raw).unwrap();
446 let mut enc = Encoder::new();
447 enc.disable_auto_calculate_body_length(true);
448 let mut out = Vec::new();
449 enc.encode(&msg, &mut out).unwrap();
450 assert!(out.windows(4).any(|w| w == b"9=5\x01"));
452 let mut dec2 = Decoder::new();
454 let msg2 = dec2.decode(&out).unwrap();
455 assert!(msg2.validate_checksum().is_ok());
456 }
457
458 #[test]
459 fn encode_disable_checksum_only_does_not_affect_body_length() {
460 let raw = b"8=FIX.4.2\x019=5\x0135=D\x0110=181\x01";
462 let mut dec = Decoder::new();
463 let msg = dec.decode(raw).unwrap();
464 let mut enc = Encoder::new();
465 enc.disable_auto_calculate_checksum(true);
466 let mut out = Vec::new();
467 enc.encode(&msg, &mut out).unwrap();
468 assert!(out.windows(7).any(|w| w == b"10=181\x01"));
470 let mut dec2 = Decoder::new();
472 let msg2 = dec2.decode(&out).unwrap();
473 assert!(msg2.validate_body_length().is_ok());
474 }
475}