easyfix_messages/
deserializer.rs

1use std::{error::Error, fmt};
2
3use anyhow::Result;
4
5use crate::fields::basic_types::*;
6
7#[derive(Debug)]
8pub enum DeserializeError {
9    // TODO: enum maybe?
10    GarbledMessage(String),
11    Logout,
12    Reject {
13        msg_type: Option<FixString>,
14        seq_num: SeqNum,
15        tag: Option<TagNum>,
16        reason: ParseRejectReason,
17    },
18}
19
20impl fmt::Display for DeserializeError {
21    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22        match self {
23            DeserializeError::GarbledMessage(reason) => write!(f, "garbled message: {}", reason),
24            DeserializeError::Logout => write!(f, "MsgSeqNum missing"),
25            DeserializeError::Reject {
26                tag: Some(tag),
27                reason,
28                ..
29            } => write!(f, "{reason:?} (tag={tag})"),
30            DeserializeError::Reject {
31                tag: None, reason, ..
32            } => write!(f, "{reason:?}"),
33        }
34    }
35}
36
37impl Error for DeserializeError {}
38
39impl From<RawMessageError> for DeserializeError {
40    fn from(error: RawMessageError) -> Self {
41        match error {
42            RawMessageError::Incomplete => {
43                DeserializeError::GarbledMessage("Incomplete message data".to_owned())
44            }
45            RawMessageError::Garbled => {
46                DeserializeError::GarbledMessage("Message not well formed".to_owned())
47            }
48            RawMessageError::InvalidChecksum => {
49                DeserializeError::GarbledMessage("Invalid checksum".to_owned())
50            }
51        }
52    }
53}
54
55#[derive(Clone, Copy, Debug, Eq, PartialEq)]
56#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
57#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
58pub enum ParseRejectReason {
59    ValueIsIncorrect,
60    TagSpecifiedWithoutAValue,
61    IncorrectDataFormatForValue,
62    TagAppearsMoreThanOnce,
63    TagSpecifiedOutOfRequiredOrder,
64    RequiredTagMissing,
65    IncorrectNumingroupCountForRepeatingGroup,
66    TagNotDefinedForThisMessageType,
67    UndefinedTag,
68    RepeatingGroupFieldsOutOfOrder,
69    InvalidTagNumber,
70    InvalidMsgtype,
71    SendingtimeAccuracyProblem,
72    CompidProblem,
73}
74
75#[derive(Debug, thiserror::Error)]
76enum DeserializeErrorInternal {
77    #[error("Incomplete")]
78    Incomplete,
79    #[error("{0:?}")]
80    Error(ParseRejectReason),
81}
82
83fn deserialize_tag<'a>(bytes: &'a [u8], tag: &'a [u8]) -> Result<&'a [u8], RawMessageError> {
84    if bytes.len() < tag.len() {
85        Err(RawMessageError::Incomplete)
86    } else if bytes.starts_with(tag) {
87        Ok(&bytes[tag.len()..])
88    } else {
89        Err(RawMessageError::Garbled)
90    }
91}
92
93fn deserialize_checksum(bytes: &[u8]) -> Result<(&[u8], u8), RawMessageError> {
94    if bytes.len() < 4 {
95        return Err(RawMessageError::Incomplete);
96    }
97
98    let mut value: u8 = 0;
99    for b in &bytes[0..3] {
100        match b {
101            n @ b'0'..=b'9' => {
102                value = value
103                    .checked_mul(10)
104                    .and_then(|v| v.checked_add(n - b'0'))
105                    .ok_or(RawMessageError::InvalidChecksum)?;
106            }
107            _ => return Err(RawMessageError::InvalidChecksum),
108        }
109    }
110
111    if bytes[3] != b'\x01' {
112        return Err(RawMessageError::InvalidChecksum);
113    }
114
115    Ok((&bytes[4..], value))
116}
117
118fn deserialize_str(bytes: &[u8]) -> Result<(&[u8], &FixStr), DeserializeErrorInternal> {
119    for (i, b) in bytes.iter().enumerate() {
120        match b {
121            // No control character is allowed
122            0x00 | 0x02..=0x1f | 0x80..=0xff => {
123                return Err(DeserializeErrorInternal::Error(
124                    ParseRejectReason::ValueIsIncorrect,
125                ));
126            }
127            // Except SOH which marks end of tag
128            b'\x01' => {
129                if i == 0 {
130                    return Err(DeserializeErrorInternal::Error(
131                        ParseRejectReason::TagSpecifiedWithoutAValue,
132                    ));
133                } else {
134                    // SAFETY: Check for valid ASCII values just above
135                    return Ok((&bytes[i + 1..], unsafe {
136                        FixStr::from_ascii_unchecked(&bytes[..i])
137                    }));
138                }
139            }
140            _ => {}
141        }
142    }
143
144    Err(DeserializeErrorInternal::Incomplete)
145}
146
147fn deserialize_length(bytes: &[u8]) -> Result<(&[u8], Length), DeserializeErrorInternal> {
148    let mut value: Length = 0;
149    for (i, b) in bytes.iter().enumerate() {
150        match b {
151            n @ b'0'..=b'9' => {
152                value = value
153                    .checked_mul(10)
154                    .and_then(|v| v.checked_add(Length::from(n - b'0')))
155                    .ok_or(DeserializeErrorInternal::Error(
156                        ParseRejectReason::ValueIsIncorrect,
157                    ))?;
158            }
159            b'\x01' => {
160                if i == 0 {
161                    return Err(DeserializeErrorInternal::Error(
162                        ParseRejectReason::TagSpecifiedWithoutAValue,
163                    ));
164                } else if value == 0 {
165                    return Err(DeserializeErrorInternal::Error(
166                        ParseRejectReason::ValueIsIncorrect,
167                    ));
168                } else {
169                    return Ok((&bytes[i + 1..], value));
170                }
171            }
172            _ => {
173                return Err(DeserializeErrorInternal::Error(
174                    ParseRejectReason::IncorrectDataFormatForValue,
175                ));
176            }
177        }
178    }
179
180    Err(DeserializeErrorInternal::Incomplete)
181}
182
183#[derive(Debug)]
184pub struct RawMessage<'a> {
185    pub begin_string: &'a FixStr,
186    pub body: &'a [u8],
187    pub checksum: u8,
188}
189
190#[derive(Debug, thiserror::Error)]
191pub enum RawMessageError {
192    #[error("Incomplete")]
193    Incomplete,
194    #[error("Garbled")]
195    Garbled,
196    #[error("Invalid checksum")]
197    InvalidChecksum,
198}
199
200impl From<DeserializeErrorInternal> for RawMessageError {
201    fn from(d: DeserializeErrorInternal) -> RawMessageError {
202        match d {
203            DeserializeErrorInternal::Incomplete => RawMessageError::Incomplete,
204            DeserializeErrorInternal::Error(_) => RawMessageError::Garbled,
205        }
206    }
207}
208
209pub fn raw_message(bytes: &[u8]) -> Result<(&[u8], RawMessage<'_>), RawMessageError> {
210    let orig_bytes = bytes;
211
212    let bytes = deserialize_tag(bytes, b"8=")?;
213    let (bytes, begin_string) = deserialize_str(bytes)?;
214
215    let bytes = deserialize_tag(bytes, b"9=")?;
216    let (bytes, body_length) = deserialize_length(bytes)?;
217    let body_length = usize::from(body_length);
218
219    const CHECKSUM_LEN: usize = 4;
220    if bytes.len() < body_length + CHECKSUM_LEN {
221        return Err(RawMessageError::Incomplete);
222    }
223
224    let body = &bytes[..body_length];
225    let bytes = &bytes[body_length..];
226
227    let calculated_checksum = orig_bytes[0..orig_bytes.len() - bytes.len()]
228        .iter()
229        .fold(0, |acc: u8, x| acc.wrapping_add(*x));
230
231    let bytes = deserialize_tag(bytes, b"10=")?;
232    let (bytes, checksum) = deserialize_checksum(bytes)?;
233    if calculated_checksum != checksum {
234        return Err(RawMessageError::InvalidChecksum);
235    }
236    Ok((
237        bytes,
238        RawMessage {
239            begin_string,
240            body,
241            checksum,
242        },
243    ))
244}
245
246// TODO:
247// enum GarbledReason
248
249#[derive(Debug)]
250pub struct Deserializer<'de> {
251    raw_message: RawMessage<'de>,
252    buf: &'de [u8],
253    msg_type: Option<std::ops::Range<usize>>,
254    seq_num: Option<SeqNum>,
255    current_tag: Option<TagNum>,
256    // Used to put tag back to deserializer, when switching to deserialization
257    // another message section.
258    tmp_tag: Option<TagNum>,
259}
260
261impl Deserializer<'_> {
262    pub fn from_raw_message(raw_message: RawMessage) -> Deserializer {
263        let buf = raw_message.body;
264        Deserializer {
265            raw_message,
266            buf,
267            msg_type: None,
268            seq_num: None,
269            current_tag: None,
270            tmp_tag: None,
271        }
272    }
273
274    pub fn begin_string(&self) -> FixString {
275        self.raw_message.begin_string.to_owned()
276    }
277
278    pub fn body_length(&self) -> Length {
279        self.raw_message.body.len() as Length
280    }
281
282    pub fn check_sum(&self) -> FixString {
283        FixString::from_ascii_lossy(format!("{:03}", self.raw_message.checksum).into_bytes())
284    }
285
286    pub fn set_seq_num(&mut self, seq_num: SeqNum) {
287        debug_assert!(self.seq_num.is_none());
288
289        self.seq_num = Some(seq_num);
290    }
291
292    // This may fail when RawData or XmlData fields (or other binary fields)
293    // are located before MsgSeqNum and has value `34=` inside
294    fn try_find_msg_seq_num(&mut self) -> Result<SeqNum, DeserializeError> {
295        let seq_num_tag = b"34=";
296
297        let start_index = self
298            .buf
299            .windows(seq_num_tag.len())
300            .position(|window| window == seq_num_tag)
301            .ok_or(DeserializeError::Logout)?;
302        self.buf = &self.buf[start_index + seq_num_tag.len()..];
303
304        self.deserialize_seq_num()
305    }
306
307    pub fn reject(&mut self, tag: Option<TagNum>, reason: ParseRejectReason) -> DeserializeError {
308        let seq_num = if let Some(seq_num) = self.seq_num {
309            seq_num
310        } else {
311            match self.try_find_msg_seq_num() {
312                Ok(seq_num) => seq_num,
313                Err(err) => return err,
314            }
315        };
316
317        DeserializeError::Reject {
318            msg_type: self.msg_type.clone().map(|msg_type| {
319                FixString::from_ascii_lossy(self.raw_message.body[msg_type].to_vec())
320            }),
321            seq_num,
322            tag,
323            reason,
324        }
325    }
326
327    pub fn repeating_group_fields_out_of_order(
328        &mut self,
329        expected_tags: &[u16],
330        processed_tags: &[u16],
331        current_tag: u16,
332    ) -> DeserializeError {
333        let mut current_tag_found = false;
334        'outer: for processed_tag in processed_tags {
335            for expected_tag in expected_tags {
336                if expected_tag == processed_tag {
337                    if current_tag_found {
338                        return self.reject(
339                            Some(*processed_tag),
340                            ParseRejectReason::RepeatingGroupFieldsOutOfOrder,
341                        );
342                    } else {
343                        continue 'outer;
344                    }
345                } else if *expected_tag == current_tag {
346                    current_tag_found = true;
347                }
348            }
349        }
350        // This should never happen
351        debug_assert!(false);
352        self.reject(None, ParseRejectReason::RepeatingGroupFieldsOutOfOrder)
353    }
354
355    pub fn put_tag(&mut self, tag: TagNum) {
356        self.tmp_tag = Some(tag);
357    }
358
359    pub fn range_to_fixstr(&self, range: std::ops::Range<usize>) -> &FixStr {
360        unsafe { FixStr::from_ascii_unchecked(&self.raw_message.body[range]) }
361    }
362
363    /// Deserialize MsgType
364    pub fn deserialize_msg_type(&mut self) -> Result<std::ops::Range<usize>, DeserializeError> {
365        let raw_message_pointer = self.raw_message.body.as_ptr();
366
367        let msg_type_range = {
368            let Ok(deser_str) = self.deserialize_str() else {
369                return Err(self.reject(Some(35), ParseRejectReason::InvalidMsgtype));
370            };
371            let msg_type_pointer = deser_str.as_bytes().as_ptr();
372            let msg_type_start_index =
373                unsafe { msg_type_pointer.offset_from(raw_message_pointer) } as usize;
374            let msg_type_len = deser_str.len();
375            msg_type_start_index..(msg_type_start_index + msg_type_len)
376        };
377
378        self.msg_type = Some(msg_type_range.clone());
379        Ok(msg_type_range)
380    }
381
382    /// Deserialize sequence of character digits without commas or decimals.
383    /// Value must be positive and may not contain leading zeros.
384    pub fn deserialize_tag_num(&mut self) -> Result<Option<TagNum>, DeserializeError> {
385        if self.tmp_tag.is_some() {
386            return Ok(self.tmp_tag.take());
387        }
388
389        match self.buf {
390            // End of stream
391            [] => return Ok(None),
392            // Leading zero
393            [b'0' | b'=', ..] => return Err(self.reject(None, ParseRejectReason::InvalidTagNumber)),
394            _ => {}
395        }
396
397        let mut value: TagNum = 0;
398        for i in 0..self.buf.len() {
399            // SAFETY: i is between 0 and self.buf.len()
400            match unsafe { self.buf.get_unchecked(i) } {
401                n @ b'0'..=b'9' => {
402                    value = value
403                        .checked_mul(10)
404                        .and_then(|v| v.checked_add((n - b'0') as TagNum))
405                        // Integer overflow
406                        .ok_or_else(|| self.reject(None, ParseRejectReason::InvalidTagNumber))?;
407                }
408                b'=' => {
409                    if value == 0 {
410                        return Err(
411                            self.reject(self.current_tag, ParseRejectReason::InvalidTagNumber)
412                        );
413                    } else {
414                        self.current_tag = Some(value);
415                        self.buf = &self.buf[i + 1..];
416                        return Ok(Some(value));
417                    }
418                }
419                // Unexpected value
420                _ => return Err(self.reject(None, ParseRejectReason::InvalidTagNumber)),
421            }
422        }
423
424        // End of stream
425        Err(DeserializeError::GarbledMessage(format!(
426            "no more data to parse tag {:?}",
427            self.current_tag
428        )))
429    }
430
431    /// Deserialize sequence of character digits without commas or decimals
432    /// and optional sign character (characters “-” and “0” – “9” ).
433    /// The sign character utilizes one octet (i.e., positive int is “99999”
434    /// while negative int is “-99999”).
435    ///
436    /// Note that int values may contain leading zeros (e.g. “00023” = “23”).
437    pub fn deserialize_int(&mut self) -> Result<Int, DeserializeError> {
438        let negative = match self.buf {
439            // MSG Garbled
440            [] => {
441                return Err(DeserializeError::GarbledMessage(format!(
442                    "no more data to parse tag {:?}",
443                    self.current_tag
444                )));
445            }
446            [b'\x01', ..] => {
447                return Err(self.reject(
448                    self.current_tag,
449                    ParseRejectReason::TagSpecifiedWithoutAValue,
450                ));
451            }
452            [b'-', b'\x01', ..] => {
453                return Err(self.reject(
454                    self.current_tag,
455                    ParseRejectReason::IncorrectDataFormatForValue,
456                ));
457            }
458            [b'-', buf @ ..] => {
459                self.buf = buf;
460                true
461            }
462            _ => false,
463        };
464
465        let mut value: Int = 0;
466        for i in 0..self.buf.len() {
467            // SAFETY: i is between 0 and self.buf.len()
468            match unsafe { self.buf.get_unchecked(i) } {
469                n @ b'0'..=b'9' => {
470                    value = value
471                        .checked_mul(10)
472                        .and_then(|v| v.checked_add((n - b'0') as Int))
473                        .ok_or_else(|| {
474                            self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect)
475                        })?;
476                }
477                b'\x01' => {
478                    self.buf = &self.buf[i + 1..];
479                    return Ok(if negative { -value } else { value });
480                }
481                _ => {
482                    return Err(self.reject(
483                        self.current_tag,
484                        ParseRejectReason::IncorrectDataFormatForValue,
485                    ));
486                }
487            }
488        }
489
490        Err(DeserializeError::GarbledMessage(format!(
491            "no more data to parse tag {:?}",
492            self.current_tag
493        )))
494    }
495
496    /// Deserialize sequence of character digits without commas or decimals.
497    /// Value must be positive.
498    pub fn deserialize_seq_num(&mut self) -> Result<SeqNum, DeserializeError> {
499        match self.buf {
500            // No more data, MSG Garbled
501            [] => {
502                return Err(DeserializeError::GarbledMessage(format!(
503                    "no more data to parse tag {:?}",
504                    self.current_tag
505                )));
506            }
507            [b'\x01', ..] => return Err(DeserializeError::Logout),
508            _ => {}
509        }
510
511        let mut value: SeqNum = 0;
512        for i in 0..self.buf.len() {
513            // SAFETY: i is between 0 and buf.len()
514            match unsafe { self.buf.get_unchecked(i) } {
515                n @ b'0'..=b'9' => {
516                    value = value
517                        .checked_mul(10)
518                        .and_then(|v| v.checked_add((n - b'0') as SeqNum))
519                        .ok_or(DeserializeError::Logout)?;
520                }
521                b'\x01' => {
522                    self.buf = &self.buf[i + 1..];
523                    // XXX: Accept `0` as EndSeqNum<16> uses `0` as infinite
524                    return Ok(value);
525                }
526                _ => return Err(DeserializeError::Logout),
527            }
528        }
529
530        Err(DeserializeError::GarbledMessage(format!(
531            "no more data to parse tag {:?}",
532            self.current_tag
533        )))
534    }
535
536    /// Deserialize sequence of character digits without commas or decimals.
537    /// Value must be positive.
538    pub fn deserialize_num_in_group(&mut self) -> Result<NumInGroup, DeserializeError> {
539        match self.buf {
540            // MSG Garbled
541            [] => {
542                return Err(DeserializeError::GarbledMessage(format!(
543                    "no more data to parse tag {:?}",
544                    self.current_tag
545                )));
546            }
547            [b'\x01', ..] => {
548                return Err(self.reject(
549                    self.current_tag,
550                    ParseRejectReason::TagSpecifiedWithoutAValue,
551                ));
552            }
553            _ => {}
554        }
555
556        let mut value: NumInGroup = 0;
557        for i in 0..self.buf.len() {
558            // SAFETY: i is between 0 and buf.len()
559            match unsafe { self.buf.get_unchecked(i) } {
560                n @ b'0'..=b'9' => {
561                    value = value
562                        .checked_mul(10)
563                        .and_then(|v| v.checked_add((n - b'0') as NumInGroup))
564                        .ok_or_else(|| {
565                            self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect)
566                        })?;
567                }
568                b'\x01' => {
569                    if value == 0 {
570                        return Err(
571                            self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect)
572                        );
573                    } else {
574                        self.buf = &self.buf[i + 1..];
575                        return Ok(value);
576                    }
577                }
578                _ => {
579                    return Err(self.reject(
580                        self.current_tag,
581                        ParseRejectReason::IncorrectDataFormatForValue,
582                    ));
583                }
584            }
585        }
586
587        Err(DeserializeError::GarbledMessage(format!(
588            "no more data to parse tag {:?}",
589            self.current_tag
590        )))
591    }
592
593    /// Deserialize sequence of character digits without commas or decimals
594    /// (values 1 to 31).
595    pub fn deserialize_day_of_month(&mut self) -> Result<DayOfMonth, DeserializeError> {
596        match self.buf {
597            // MSG Garbled
598            [] => {
599                return Err(DeserializeError::GarbledMessage(format!(
600                    "no more data to parse tag {:?}",
601                    self.current_tag
602                )));
603            }
604            [b'\x01', ..] => {
605                return Err(self.reject(
606                    self.current_tag,
607                    ParseRejectReason::TagSpecifiedWithoutAValue,
608                ));
609            }
610            [b'0', ..] => {
611                return Err(self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect));
612            }
613            _ => {}
614        };
615
616        let mut value: NumInGroup = 0;
617        for i in 0..self.buf.len() {
618            // SAFETY: i is between 0 and buf.len()
619            match unsafe { self.buf.get_unchecked(i) } {
620                n @ b'0'..=b'9' => {
621                    value = value
622                        .checked_mul(10)
623                        .and_then(|v| v.checked_add((n - b'0') as NumInGroup))
624                        .ok_or_else(|| {
625                            self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect)
626                        })?;
627                }
628                b'\x01' => {
629                    self.buf = &self.buf[i + 1..];
630                    break;
631                }
632                _ => {
633                    return Err(self.reject(
634                        self.current_tag,
635                        ParseRejectReason::IncorrectDataFormatForValue,
636                    ));
637                }
638            }
639        }
640
641        match value {
642            1..=31 => Ok(value),
643            _ => Err(self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect)),
644        }
645    }
646
647    /// Deserialize sequence of character digits with optional decimal point
648    /// and sign character (characters “-”, “0” – “9” and “.”);
649    /// the absence of the decimal point within the string will be interpreted
650    /// as the float representation of an integer value. Note that float values
651    /// may contain leading zeros (e.g. “00023.23” = “23.23”) and may contain
652    /// or omit trailing zeros after the decimal point
653    /// (e.g. “23.0” = “23.0000” = “23” = “23.”).
654    ///
655    /// All float fields must accommodate up to fifteen significant digits.
656    /// The number of decimal places used should be a factor of business/market
657    /// needs and mutual agreement between counterparties.
658    pub fn deserialize_float(&mut self) -> Result<Float, DeserializeError> {
659        let (negative, buf) = match self.buf {
660            [] => {
661                return Err(DeserializeError::GarbledMessage(format!(
662                    "no more data to parse tag {:?}",
663                    self.current_tag
664                )));
665            }
666            [b'\x01', ..] => {
667                return Err(self.reject(
668                    self.current_tag,
669                    ParseRejectReason::TagSpecifiedWithoutAValue,
670                ));
671            }
672            [b'-', b'\x01', ..] => {
673                return Err(self.reject(
674                    self.current_tag,
675                    ParseRejectReason::IncorrectDataFormatForValue,
676                ));
677            }
678            [b'-', buf @ ..] => (true, buf),
679            _ => (false, self.buf),
680        };
681
682        let mut num: i64 = 0;
683        let mut scale = None;
684        for i in 0..buf.len() {
685            // SAFETY: i is between 0 and buf.len()
686            match unsafe { buf.get_unchecked(i) } {
687                n @ b'0'..=b'9' => {
688                    num = num
689                        .checked_mul(10)
690                        .and_then(|v| v.checked_add((n - b'0') as i64))
691                        .ok_or_else(|| {
692                            self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect)
693                        })?;
694                    if let Some(scale) = scale.as_mut() {
695                        *scale += 1;
696                    }
697                }
698                b'.' => {
699                    if scale.is_some() {
700                        return Err(self.reject(
701                            self.current_tag,
702                            ParseRejectReason::IncorrectDataFormatForValue,
703                        ));
704                    }
705                    scale = Some(0);
706                }
707                b'\x01' => {
708                    self.buf = &self.buf[i + 1..];
709                    let scale = scale.unwrap_or(0);
710                    // TODO: Limit scale (28 or more panics!)
711                    return Ok(Decimal::new(if negative { -num } else { num }, scale));
712                }
713                _ => {
714                    return Err(self.reject(
715                        self.current_tag,
716                        ParseRejectReason::IncorrectDataFormatForValue,
717                    ));
718                }
719            }
720        }
721
722        Err(DeserializeError::GarbledMessage(format!(
723            "no more data to parse tag {:?}",
724            self.current_tag
725        )))
726    }
727
728    #[inline(always)]
729    pub fn deserialize_qty(&mut self) -> Result<Qty, DeserializeError> {
730        self.deserialize_float()
731    }
732
733    #[inline(always)]
734    pub fn deserialize_price(&mut self) -> Result<Price, DeserializeError> {
735        self.deserialize_float()
736    }
737
738    #[inline(always)]
739    pub fn deserialize_price_offset(&mut self) -> Result<PriceOffset, DeserializeError> {
740        self.deserialize_float()
741    }
742
743    #[inline(always)]
744    pub fn deserialize_amt(&mut self) -> Result<Amt, DeserializeError> {
745        self.deserialize_float()
746    }
747
748    #[inline(always)]
749    pub fn deserialize_percentage(&mut self) -> Result<Percentage, DeserializeError> {
750        self.deserialize_float()
751    }
752
753    pub fn deserialize_boolean(&mut self) -> Result<Boolean, DeserializeError> {
754        match self.buf {
755            // Empty or missing separator at the end
756            [] => Err(DeserializeError::GarbledMessage(format!(
757                "no more data to parse tag {:?}",
758                self.current_tag
759            ))),
760            [b'Y'] | [b'N'] => Err(DeserializeError::GarbledMessage(format!(
761                "missing tag ({:?}) separator",
762                self.current_tag
763            ))),
764            [b'\x01', ..] => Err(self.reject(
765                self.current_tag,
766                ParseRejectReason::TagSpecifiedWithoutAValue,
767            )),
768            [b'Y', b'\x01', buf @ ..] => {
769                self.buf = buf;
770                Ok(true)
771            }
772            [b'N', b'\x01', buf @ ..] => {
773                self.buf = buf;
774                Ok(false)
775            }
776            _ => Err(self.reject(
777                self.current_tag,
778                ParseRejectReason::IncorrectDataFormatForValue,
779            )),
780        }
781    }
782
783    /// Deserialize any ASCII character except control characters.
784    // TODO: [Feature]: Deserialize any ISO/IEC 8859-1 (Latin-1) character except control characters.
785    pub fn deserialize_char(&mut self) -> Result<Char, DeserializeError> {
786        match self.buf {
787            [] => Err(DeserializeError::GarbledMessage(format!(
788                "no more data to parse tag {:?}",
789                self.current_tag
790            ))),
791            [b'\x01', ..] => Err(self.reject(
792                self.current_tag,
793                ParseRejectReason::TagSpecifiedWithoutAValue,
794            )),
795            // ASCII controll characters range + unused range
796            [0x00..=0x1f | 0x80..=0xff, ..] => {
797                Err(self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect))
798            }
799            [n, b'\x01', buf @ ..] => {
800                self.buf = buf;
801                Ok(*n)
802            }
803            // Missing separator at the end
804            [_, byte] if *byte != b'\x01' => Err(DeserializeError::GarbledMessage(
805                "missing tag spearator".into(),
806            )),
807            _ => Err(self.reject(
808                self.current_tag,
809                ParseRejectReason::IncorrectDataFormatForValue,
810            )),
811        }
812    }
813
814    /// Deserialize string containing one or more space-delimited single
815    /// character values, e.g. “2 A F”.
816    pub fn deserialize_multiple_char_value(
817        &mut self,
818    ) -> Result<MultipleCharValue, DeserializeError> {
819        match self.buf {
820            [] => {
821                return Err(DeserializeError::GarbledMessage(format!(
822                    "no more data to parse tag {:?}",
823                    self.current_tag
824                )));
825            }
826            [b'\x01', ..] => {
827                return Err(self.reject(
828                    self.current_tag,
829                    ParseRejectReason::TagSpecifiedWithoutAValue,
830                ));
831            }
832            _ => {}
833        }
834
835        for i in 0..self.buf.len() {
836            // SAFETY: i is between 0 and input.len()
837            if let b'\x01' = unsafe { self.buf.get_unchecked(i) } {
838                let data = &self.buf[0..i];
839                // Skip data and separator
840                self.buf = &self.buf[i + 1..];
841                let mut result = MultipleCharValue::with_capacity(data.len() / 2 + 1);
842                for chunk in data.chunks(2) {
843                    match chunk {
844                        [b' '] | [b' ', _] => {
845                            return Err(self.reject(
846                                self.current_tag,
847                                ParseRejectReason::IncorrectDataFormatForValue,
848                            ));
849                        }
850                        // Latin-1 controll characters ranges
851                        // [0x00..=0x1f] | [0x80..=0x9f] | [0x00..=0x1f, _] | [0x80..=0x9f, _] => {
852
853                        // ASCII controll character range + unused range
854                        [0x00..=0x1f] | [0x80..=0xff] => {
855                            return Err(
856                                self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect)
857                            );
858                        }
859                        [n] | [n, b' '] => result.push(*n),
860                        _ => {
861                            return Err(self.reject(
862                                self.current_tag,
863                                ParseRejectReason::IncorrectDataFormatForValue,
864                            ));
865                        }
866                    }
867                }
868                return Ok(result);
869            }
870        }
871
872        Err(DeserializeError::GarbledMessage(format!(
873            "no more data to parse tag {:?}",
874            self.current_tag
875        )))
876    }
877
878    /// Deserialize alphanumeric free-format strings can include any character
879    /// except control characters.
880    pub fn deserialize_str(&mut self) -> Result<&FixStr, DeserializeError> {
881        match deserialize_str(self.buf) {
882            Ok((leftover, fix_str)) => {
883                self.buf = leftover;
884                Ok(fix_str)
885            }
886            Err(DeserializeErrorInternal::Incomplete) => Err(DeserializeError::GarbledMessage(
887                format!("no more data to parse tag {:?}", self.current_tag),
888            )),
889            Err(DeserializeErrorInternal::Error(reason)) => {
890                Err(self.reject(self.current_tag, reason))
891            }
892        }
893    }
894
895    /// Deserialize alphanumeric free-format strings can include any character
896    /// except control characters.
897    #[inline(always)]
898    pub fn deserialize_string(&mut self) -> Result<FixString, DeserializeError> {
899        self.deserialize_str().map(FixString::from)
900    }
901
902    /// Deserialize string containing one or more space-delimited multiple
903    /// character values, e.g. “AV AN A”.
904    pub fn deserialize_multiple_string_value(
905        &mut self,
906    ) -> Result<MultipleStringValue, DeserializeError> {
907        match self.buf {
908            [] => {
909                return Err(DeserializeError::GarbledMessage(format!(
910                    "no more data to parse tag {:?}",
911                    self.current_tag
912                )));
913            }
914            [b'\x01', ..] => {
915                return Err(self.reject(
916                    self.current_tag,
917                    ParseRejectReason::TagSpecifiedWithoutAValue,
918                ));
919            }
920            _ => {}
921        }
922
923        for i in 0..self.buf.len() {
924            // SAFETY: i is between 0 and input.len()
925            if let b'\x01' = unsafe { self.buf.get_unchecked(i) } {
926                let data = &self.buf[0..i];
927                // Skip data and separator
928                self.buf = &self.buf[i + 1..];
929                const DEFAULT_CAPACITY: usize = 4;
930                let mut result = MultipleStringValue::with_capacity(DEFAULT_CAPACITY);
931                for part in data.split(|p| *p == b' ') {
932                    let mut sub_result = Vec::with_capacity(part.len());
933                    for byte in part {
934                        match byte {
935                            // ASCII controll characters range
936                            0x00..=0x1f | 0x80..=0xff => {
937                                return Err(self.reject(
938                                    self.current_tag,
939                                    ParseRejectReason::ValueIsIncorrect,
940                                ));
941                            }
942                            n => sub_result.push(*n),
943                        }
944                    }
945                    // SAFETY: string validity checked above
946                    result.push(unsafe { FixString::from_ascii_unchecked(sub_result) });
947                }
948                return Ok(result);
949            }
950        }
951
952        Err(DeserializeError::GarbledMessage(format!(
953            "no more data to parse tag {:?}",
954            self.current_tag
955        )))
956    }
957
958    /// Deserialize ISO 3166-1:2013 Codes for the representation of names of
959    /// countries and their subdivision (2-character code).
960    pub fn deserialize_country(&mut self) -> Result<Country, DeserializeError> {
961        match self.buf {
962            [] => Err(DeserializeError::GarbledMessage(format!(
963                "no more data to parse tag {:?}",
964                self.current_tag
965            ))),
966            [b'\x01', ..] => Err(self.reject(
967                self.current_tag,
968                ParseRejectReason::TagSpecifiedWithoutAValue,
969            )),
970            [_, b'\x01', ..] => Err(self.reject(
971                self.current_tag,
972                ParseRejectReason::IncorrectDataFormatForValue,
973            )),
974            bytes @ [_, _, b'\x01', buf @ ..] => {
975                self.buf = buf;
976                Country::from_bytes(&bytes[0..2]).ok_or_else(|| {
977                    self.reject(
978                        self.current_tag,
979                        ParseRejectReason::IncorrectDataFormatForValue,
980                    )
981                })
982            }
983            // TODO: add the same for [a, b] and [a] cases
984            // TODO: and do it in every deserialize_* function without loop
985            // TODO: or maybe better just check if len < expected message size
986            &[a, b, c] if a != b'\x01' && b != b'\x01' && c != b'\x01' => {
987                Err(DeserializeError::GarbledMessage(format!(
988                    "missing tag ({:?}) separator",
989                    self.current_tag
990                )))
991            }
992            _ => Err(self.reject(
993                self.current_tag,
994                ParseRejectReason::IncorrectDataFormatForValue,
995            )),
996        }
997    }
998
999    /// Deserialize ISO 4217:2015 Codes for the representation of currencies
1000    /// and funds (3-character code).
1001    pub fn deserialize_currency(&mut self) -> Result<Currency, DeserializeError> {
1002        match self.buf {
1003            [] => Err(DeserializeError::GarbledMessage(format!(
1004                "no more data to parse tag {:?}",
1005                self.current_tag
1006            ))),
1007            [b'\x01', ..] => Err(self.reject(
1008                self.current_tag,
1009                ParseRejectReason::TagSpecifiedWithoutAValue,
1010            )),
1011            bytes @ [_, _, _, b'\x01', buf @ ..] => {
1012                self.buf = buf;
1013                Currency::from_bytes(&bytes[0..3]).ok_or_else(|| {
1014                    self.reject(
1015                        self.current_tag,
1016                        ParseRejectReason::IncorrectDataFormatForValue,
1017                    )
1018                })
1019            }
1020            _ => Err(self.reject(
1021                self.current_tag,
1022                ParseRejectReason::IncorrectDataFormatForValue,
1023            )),
1024        }
1025    }
1026
1027    /// Deserialize ISO 10383:2012 Securities and related financial instruments
1028    /// – Codes for exchanges and market identification (MIC)
1029    /// (4-character code).
1030    pub fn deserialize_exchange(&mut self) -> Result<Exchange, DeserializeError> {
1031        match self.buf {
1032            [] => Err(DeserializeError::GarbledMessage(format!(
1033                "no more data to parse tag {:?}",
1034                self.current_tag
1035            ))),
1036            [b'\x01', ..] => Err(self.reject(
1037                self.current_tag,
1038                ParseRejectReason::TagSpecifiedWithoutAValue,
1039            )),
1040            [a, b, c, d, b'\x01', buf @ ..] => {
1041                self.buf = buf;
1042                // TODO
1043                Ok([*a, *b, *c, *d])
1044            }
1045            _ => Err(self.reject(
1046                self.current_tag,
1047                ParseRejectReason::IncorrectDataFormatForValue,
1048            )),
1049        }
1050    }
1051
1052    /// Deserialize string representing month of a year.
1053    /// An optional day of the month can be appended or an optional week code.
1054    ///
1055    /// # Valid formats:
1056    /// - `YYYYMM
1057    /// - `YYYYMMDD
1058    /// - `YYYYMMWW
1059    ///
1060    /// # Valid values:
1061    /// - YYYY = 0000-9999
1062    /// - MM = 01-12
1063    /// - DD = 01-31
1064    /// - WW = w1, w2, w3, w4, w5
1065    pub fn deserialize_month_year(&mut self) -> Result<MonthYear, DeserializeError> {
1066        match self.buf {
1067            [] => Err(DeserializeError::GarbledMessage(format!(
1068                "no more data to parse tag {:?}",
1069                self.current_tag
1070            ))),
1071            [b'\x01', ..] => Err(self.reject(
1072                self.current_tag,
1073                ParseRejectReason::TagSpecifiedWithoutAValue,
1074            )),
1075            [a, b, c, d, e, f, g, h, b'\x01', buf @ ..] => {
1076                self.buf = buf;
1077                // TODO
1078                Ok([*a, *b, *c, *d, *e, *f, *g, *h].into())
1079            }
1080            _ => Err(self.reject(
1081                self.current_tag,
1082                ParseRejectReason::IncorrectDataFormatForValue,
1083            )),
1084        }
1085    }
1086
1087    /// Deserialize ISO 639-1:2002 Codes for the representation of names
1088    /// of languages (2-character code).
1089    pub fn deserialize_language(&mut self) -> Result<Language, DeserializeError> {
1090        match self.buf {
1091            [] => Err(DeserializeError::GarbledMessage(format!(
1092                "no more data to parse tag {:?}",
1093                self.current_tag
1094            ))),
1095            [b'\x01', ..] => Err(self.reject(
1096                self.current_tag,
1097                ParseRejectReason::TagSpecifiedWithoutAValue,
1098            )),
1099            [a, b, b'\x01', buf @ ..] => {
1100                self.buf = buf;
1101                Ok([*a, *b])
1102            }
1103            _ => Err(self.reject(
1104                self.current_tag,
1105                ParseRejectReason::IncorrectDataFormatForValue,
1106            )),
1107        }
1108    }
1109
1110    // Helper for UTC timestamp deserialization.
1111    fn deserialize_fraction_of_second(&mut self) -> Result<(u32, u8), DeserializeError> {
1112        match self.buf {
1113            [] => {
1114                return Err(DeserializeError::GarbledMessage(format!(
1115                    "no more data to parse tag {:?}",
1116                    self.current_tag
1117                )));
1118            }
1119            [b'\x01', ..] => {
1120                self.buf = &self.buf[1..];
1121                return Ok((0, 0));
1122            }
1123            // Do nothing here, fraction of second will be deserializede below
1124            [b'.', ..] => self.buf = &self.buf[1..],
1125            _ => {
1126                return Err(self.reject(
1127                    self.current_tag,
1128                    ParseRejectReason::IncorrectDataFormatForValue,
1129                ));
1130            }
1131        }
1132
1133        let mut fraction_of_second: u64 = 0;
1134        for i in 0..self.buf.len() {
1135            // SAFETY: i is between 0 and buf.len()
1136            match unsafe { self.buf.get_unchecked(i) } {
1137                n @ b'0'..=b'9' => {
1138                    fraction_of_second = fraction_of_second
1139                        .checked_mul(10)
1140                        .and_then(|v| v.checked_add((n - b'0') as u64))
1141                        .ok_or_else(|| {
1142                            self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect)
1143                        })?;
1144                }
1145                b'\x01' => {
1146                    self.buf = &self.buf[i + 1..];
1147                    let (multiplier, divider) = match i {
1148                        3 => (1_000_000, 1),
1149                        6 => (1_000, 1),
1150                        9 => (1, 1),
1151                        // XXX: Types from `chrono` crate can't hold
1152                        //      time at picosecond resolution
1153                        12 => (1, 1_000),
1154                        _ => {
1155                            return Err(self.reject(
1156                                self.current_tag,
1157                                ParseRejectReason::IncorrectDataFormatForValue,
1158                            ));
1159                        }
1160                    };
1161                    let adjusted_fraction_of_second = (fraction_of_second * multiplier / divider)
1162                        .try_into()
1163                        .map_err(|_| {
1164                            self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect)
1165                        });
1166                    match adjusted_fraction_of_second {
1167                        Ok(adjusted_fraction_of_second) => {
1168                            return Ok((adjusted_fraction_of_second, i as u8));
1169                        }
1170                        Err(err) => return Err(err),
1171                    }
1172                }
1173                _ => {
1174                    return Err(self.reject(
1175                        self.current_tag,
1176                        ParseRejectReason::IncorrectDataFormatForValue,
1177                    ));
1178                }
1179            }
1180        }
1181
1182        Err(self.reject(
1183            self.current_tag,
1184            ParseRejectReason::IncorrectDataFormatForValue,
1185        ))
1186    }
1187
1188    /// Deserialize string representing time/date combination represented
1189    /// in UTC (Universal Time Coordinated) in either YYYYMMDD-HH:MM:SS
1190    /// (whole seconds) or YYYYMMDD-HH:MM:SS.sss* format, colons, dash,
1191    /// and period required.
1192    ///
1193    /// # Valid values:
1194    /// - YYYY = 0000-9999,
1195    /// - MM = 01-12,
1196    /// - DD = 01-31,
1197    /// - HH = 00-23,
1198    /// - MM = 00-59,
1199    /// - SS = 00-60 (60 only if UTC leap second),
1200    /// - sss* fractions of seconds. The fractions of seconds may be empty when
1201    ///   no fractions of seconds are conveyed (in such a case the period
1202    ///   is not conveyed), it may include 3 digits to convey
1203    ///   milliseconds, 6 digits to convey microseconds, 9 digits
1204    ///   to convey nanoseconds, 12 digits to convey picoseconds;
1205    pub fn deserialize_utc_timestamp(&mut self) -> Result<UtcTimestamp, DeserializeError> {
1206        match self.buf {
1207            [] => Err(DeserializeError::GarbledMessage(format!(
1208                "no more data to parse tag {:?}",
1209                self.current_tag
1210            ))),
1211            [b'\x01', ..] => Err(self.reject(
1212                self.current_tag,
1213                ParseRejectReason::TagSpecifiedWithoutAValue,
1214            )),
1215            // Missing separator at the end
1216            [_] => Err(DeserializeError::GarbledMessage(format!(
1217                "missing tag ({:?}) separator",
1218                self.current_tag
1219            ))),
1220            [
1221                // Year
1222                y3 @ b'0'..=b'9',
1223                y2 @ b'0'..=b'9',
1224                y1 @ b'0'..=b'9',
1225                y0 @ b'0'..=b'9',
1226                // Month
1227                m1 @ b'0'..=b'1',
1228                m0 @ b'0'..=b'9',
1229                // Day
1230                d1 @ b'0'..=b'3',
1231                d0 @ b'0'..=b'9',
1232                b'-',
1233                // Hour
1234                h1 @ b'0'..=b'2',
1235                h0 @ b'0'..=b'9',
1236                b':',
1237                // Minute
1238                mm1 @ b'0'..=b'5',
1239                mm0 @ b'0'..=b'9',
1240                b':',
1241                // TODO: leap second!
1242                // Second
1243                s1 @ b'0'..=b'5',
1244                s0 @ b'0'..=b'9',
1245                ..,
1246            ] => {
1247                self.buf = &self.buf[17..];
1248                let year = (y3 - b'0') as i32 * 1000
1249                    + (y2 - b'0') as i32 * 100
1250                    + (y1 - b'0') as i32 * 10
1251                    + (y0 - b'0') as i32;
1252                let month = (m1 - b'0') as u32 * 10 + (m0 - b'0') as u32;
1253                let day = (d1 - b'0') as u32 * 10 + (d0 - b'0') as u32;
1254                let naive_date = NaiveDate::from_ymd_opt(year, month, day).ok_or_else(|| {
1255                    self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect)
1256                })?;
1257                let hour = (h1 - b'0') as u32 * 10 + (h0 - b'0') as u32;
1258                let min = (mm1 - b'0') as u32 * 10 + (mm0 - b'0') as u32;
1259                let sec = (s1 - b'0') as u32 * 10 + (s0 - b'0') as u32;
1260                let (fraction_of_second, precision) = self.deserialize_fraction_of_second()?;
1261                let naive_date_time = naive_date
1262                    .and_hms_nano_opt(hour, min, sec, fraction_of_second)
1263                    .ok_or_else(|| {
1264                        self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect)
1265                    })?;
1266                let timestamp = Utc.from_utc_datetime(&naive_date_time);
1267
1268                match precision {
1269                    0 => Ok(UtcTimestamp::with_secs(timestamp)),
1270                    3 => Ok(UtcTimestamp::with_millis(timestamp)),
1271                    6 => Ok(UtcTimestamp::with_micros(timestamp)),
1272                    9 => Ok(UtcTimestamp::with_nanos(timestamp)),
1273                    // XXX: Types from `chrono` crate can't hold
1274                    //      time at picosecond resolution
1275                    12 => Ok(UtcTimestamp::with_nanos(timestamp)),
1276                    _ => Err(self.reject(
1277                        self.current_tag,
1278                        ParseRejectReason::IncorrectDataFormatForValue,
1279                    )),
1280                }
1281            }
1282            _ => Err(self.reject(
1283                self.current_tag,
1284                ParseRejectReason::IncorrectDataFormatForValue,
1285            )),
1286        }
1287    }
1288
1289    /// Deserialize string representing time-only represented in UTC
1290    /// (Universal Time Coordinated) in either HH:MM:SS (whole seconds)
1291    /// or HH:MM:SS.sss* (milliseconds) format, colons, and period required.
1292    ///
1293    /// This special-purpose field is paired with UTCDateOnly to form a proper
1294    /// UTCTimestamp for bandwidth-sensitive messages.
1295    ///
1296    /// # Valid values:
1297    /// - HH = 00-23,
1298    /// - MM = 00-59,
1299    /// - SS = 00-60 (60 only if UTC leap second),
1300    /// - sss* fractions of seconds. The fractions of seconds may be empty when
1301    ///   no fractions of seconds are conveyed (in such a case the period
1302    ///   is not conveyed), it may include 3 digits to convey
1303    ///   milliseconds, 6 digits to convey microseconds, 9 digits
1304    ///   to convey nanoseconds, 12 digits to convey picoseconds;
1305    ///   // TODO: set precision!
1306    pub fn deserialize_utc_time_only(&mut self) -> Result<UtcTimeOnly, DeserializeError> {
1307        match self.buf {
1308            [] => Err(DeserializeError::GarbledMessage(format!(
1309                "no more data to parse tag {:?}",
1310                self.current_tag
1311            ))),
1312            [b'\x01', ..] => Err(self.reject(
1313                self.current_tag,
1314                ParseRejectReason::TagSpecifiedWithoutAValue,
1315            )),
1316            [
1317                // hours
1318                h1 @ b'0'..=b'2',
1319                h0 @ b'0'..=b'9',
1320                b':',
1321                // minutes
1322                m1 @ b'0'..=b'5',
1323                m0 @ b'0'..=b'9',
1324                b':',
1325                // seconds
1326                s1 @ b'0'..=b'5',
1327                s0 @ b'0'..=b'9',
1328                b':',
1329                ..,
1330            ] => {
1331                let h = (h1 - b'0') * 10 + (h0 - b'0');
1332                let m = (m1 - b'0') * 10 + (m0 - b'0');
1333                let s = (s1 - b'0') * 10 + (s0 - b'0');
1334                self.buf = &self.buf[9..];
1335                let (ns, precision) = self.deserialize_fraction_of_second()?;
1336                let timestamp = NaiveTime::from_hms_nano_opt(h.into(), m.into(), s.into(), ns)
1337                    .ok_or_else(|| {
1338                        self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect)
1339                    });
1340                match timestamp {
1341                    Ok(timestamp) => {
1342                        match precision {
1343                            0 => Ok(UtcTimeOnly::with_secs(timestamp)),
1344                            3 => Ok(UtcTimeOnly::with_millis(timestamp)),
1345                            6 => Ok(UtcTimeOnly::with_micros(timestamp)),
1346                            9 => Ok(UtcTimeOnly::with_nanos(timestamp)),
1347                            // XXX: Types from `chrono` crate can't hold
1348                            //      time at picosecond resolution
1349                            12 => Ok(UtcTimeOnly::with_nanos(timestamp)),
1350                            _ => Err(self.reject(
1351                                self.current_tag,
1352                                ParseRejectReason::IncorrectDataFormatForValue,
1353                            )),
1354                        }
1355                    }
1356                    Err(err) => Err(err),
1357                }
1358            }
1359            // Leap second case
1360            [
1361                h1 @ b'0'..=b'2',
1362                h0 @ b'0'..=b'9',
1363                b':',
1364                m1 @ b'0'..=b'5',
1365                m0 @ b'0'..=b'9',
1366                b':',
1367                b'6',
1368                b'0',
1369                b':',
1370            ] => {
1371                let h = (h1 - b'0') * 10 + (h0 - b'0');
1372                let m = (m1 - b'0') * 10 + (m0 - b'0');
1373                let s = 60;
1374                self.buf = &self.buf[9..];
1375                let (ns, precision) = self.deserialize_fraction_of_second()?;
1376                let timestamp =
1377                    NaiveTime::from_hms_nano_opt(h.into(), m.into(), s, ns).ok_or_else(|| {
1378                        self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect)
1379                    });
1380                match timestamp {
1381                    Ok(timestamp) => {
1382                        match precision {
1383                            0 => Ok(UtcTimeOnly::with_secs(timestamp)),
1384                            3 => Ok(UtcTimeOnly::with_millis(timestamp)),
1385                            6 => Ok(UtcTimeOnly::with_micros(timestamp)),
1386                            9 => Ok(UtcTimeOnly::with_nanos(timestamp)),
1387                            // XXX: Types from `chrono` crate can't hold
1388                            //      time at picosecond resolution
1389                            12 => Ok(UtcTimeOnly::with_nanos(timestamp)),
1390                            _ => Err(self.reject(
1391                                self.current_tag,
1392                                ParseRejectReason::IncorrectDataFormatForValue,
1393                            )),
1394                        }
1395                    }
1396                    Err(err) => Err(err),
1397                }
1398            }
1399            _ => Err(self.reject(
1400                self.current_tag,
1401                ParseRejectReason::IncorrectDataFormatForValue,
1402            )),
1403        }
1404    }
1405
1406    /// Deserialize date represented in UTC (Universal Time Coordinated)
1407    /// in YYYYMMDD format.
1408    ///
1409    /// # Valid values:
1410    /// - YYYY = 0000-9999,
1411    /// - MM = 01-12,
1412    /// - DD = 01-31.
1413    pub fn deserialize_utc_date_only(&mut self) -> Result<UtcDateOnly, DeserializeError> {
1414        match self.buf {
1415            [] => Err(DeserializeError::GarbledMessage(format!(
1416                "no more data to parse tag {:?}",
1417                self.current_tag
1418            ))),
1419            [b'\x01', ..] => Err(self.reject(
1420                self.current_tag,
1421                ParseRejectReason::TagSpecifiedWithoutAValue,
1422            )),
1423            // Missing separator at the end
1424            [_] => Err(DeserializeError::GarbledMessage(format!(
1425                "missing tag ({:?}) separator",
1426                self.current_tag
1427            ))),
1428            [
1429                // Year
1430                y3 @ b'0'..=b'9',
1431                y2 @ b'0'..=b'9',
1432                y1 @ b'0'..=b'9',
1433                y0 @ b'0'..=b'9',
1434                // Month
1435                m1 @ b'0'..=b'1',
1436                m0 @ b'0'..=b'9',
1437                // Day
1438                d1 @ b'0'..=b'3',
1439                d0 @ b'0'..=b'9',
1440                // Separator
1441                b'\x01',
1442            ] => {
1443                let year = (y3 - b'0') as u16 * 1000
1444                    + (y2 - b'0') as u16 * 100
1445                    + (y1 - b'0') as u16 * 10
1446                    + (y0 - b'0') as u16;
1447                let month = (m1 - b'0') * 10 + (m0 - b'0');
1448                let day = (d1 - b'0') * 10 + (d0 - b'0');
1449                self.buf = &self.buf[9..];
1450                UtcDateOnly::from_ymd_opt(year.into(), month.into(), day.into()).ok_or_else(|| {
1451                    self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect)
1452                })
1453            }
1454            _ => Err(self.reject(
1455                self.current_tag,
1456                ParseRejectReason::IncorrectDataFormatForValue,
1457            )),
1458        }
1459    }
1460
1461    /// Deserialize time local to a market center. Used where offset to UTC
1462    /// varies throughout the year and the defining market center is identified
1463    /// in a corresponding field.
1464    ///
1465    /// Format is HH:MM:SS where:
1466    /// - HH = 00-23 hours,
1467    /// - MM = 00-59 minutes,
1468    /// - SS = 00-59 seconds.
1469    ///
1470    /// In general only the hour token is non-zero.
1471    pub fn deserialize_local_mkt_time(&mut self) -> Result<LocalMktTime, DeserializeError> {
1472        match self.buf {
1473            [] => Err(DeserializeError::GarbledMessage(format!(
1474                "no more data to parse tag {:?}",
1475                self.current_tag
1476            ))),
1477            [b'\x01', ..] => Err(self.reject(
1478                self.current_tag,
1479                ParseRejectReason::TagSpecifiedWithoutAValue,
1480            )),
1481            // Missing separator at the end
1482            [_] => Err(DeserializeError::GarbledMessage(format!(
1483                "missing tag ({:?}) separator",
1484                self.current_tag
1485            ))),
1486
1487            [
1488                // Hour
1489                h1 @ b'0'..=b'2',
1490                h0 @ b'0'..=b'9',
1491                b':',
1492                // Minute
1493                m1 @ b'0'..=b'5',
1494                m0 @ b'0'..=b'0',
1495                b':',
1496                // Second
1497                s1 @ b'0'..=b'5',
1498                s0 @ b'0'..=b'9',
1499                b'\x01',
1500                ..,
1501            ] => {
1502                let hour = (h1 - b'0') as u32 * 10 + (h0 - b'0') as u32;
1503                let minute = (m1 - b'0') as u32 * 10 + (m0 - b'0') as u32;
1504                let second = (s1 - b'0') as u32 * 10 + (s0 - b'0') as u32;
1505                self.buf = &self.buf[8..];
1506                LocalMktTime::from_hms_opt(hour, minute, second).ok_or_else(|| {
1507                    self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect)
1508                })
1509            }
1510            _ => Err(self.reject(
1511                self.current_tag,
1512                ParseRejectReason::IncorrectDataFormatForValue,
1513            )),
1514        }
1515    }
1516
1517    /// Deserialize date of local market (as opposed to UTC) in YYYYMMDD
1518    /// format.
1519    ///
1520    /// # Valid values:
1521    /// - YYYY = 0000-9999,
1522    /// - MM = 01-12,
1523    /// - DD = 01-31.
1524    pub fn deserialize_local_mkt_date(&mut self) -> Result<LocalMktDate, DeserializeError> {
1525        match self.buf {
1526            [] => Err(DeserializeError::GarbledMessage(format!(
1527                "no more data to parse tag {:?}",
1528                self.current_tag
1529            ))),
1530            [b'\x01', ..] => Err(self.reject(
1531                self.current_tag,
1532                ParseRejectReason::TagSpecifiedWithoutAValue,
1533            )),
1534            // Missing separator at the end
1535            [_] => Err(DeserializeError::GarbledMessage(format!(
1536                "missing tag ({:?}) separator",
1537                self.current_tag
1538            ))),
1539            [
1540                // Year
1541                y3 @ b'0'..=b'9',
1542                y2 @ b'0'..=b'9',
1543                y1 @ b'0'..=b'9',
1544                y0 @ b'0'..=b'9',
1545                // Month
1546                m1 @ b'0'..=b'1',
1547                m0 @ b'0'..=b'9',
1548                // Day
1549                d1 @ b'0'..=b'3',
1550                d0 @ b'0'..=b'9',
1551                // Separator
1552                b'\x01',
1553                ..,
1554            ] => {
1555                let year = (y3 - b'0') as u16 * 1000
1556                    + (y2 - b'0') as u16 * 100
1557                    + (y1 - b'0') as u16 * 10
1558                    + (y0 - b'0') as u16;
1559                let month = (m1 - b'0') * 10 + (m0 - b'0');
1560                let day = (d1 - b'0') * 10 + (d0 - b'0');
1561                self.buf = &self.buf[9..];
1562                LocalMktDate::from_ymd_opt(year.into(), month.into(), day.into()).ok_or_else(|| {
1563                    self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect)
1564                })
1565            }
1566            _ => Err(self.reject(
1567                self.current_tag,
1568                ParseRejectReason::IncorrectDataFormatForValue,
1569            )),
1570        }
1571    }
1572
1573    /// Deserialize string representing a time/date combination representing
1574    /// local time with an offset to UTC to allow identification of local time
1575    /// and time zone offset of that time.
1576    ///
1577    /// The representation is based on ISO 8601.
1578    ///
1579    /// Format is `YYYYMMDD-HH:MM:SS.sss*[Z | [ + | – hh[:mm]]]` where:
1580    /// - YYYY = 0000 to 9999,
1581    /// - MM = 01-12,
1582    /// - DD = 01-31 HH = 00-23 hours,
1583    /// - MM = 00-59 minutes,
1584    /// - SS = 00-59 seconds,
1585    /// - hh = 01-12 offset hours,
1586    /// - mm = 00-59 offset minutes,
1587    /// - sss* fractions of seconds. The fractions of seconds may be empty when
1588    ///   no fractions of seconds are conveyed (in such a case the period
1589    ///   is not conveyed), it may include 3 digits to convey
1590    ///   milliseconds, 6 digits to convey microseconds, 9 digits
1591    ///   to convey nanoseconds, 12 digits to convey picoseconds;
1592    pub fn deserialize_tz_timestamp(&mut self) -> Result<TzTimestamp, DeserializeError> {
1593        match self.buf {
1594            [] => {
1595                return Err(DeserializeError::GarbledMessage(format!(
1596                    "no more data to parse tag {:?}",
1597                    self.current_tag
1598                )));
1599            }
1600            [b'\x01', ..] => {
1601                return Err(self.reject(
1602                    self.current_tag,
1603                    ParseRejectReason::TagSpecifiedWithoutAValue,
1604                ));
1605            }
1606            // Missing separator at the end
1607            [_] => {
1608                return Err(DeserializeError::GarbledMessage(format!(
1609                    "missing tag ({:?}) separator",
1610                    self.current_tag
1611                )));
1612            }
1613            _ => {}
1614        }
1615        for i in 0..self.buf.len() {
1616            // SAFETY: i is between 0 and buf.len()
1617            if let b'\x01' = unsafe { self.buf.get_unchecked(i) } {
1618                // -1 to drop separator, separator on idx 0 is checked separately
1619                let data = &self.buf[0..i - 1];
1620                self.buf = &self.buf[i + 1..];
1621                // TODO
1622                return Ok(data.into());
1623            }
1624        }
1625
1626        Err(DeserializeError::GarbledMessage(format!(
1627            "no more data to parse tag {:?}",
1628            self.current_tag
1629        )))
1630    }
1631
1632    /// Deserialize time of day with timezone. Time represented based on
1633    /// ISO 8601. This is the time with a UTC offset to allow identification of
1634    /// local time and time zone of that time.
1635    ///
1636    /// Format is `HH:MM[:SS][Z | [ + | – hh[:mm]]]` where:
1637    /// - HH = 00-23 hours,
1638    /// - MM = 00-59 minutes,
1639    /// - SS = 00-59 seconds,
1640    /// - hh = 01-12 offset hours,
1641    /// - mm = 00-59 offset minutes.
1642    pub fn deserialize_tz_timeonly(&mut self) -> Result<TzTimeOnly, DeserializeError> {
1643        match self.buf {
1644            [] => {
1645                return Err(DeserializeError::GarbledMessage(format!(
1646                    "no more data to parse tag {:?}",
1647                    self.current_tag
1648                )));
1649            }
1650            &[b'\x01', ..] => {
1651                return Err(self.reject(
1652                    self.current_tag,
1653                    ParseRejectReason::TagSpecifiedWithoutAValue,
1654                ));
1655            }
1656            // Missing separator at the end
1657            &[_] => {
1658                return Err(DeserializeError::GarbledMessage(format!(
1659                    "missing tag ({:?}) separator",
1660                    self.current_tag
1661                )));
1662            }
1663            _ => {}
1664        }
1665        for i in 0..self.buf.len() {
1666            // SAFETY: i is between 0 and buf.len()
1667            if let b'\x01' = unsafe { self.buf.get_unchecked(i) } {
1668                // -1 to drop separator, separator on idx 0 is checked separately
1669                let data = &self.buf[0..i - 1];
1670                self.buf = &self.buf[i + 1..];
1671                return Ok(data.into());
1672            }
1673        }
1674
1675        Err(DeserializeError::GarbledMessage(format!(
1676            "no more data to parse tag {:?}",
1677            self.current_tag
1678        )))
1679    }
1680
1681    /// Deserialize sequence of character digits without commas or decimals.
1682    /// Value must be positive. Fields of datatype Length are referred to as
1683    /// Length fields.
1684    ///
1685    /// The Length field must be associated with a field of datatype data.
1686    ///
1687    /// The Length field must specify the number of octets of the value
1688    /// contained in the associated data field up to but not including
1689    /// the terminating `<SOH>`.
1690    pub fn deserialize_length(&mut self) -> Result<Length, DeserializeError> {
1691        match deserialize_length(self.buf) {
1692            Ok((leftover, len)) => {
1693                self.buf = leftover;
1694                Ok(len)
1695            }
1696            Err(DeserializeErrorInternal::Incomplete) => Err(DeserializeError::GarbledMessage(
1697                format!("no more data to parse tag {:?}", self.current_tag),
1698            )),
1699            Err(DeserializeErrorInternal::Error(reject)) => {
1700                Err(self.reject(self.current_tag, reject))
1701            }
1702        }
1703    }
1704
1705    /// Deserialize raw data with no format or content restrictions,
1706    /// or a character string encoded as specified by MessageEncoding(347).
1707    /// Fields of datatype data must have an associated field of type Length.
1708    /// Fields of datatype data must be immediately preceded by their
1709    /// associated Length field.
1710    pub fn deserialize_data(&mut self, len: usize) -> Result<Data, DeserializeError> {
1711        if self.buf.is_empty() {
1712            return Err(DeserializeError::GarbledMessage(format!(
1713                "no more data to parse tag {:?}",
1714                self.current_tag
1715            )));
1716        }
1717
1718        // Data length + separator (SOH)
1719        if self.buf.len() < len + 1 {
1720            return Err(DeserializeError::GarbledMessage(format!(
1721                "no more data to parse tag {:?}",
1722                self.current_tag
1723            )));
1724        }
1725
1726        // SAFETY: length checked above
1727        if let b'\x01' = unsafe { *self.buf.get_unchecked(len + 1) } {
1728            // Missing separator
1729            return Err(DeserializeError::GarbledMessage(format!(
1730                "missing tag ({:?}) separator",
1731                self.current_tag
1732            )));
1733        }
1734
1735        let data = &self.buf[0..len];
1736        // Skip data and separator
1737        self.buf = &self.buf[len + 1..];
1738        Ok(data.into())
1739    }
1740
1741    /// Deserialize XML document with characterstring repertoire specified
1742    /// as value of XML encoding declaration.
1743    ///
1744    /// # Requirements
1745    /// - A field of datatype XMLData must contain a well-formed document,
1746    ///   as defined by the W3C XML recommendation.
1747    /// - Fields of datatype XMLData must have an associated field of type
1748    ///   Length.
1749    /// - Fields of datatype XMLData must be immediately preceded by their
1750    ///   associated Length field.
1751    pub fn deserialize_xml(&mut self, len: usize) -> Result<XmlData, DeserializeError> {
1752        match self.buf {
1753            [] => {
1754                return Err(DeserializeError::GarbledMessage(format!(
1755                    "no more data to parse tag {:?}",
1756                    self.current_tag
1757                )));
1758            }
1759            [b'\x01', ..] => {
1760                return Err(self.reject(
1761                    self.current_tag,
1762                    ParseRejectReason::TagSpecifiedWithoutAValue,
1763                ));
1764            }
1765            _ => {}
1766        }
1767
1768        // XML length + separator (SOH)
1769        if self.buf.len() < len + 1 {
1770            return Err(DeserializeError::GarbledMessage(format!(
1771                "no more data to parse tag {:?}",
1772                self.current_tag
1773            )));
1774        }
1775
1776        // SAFETY: length checked above
1777        if let b'\x01' = unsafe { *self.buf.get_unchecked(len + 1) } {
1778            // Missing separator
1779            return Err(DeserializeError::GarbledMessage(format!(
1780                "missing tag ({:?}) separator",
1781                self.current_tag
1782            )));
1783        }
1784
1785        // TODO: XML validation, ParseRejectReason::XmlValidationError when invalid
1786        let xml = &self.buf[0..len];
1787        // Skip XML and separator
1788        self.buf = &self.buf[len + 1..];
1789        Ok(xml.into())
1790    }
1791
1792    // fn deserialize_tenor(input: &[u8]) -> Result<Tenor, ParseRejectReason>;
1793
1794    // TODO: it would be nice to have on generic function for all `*_enum`
1795    //       deserializations
1796
1797    pub fn deserialize_int_enum<T>(&mut self) -> Result<T, DeserializeError>
1798    where
1799        T: TryFrom<Int, Error = ParseRejectReason>,
1800    {
1801        T::try_from(self.deserialize_int()?).map_err(|reason| self.reject(self.current_tag, reason))
1802    }
1803
1804    pub fn deserialize_num_in_group_enum<T>(&mut self) -> Result<T, DeserializeError>
1805    where
1806        T: TryFrom<NumInGroup, Error = ParseRejectReason>,
1807    {
1808        T::try_from(self.deserialize_num_in_group()?)
1809            .map_err(|reason| self.reject(self.current_tag, reason))
1810    }
1811
1812    pub fn deserialize_char_enum<T>(&mut self) -> Result<T, DeserializeError>
1813    where
1814        T: TryFrom<Char, Error = ParseRejectReason>,
1815    {
1816        let value = self.deserialize_char()?;
1817        T::try_from(value).map_err(|reason| self.reject(self.current_tag, reason))
1818    }
1819
1820    pub fn deserialize_string_enum<T>(&mut self) -> Result<T, DeserializeError>
1821    where
1822        for<'a> T: TryFrom<&'a FixStr, Error = ParseRejectReason>,
1823    {
1824        let value = self.deserialize_str()?;
1825        T::try_from(value).map_err(|reason| self.reject(self.current_tag, reason))
1826    }
1827
1828    pub fn deserialize_multiple_char_value_enum<T>(&mut self) -> Result<Vec<T>, DeserializeError>
1829    where
1830        T: TryFrom<Char, Error = ParseRejectReason>,
1831    {
1832        let values = self.deserialize_multiple_char_value()?;
1833        let mut result = Vec::with_capacity(values.len());
1834        for value in values {
1835            result
1836                .push(T::try_from(value).map_err(|reason| self.reject(self.current_tag, reason))?);
1837        }
1838        Ok(result)
1839    }
1840
1841    pub fn deserialize_multiple_string_value_enum<T>(&mut self) -> Result<Vec<T>, DeserializeError>
1842    where
1843        for<'a> T: TryFrom<&'a FixStr, Error = ParseRejectReason>,
1844    {
1845        let values = self.deserialize_multiple_string_value()?;
1846        let mut result = Vec::with_capacity(values.len());
1847        for value in values {
1848            result
1849                .push(T::try_from(&value).map_err(|reason| self.reject(self.current_tag, reason))?);
1850        }
1851        Ok(result)
1852    }
1853}
1854
1855#[cfg(test)]
1856mod tests {
1857    use std::str::FromStr;
1858
1859    use assert_matches::assert_matches;
1860    use chrono::{DateTime, NaiveDate, NaiveTime, TimeZone, Utc};
1861
1862    use super::{Deserializer, RawMessage, deserialize_tag, raw_message};
1863    use crate::{
1864        deserializer::{RawMessageError, deserialize_checksum},
1865        fields::{LocalMktDate, Price, TimePrecision},
1866        messages::BEGIN_STRING,
1867    };
1868
1869    #[test]
1870    fn deserialize_tag_ok() {
1871        assert_matches!(deserialize_tag(b"8=FIXT1.1\x01", b"8="), Ok(b"FIXT1.1\x01"));
1872    }
1873
1874    #[test]
1875    fn deserialize_tag_incomplete() {
1876        assert_matches!(
1877            deserialize_tag(b"", b"8="),
1878            Err(RawMessageError::Incomplete)
1879        );
1880
1881        assert_matches!(
1882            deserialize_tag(b"8", b"8="),
1883            Err(RawMessageError::Incomplete)
1884        );
1885    }
1886
1887    #[test]
1888    fn deserialize_tag_garbled() {
1889        assert_matches!(
1890            deserialize_tag(b"89FIXT1.1\x01", b"8="),
1891            Err(RawMessageError::Garbled)
1892        );
1893    }
1894
1895    #[test]
1896    fn deserialize_checksum_ok() {
1897        assert_matches!(deserialize_checksum(b"123\x01"), Ok((b"", 123)));
1898
1899        assert_matches!(
1900            deserialize_checksum(b"123\x01more data"),
1901            Ok((b"more data", 123))
1902        );
1903    }
1904
1905    #[test]
1906    fn deserialize_checksum_incomplete() {
1907        assert_matches!(deserialize_checksum(b"1"), Err(RawMessageError::Incomplete));
1908
1909        assert_matches!(
1910            deserialize_checksum(b"12"),
1911            Err(RawMessageError::Incomplete)
1912        );
1913
1914        assert_matches!(
1915            deserialize_checksum(b"123"),
1916            Err(RawMessageError::Incomplete)
1917        );
1918    }
1919
1920    #[test]
1921    fn deserialize_checksum_garbled() {
1922        assert_matches!(
1923            deserialize_checksum(b"A23\x01"),
1924            Err(RawMessageError::InvalidChecksum)
1925        );
1926
1927        assert_matches!(
1928            deserialize_checksum(b"1234"),
1929            Err(RawMessageError::InvalidChecksum)
1930        );
1931        assert_matches!(
1932            deserialize_checksum(b"1234\x01"),
1933            Err(RawMessageError::InvalidChecksum)
1934        );
1935    }
1936
1937    #[test]
1938    fn raw_message_ok() {
1939        let input = b"8=MSG_BODY\x019=19\x01<lots of tags here>10=143\x01";
1940        assert!(raw_message(input).is_ok());
1941    }
1942
1943    #[test]
1944    fn raw_message_from_chunks_ok() {
1945        let input = &[
1946            b"8=MSG_BOD".as_slice(),
1947            b"Y\x019=19\x01<lots".as_slice(),
1948            b" of tags here>10=143\x01".as_slice(),
1949            b"leftover".as_slice(),
1950        ];
1951        let mut buf = Vec::new();
1952        let mut i = input.iter();
1953        {
1954            buf.extend_from_slice(i.next().unwrap());
1955            assert!(matches!(
1956                raw_message(&buf),
1957                Err(RawMessageError::Incomplete)
1958            ));
1959        }
1960        {
1961            buf.extend_from_slice(i.next().unwrap());
1962            assert!(matches!(
1963                raw_message(&buf),
1964                Err(RawMessageError::Incomplete)
1965            ));
1966        }
1967        {
1968            buf.extend_from_slice(i.next().unwrap());
1969            assert!(matches!(raw_message(&buf), Ok(([], _))));
1970        }
1971        {
1972            buf.extend_from_slice(i.next().unwrap());
1973            assert!(matches!(raw_message(&buf), Ok((b"leftover", _))));
1974        }
1975    }
1976
1977    fn deserializer(body: &[u8]) -> Deserializer {
1978        let raw_message = RawMessage {
1979            begin_string: BEGIN_STRING,
1980            body,
1981            checksum: 0,
1982        };
1983
1984        Deserializer {
1985            raw_message,
1986            buf: body,
1987            msg_type: None,
1988            seq_num: Some(1),
1989            current_tag: None,
1990            tmp_tag: None,
1991        }
1992    }
1993
1994    #[test]
1995    fn deserialize_str_ok() {
1996        let input = b"lorem ipsum\x01\x00";
1997        let mut deserializer = deserializer(input);
1998        let buf = deserializer
1999            .deserialize_str()
2000            .expect("failed to deserialize utc timestamp");
2001        assert_eq!(buf, "lorem ipsum");
2002        assert_eq!(deserializer.buf, &[b'\x00']);
2003    }
2004
2005    #[test]
2006    fn deserialize_string_ok() {
2007        let input = b"lorem ipsum\x01\x00";
2008        let mut deserializer = deserializer(input);
2009        let buf = deserializer
2010            .deserialize_string()
2011            .expect("failed to deserialize utc timestamp");
2012        assert_eq!(buf, "lorem ipsum");
2013        assert_eq!(deserializer.buf, &[b'\x00']);
2014    }
2015
2016    #[test]
2017    fn deserialize_utc_timestamp_ok() {
2018        let input = b"20190605-11:51:27\x01\x00";
2019        let mut deserializer = deserializer(input);
2020        let utc_timestamp = deserializer
2021            .deserialize_utc_timestamp()
2022            .expect("failed to deserialize utc timestamp");
2023        let date_time: DateTime<Utc> = Utc.from_utc_datetime(
2024            &NaiveDate::from_ymd_opt(2019, 6, 5)
2025                .unwrap()
2026                .and_hms_opt(11, 51, 27)
2027                .unwrap(),
2028        );
2029        assert_eq!(utc_timestamp.timestamp(), date_time);
2030        assert_eq!(utc_timestamp.precision(), TimePrecision::Secs);
2031        assert_eq!(deserializer.buf, &[b'\x00']);
2032    }
2033
2034    #[test]
2035    fn deserialize_utc_timestamp_with_millis_ok() {
2036        let input = b"20190605-11:51:27.848\x01\x00";
2037        let mut deserializer = deserializer(input);
2038        let utc_timestamp = deserializer
2039            .deserialize_utc_timestamp()
2040            .expect("failed to deserialize utc timestamp");
2041        let date_time = Utc.from_utc_datetime(
2042            &NaiveDate::from_ymd_opt(2019, 6, 5)
2043                .unwrap()
2044                .and_hms_milli_opt(11, 51, 27, 848)
2045                .unwrap(),
2046        );
2047        assert_eq!(utc_timestamp.timestamp(), date_time);
2048        assert_eq!(utc_timestamp.precision(), TimePrecision::Millis);
2049        assert_eq!(deserializer.buf, &[b'\x00']);
2050    }
2051
2052    #[test]
2053    fn deserialize_utc_timestamp_with_micros_ok() {
2054        let input = b"20190605-11:51:27.848757\x01\x00";
2055        let mut deserializer = deserializer(input);
2056        let utc_timestamp = deserializer
2057            .deserialize_utc_timestamp()
2058            .expect("failed to deserialize utc timestamp");
2059        let date_time = Utc.from_utc_datetime(
2060            &NaiveDate::from_ymd_opt(2019, 6, 5)
2061                .unwrap()
2062                .and_hms_micro_opt(11, 51, 27, 848757)
2063                .unwrap(),
2064        );
2065        assert_eq!(utc_timestamp.timestamp(), date_time);
2066        assert_eq!(utc_timestamp.precision(), TimePrecision::Micros);
2067        assert_eq!(deserializer.buf, &[b'\x00']);
2068    }
2069
2070    #[test]
2071    fn deserialize_utc_timestamp_with_nanos_ok() {
2072        let input = b"20190605-11:51:27.848757123\x01\x00";
2073        let mut deserializer = deserializer(input);
2074        let utc_timestamp = deserializer
2075            .deserialize_utc_timestamp()
2076            .expect("failed to deserialize utc timestamp");
2077        let date_time = Utc.from_utc_datetime(
2078            &NaiveDate::from_ymd_opt(2019, 6, 5)
2079                .unwrap()
2080                .and_hms_nano_opt(11, 51, 27, 848757123)
2081                .unwrap(),
2082        );
2083        assert_eq!(utc_timestamp.timestamp(), date_time);
2084        assert_eq!(utc_timestamp.precision(), TimePrecision::Nanos);
2085        assert_eq!(deserializer.buf, &[b'\x00']);
2086    }
2087
2088    #[test]
2089    fn deserialize_utc_timestamp_with_picos_ok() {
2090        let input = b"20190605-11:51:27.848757123999\x01\x00";
2091        let mut deserializer = deserializer(input);
2092        let utc_timestamp = deserializer
2093            .deserialize_utc_timestamp()
2094            .expect("failed to deserialize utc timestamp");
2095        let date_time = Utc.from_utc_datetime(
2096            &NaiveDate::from_ymd_opt(2019, 6, 5)
2097                .unwrap()
2098                .and_hms_nano_opt(11, 51, 27, 848757123)
2099                .unwrap(),
2100        );
2101        assert_eq!(utc_timestamp.timestamp(), date_time);
2102        assert_eq!(utc_timestamp.precision(), TimePrecision::Nanos);
2103        assert_eq!(deserializer.buf, &[b'\x00']);
2104    }
2105
2106    /// FIXME: it seems that timeonly deserialization has not been working for some time now
2107    #[ignore]
2108    #[test]
2109    fn deserialize_utc_timeonly_ok() {
2110        let input = b"11:51:27\x01\x00";
2111        let mut deserializer = deserializer(input);
2112        let utc_timeonly = deserializer
2113            .deserialize_utc_time_only()
2114            .expect("failed to deserialize utc timeonly");
2115        let time: NaiveTime = NaiveTime::from_hms_opt(11, 51, 27).unwrap();
2116        assert_eq!(utc_timeonly.timestamp(), time);
2117        assert_eq!(utc_timeonly.precision(), TimePrecision::Secs);
2118        assert_eq!(deserializer.buf, &[b'\x00']);
2119    }
2120
2121    #[test]
2122    fn deserialize_local_mkt_date_ok() {
2123        let input = b"20220530\x01\x00";
2124        let mut deserializer = deserializer(input);
2125        let local_mkt_date = deserializer
2126            .deserialize_local_mkt_date()
2127            .expect("failed to deserialize utc timestamp");
2128        assert_eq!(
2129            local_mkt_date,
2130            LocalMktDate::from_ymd_opt(2022, 5, 30).unwrap()
2131        );
2132        assert_eq!(deserializer.buf, &[b'\x00']);
2133    }
2134
2135    #[test]
2136    fn deserialize_price_ok() {
2137        let values: &[(&[u8], Price)] = &[
2138            (b"97\x01\x00", Price::from_str("97").expect("Wrong decimal")),
2139            (
2140                b"97.\x01\x00",
2141                Price::from_str("97.").expect("Wrong decimal"),
2142            ),
2143            (
2144                b"97.0347\x01\x00",
2145                Price::from_str("97.0347").expect("Wrong decimal"),
2146            ),
2147        ];
2148        for (input, value) in values {
2149            let mut deserializer = deserializer(input);
2150            let price = deserializer
2151                .deserialize_price()
2152                .expect("failed to deserialize price");
2153            assert_eq!(price, *value);
2154            assert_eq!(deserializer.buf, &[b'\x00']);
2155        }
2156    }
2157}