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            [] => {
1208                Err(DeserializeError::GarbledMessage(format!(
1209                    "no more data to parse tag {:?}",
1210                    self.current_tag
1211                )))
1212            }
1213            [b'\x01', ..] => {
1214                Err(self.reject(self.current_tag, ParseRejectReason::TagSpecifiedWithoutAValue))
1215            }
1216            // Missing separator at the end
1217            [_] => Err(DeserializeError::GarbledMessage(format!(
1218                "missing tag ({:?}) separator",
1219                self.current_tag
1220            ))),
1221            [
1222                // Year
1223                y3 @ b'0'..=b'9', y2 @ b'0'..=b'9', y1 @ b'0'..=b'9', y0 @ b'0'..=b'9',
1224                // Month
1225                m1 @ b'0'..=b'1', m0 @ b'0'..=b'9',
1226                // Day
1227                d1 @ b'0'..=b'3', d0 @ b'0'..=b'9',
1228                b'-',
1229                // Hour
1230                h1 @ b'0'..=b'2', h0 @ b'0'..=b'9',
1231                b':',
1232                // Minute
1233                mm1 @ b'0'..=b'5', mm0 @ b'0'..=b'9',
1234                b':',
1235                // TODO: leap second!
1236                // Second
1237                s1 @ b'0'..=b'5', s0 @ b'0'..=b'9',
1238                ..
1239            ] => {
1240                self.buf = &self.buf[17..];
1241                let year = (y3 - b'0') as i32 * 1000
1242                    + (y2 - b'0') as i32 * 100
1243                    + (y1 - b'0') as i32 * 10
1244                    + (y0 - b'0') as i32;
1245                let month = (m1 - b'0') as u32 * 10 + (m0 - b'0') as u32;
1246                let day = (d1 - b'0') as u32 * 10 + (d0 - b'0') as u32;
1247                let naive_date = NaiveDate::from_ymd_opt(year, month, day)
1248                    .ok_or_else(|| self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect))?;
1249                let hour = (h1 - b'0') as u32 * 10 + (h0 - b'0') as u32;
1250                let min = (mm1 - b'0') as u32 * 10 + (mm0 - b'0') as u32;
1251                let sec = (s1 - b'0') as u32 * 10 + (s0 - b'0') as u32;
1252                let (fraction_of_second, precision) = self.deserialize_fraction_of_second()?;
1253                let naive_date_time = naive_date
1254                    .and_hms_nano_opt(hour, min, sec, fraction_of_second)
1255                    .ok_or_else(|| self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect))?;
1256                let timestamp = Utc.from_utc_datetime(&naive_date_time);
1257
1258                match precision {
1259                    0 => Ok(UtcTimestamp::with_secs(timestamp)),
1260                    3 => Ok(UtcTimestamp::with_millis(timestamp)),
1261                    6 => Ok(UtcTimestamp::with_micros(timestamp)),
1262                    9 => Ok(UtcTimestamp::with_nanos(timestamp)),
1263                    // XXX: Types from `chrono` crate can't hold
1264                    //      time at picosecond resolution
1265                    12 => Ok(UtcTimestamp::with_nanos(timestamp)),
1266                    _ => Err(self.reject(self.current_tag, ParseRejectReason::IncorrectDataFormatForValue)),
1267                }
1268            }
1269            _ => Err(self.reject(self.current_tag, ParseRejectReason::IncorrectDataFormatForValue)),
1270        }
1271    }
1272
1273    /// Deserialize string representing time-only represented in UTC
1274    /// (Universal Time Coordinated) in either HH:MM:SS (whole seconds)
1275    /// or HH:MM:SS.sss* (milliseconds) format, colons, and period required.
1276    ///
1277    /// This special-purpose field is paired with UTCDateOnly to form a proper
1278    /// UTCTimestamp for bandwidth-sensitive messages.
1279    ///
1280    /// # Valid values:
1281    /// - HH = 00-23,
1282    /// - MM = 00-59,
1283    /// - SS = 00-60 (60 only if UTC leap second),
1284    /// - sss* fractions of seconds. The fractions of seconds may be empty when
1285    ///        no fractions of seconds are conveyed (in such a case the period
1286    ///        is not conveyed), it may include 3 digits to convey
1287    ///        milliseconds, 6 digits to convey microseconds, 9 digits
1288    ///        to convey nanoseconds, 12 digits to convey picoseconds;
1289    ///        // TODO: set precision!
1290    pub fn deserialize_utc_time_only(&mut self) -> Result<UtcTimeOnly, DeserializeError> {
1291        match self.buf {
1292            [] => {
1293                Err(DeserializeError::GarbledMessage(format!(
1294                    "no more data to parse tag {:?}",
1295                    self.current_tag
1296                )))
1297            }
1298            [b'\x01', ..] => {
1299                Err(self.reject(
1300                    self.current_tag,
1301                    ParseRejectReason::TagSpecifiedWithoutAValue,
1302                ))
1303            }
1304            [
1305                // hours
1306                h1 @ b'0'..=b'2', h0 @ b'0'..=b'9', b':',
1307                // minutes
1308                m1 @ b'0'..=b'5', m0 @ b'0'..=b'9', b':',
1309                // seconds
1310                s1 @ b'0'..=b'5', s0 @ b'0'..=b'9', b':',
1311                ..
1312            ] =>
1313            {
1314                let h = (h1 - b'0') * 10 + (h0 - b'0');
1315                let m = (m1 - b'0') * 10 + (m0 - b'0');
1316                let s = (s1 - b'0') * 10 + (s0 - b'0');
1317                self.buf = &self.buf[9..];
1318                let (ns, precision) = self.deserialize_fraction_of_second()?;
1319                let timestamp = NaiveTime::from_hms_nano_opt(h.into(), m.into(), s.into(), ns)
1320                    .ok_or_else(|| self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect));
1321                match timestamp {
1322                    Ok(timestamp) => {
1323                        match precision {
1324                            0 => Ok(UtcTimeOnly::with_secs(timestamp)),
1325                            3 => Ok(UtcTimeOnly::with_millis(timestamp)),
1326                            6 => Ok(UtcTimeOnly::with_micros(timestamp)),
1327                            9 => Ok(UtcTimeOnly::with_nanos(timestamp)),
1328                            // XXX: Types from `chrono` crate can't hold
1329                            //      time at picosecond resolution
1330                            12 => Ok(UtcTimeOnly::with_nanos(timestamp)),
1331                            _ => Err(self.reject(self.current_tag, ParseRejectReason::IncorrectDataFormatForValue)),
1332                        }
1333                    },
1334                    Err(err) => Err(err)
1335                }
1336            }
1337            // Leap second case
1338            [h1 @ b'0'..=b'2', h0 @ b'0'..=b'9', b':', m1 @ b'0'..=b'5', m0 @ b'0'..=b'9', b':', b'6', b'0', b':'] =>
1339            {
1340                let h = (h1 - b'0') * 10 + (h0 - b'0');
1341                let m = (m1 - b'0') * 10 + (m0 - b'0');
1342                let s = 60;
1343                self.buf = &self.buf[9..];
1344                let (ns, precision) = self.deserialize_fraction_of_second()?;
1345                let timestamp = NaiveTime::from_hms_nano_opt(h.into(), m.into(), s, ns)
1346                    .ok_or_else(|| self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect));
1347                match timestamp {
1348                    Ok(timestamp) => {
1349                        match precision {
1350                            0 => Ok(UtcTimeOnly::with_secs(timestamp)),
1351                            3 => Ok(UtcTimeOnly::with_millis(timestamp)),
1352                            6 => Ok(UtcTimeOnly::with_micros(timestamp)),
1353                            9 => Ok(UtcTimeOnly::with_nanos(timestamp)),
1354                            // XXX: Types from `chrono` crate can't hold
1355                            //      time at picosecond resolution
1356                            12 => Ok(UtcTimeOnly::with_nanos(timestamp)),
1357                            _ => Err(self.reject(self.current_tag, ParseRejectReason::IncorrectDataFormatForValue)),
1358                        }
1359                    },
1360                    Err(err) => Err(err)
1361                }
1362            }
1363            _ => Err(self.reject(self.current_tag, ParseRejectReason::IncorrectDataFormatForValue)),
1364        }
1365    }
1366
1367    /// Deserialize date represented in UTC (Universal Time Coordinated)
1368    /// in YYYYMMDD format.
1369    ///
1370    /// # Valid values:
1371    /// - YYYY = 0000-9999,
1372    /// - MM = 01-12,
1373    /// - DD = 01-31.
1374    pub fn deserialize_utc_date_only(&mut self) -> Result<UtcDateOnly, DeserializeError> {
1375        match self.buf {
1376            [] => {
1377                Err(DeserializeError::GarbledMessage(format!(
1378                    "no more data to parse tag {:?}",
1379                    self.current_tag
1380                )))
1381            }
1382            [b'\x01', ..] => Err(self.reject(self.current_tag, ParseRejectReason::TagSpecifiedWithoutAValue)),
1383            // Missing separator at the end
1384            [_] => Err(DeserializeError::GarbledMessage(format!(
1385                "missing tag ({:?}) separator",
1386                self.current_tag
1387            ))),
1388            [
1389                // Year
1390                y3 @ b'0'..=b'9', y2 @ b'0'..=b'9', y1 @ b'0'..=b'9', y0 @ b'0'..=b'9',
1391                // Month
1392                m1 @ b'0'..=b'1', m0 @ b'0'..=b'9',
1393                // Day
1394                d1 @ b'0'..=b'3', d0 @ b'0'..=b'9',
1395                // Separator
1396                b'\x01',
1397            ] => {
1398                let year = (y3 - b'0') as u16 * 1000
1399                    + (y2 - b'0') as u16 * 100
1400                    + (y1 - b'0') as u16 * 10
1401                    + (y0 - b'0') as u16;
1402                let month = (m1 - b'0') * 10 + (m0 - b'0');
1403                let day = (d1 - b'0') * 10 + (d0 - b'0');
1404                self.buf = &self.buf[9..];
1405                UtcDateOnly::from_ymd_opt(year.into(), month.into(), day.into())
1406                    .ok_or_else(|| self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect))
1407            },
1408            _ => Err(self.reject(self.current_tag, ParseRejectReason::IncorrectDataFormatForValue)),
1409        }
1410    }
1411
1412    /// Deserialize time local to a market center. Used where offset to UTC
1413    /// varies throughout the year and the defining market center is identified
1414    /// in a corresponding field.
1415    ///
1416    /// Format is HH:MM:SS where:
1417    /// - HH = 00-23 hours,
1418    /// - MM = 00-59 minutes,
1419    /// - SS = 00-59 seconds.
1420    ///
1421    /// In general only the hour token is non-zero.
1422    pub fn deserialize_local_mkt_time(&mut self) -> Result<LocalMktTime, DeserializeError> {
1423        match self.buf {
1424            [] => {
1425                Err(DeserializeError::GarbledMessage(format!(
1426                    "no more data to parse tag {:?}",
1427                    self.current_tag
1428                )))
1429            }
1430            [b'\x01', ..] => {
1431                Err(self.reject(self.current_tag, ParseRejectReason::TagSpecifiedWithoutAValue))
1432            }
1433            // Missing separator at the end
1434            [_] => Err(DeserializeError::GarbledMessage(format!(
1435                "missing tag ({:?}) separator",
1436                self.current_tag
1437            ))),
1438
1439            [
1440                // Hour
1441                h1 @ b'0'..=b'2', h0 @ b'0'..=b'9',
1442                b':',
1443                // Minute
1444                m1 @ b'0'..=b'5', m0 @ b'0'..=b'0',
1445                b':',
1446                // Second
1447                s1 @ b'0'..=b'5', s0 @ b'0'..=b'9',
1448                b'\x01',
1449                ..
1450            ] =>
1451            {
1452                let hour = (h1 - b'0') as u32 * 10 + (h0 - b'0') as u32;
1453                let minute = (m1 - b'0') as u32 * 10 + (m0 - b'0') as u32;
1454                let second = (s1 - b'0') as u32 * 10 + (s0 - b'0') as u32;
1455                self.buf = &self.buf[8..];
1456                LocalMktTime::from_hms_opt(hour, minute, second)
1457                    .ok_or_else(|| self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect))
1458            }
1459            _ => Err(self.reject(self.current_tag, ParseRejectReason::IncorrectDataFormatForValue)),
1460        }
1461    }
1462
1463    /// Deserialize date of local market (as opposed to UTC) in YYYYMMDD
1464    /// format.
1465    ///
1466    /// # Valid values:
1467    /// - YYYY = 0000-9999,
1468    /// - MM = 01-12,
1469    /// - DD = 01-31.
1470    pub fn deserialize_local_mkt_date(&mut self) -> Result<LocalMktDate, DeserializeError> {
1471        match self.buf {
1472            [] => {
1473                Err(DeserializeError::GarbledMessage(format!(
1474                    "no more data to parse tag {:?}",
1475                    self.current_tag
1476                )))
1477            }
1478            [b'\x01', ..] => Err(self.reject(self.current_tag, ParseRejectReason::TagSpecifiedWithoutAValue)),
1479            // Missing separator at the end
1480            [_] => Err(DeserializeError::GarbledMessage(format!(
1481                "missing tag ({:?}) separator",
1482                self.current_tag
1483            ))),
1484            [
1485                // Year
1486                y3 @ b'0'..=b'9', y2 @ b'0'..=b'9', y1 @ b'0'..=b'9', y0 @ b'0'..=b'9',
1487                // Month
1488                m1 @ b'0'..=b'1', m0 @ b'0'..=b'9',
1489                // Day
1490                d1 @ b'0'..=b'3', d0 @ b'0'..=b'9',
1491                // Separator
1492                b'\x01', ..
1493            ] => {
1494                let year = (y3 - b'0') as u16 * 1000
1495                    + (y2 - b'0') as u16 * 100
1496                    + (y1 - b'0') as u16 * 10
1497                    + (y0 - b'0') as u16;
1498                let month = (m1 - b'0') * 10 + (m0 - b'0');
1499                let day = (d1 - b'0') * 10 + (d0 - b'0');
1500                self.buf = &self.buf[9..];
1501                LocalMktDate::from_ymd_opt(year.into(), month.into(), day.into())
1502                    .ok_or_else(|| self.reject(self.current_tag, ParseRejectReason::ValueIsIncorrect))
1503            }
1504            _ => Err(self.reject(self.current_tag, ParseRejectReason::IncorrectDataFormatForValue)),
1505        }
1506    }
1507
1508    /// Deserialize string representing a time/date combination representing
1509    /// local time with an offset to UTC to allow identification of local time
1510    /// and time zone offset of that time.
1511    ///
1512    /// The representation is based on ISO 8601.
1513    ///
1514    /// Format is `YYYYMMDD-HH:MM:SS.sss*[Z | [ + | – hh[:mm]]]` where:
1515    /// - YYYY = 0000 to 9999,
1516    /// - MM = 01-12,
1517    /// - DD = 01-31 HH = 00-23 hours,
1518    /// - MM = 00-59 minutes,
1519    /// - SS = 00-59 seconds,
1520    /// - hh = 01-12 offset hours,
1521    /// - mm = 00-59 offset minutes,
1522    /// - sss* fractions of seconds. The fractions of seconds may be empty when
1523    ///        no fractions of seconds are conveyed (in such a case the period
1524    ///        is not conveyed), it may include 3 digits to convey
1525    ///        milliseconds, 6 digits to convey microseconds, 9 digits
1526    ///        to convey nanoseconds, 12 digits to convey picoseconds;
1527    pub fn deserialize_tz_timestamp(&mut self) -> Result<TzTimestamp, DeserializeError> {
1528        match self.buf {
1529            [] => {
1530                return Err(DeserializeError::GarbledMessage(format!(
1531                    "no more data to parse tag {:?}",
1532                    self.current_tag
1533                )))
1534            }
1535            [b'\x01', ..] => {
1536                return Err(self.reject(
1537                    self.current_tag,
1538                    ParseRejectReason::TagSpecifiedWithoutAValue,
1539                ))
1540            }
1541            // Missing separator at the end
1542            [_] => {
1543                return Err(DeserializeError::GarbledMessage(format!(
1544                    "missing tag ({:?}) separator",
1545                    self.current_tag
1546                )))
1547            }
1548            _ => {}
1549        }
1550        for i in 0..self.buf.len() {
1551            // SAFETY: i is between 0 and buf.len()
1552            if let b'\x01' = unsafe { self.buf.get_unchecked(i) } {
1553                // -1 to drop separator, separator on idx 0 is checked separately
1554                let data = &self.buf[0..i - 1];
1555                self.buf = &self.buf[i + 1..];
1556                // TODO
1557                return Ok(data.into());
1558            }
1559        }
1560
1561        Err(DeserializeError::GarbledMessage(format!(
1562            "no more data to parse tag {:?}",
1563            self.current_tag
1564        )))
1565    }
1566
1567    /// Deserialize time of day with timezone. Time represented based on
1568    /// ISO 8601. This is the time with a UTC offset to allow identification of
1569    /// local time and time zone of that time.
1570    ///
1571    /// Format is `HH:MM[:SS][Z | [ + | – hh[:mm]]]` where:
1572    /// - HH = 00-23 hours,
1573    /// - MM = 00-59 minutes,
1574    /// - SS = 00-59 seconds,
1575    /// - hh = 01-12 offset hours,
1576    /// - mm = 00-59 offset minutes.
1577    pub fn deserialize_tz_timeonly(&mut self) -> Result<TzTimeOnly, DeserializeError> {
1578        match self.buf {
1579            [] => {
1580                return Err(DeserializeError::GarbledMessage(format!(
1581                    "no more data to parse tag {:?}",
1582                    self.current_tag
1583                )))
1584            }
1585            &[b'\x01', ..] => {
1586                return Err(self.reject(
1587                    self.current_tag,
1588                    ParseRejectReason::TagSpecifiedWithoutAValue,
1589                ))
1590            }
1591            // Missing separator at the end
1592            &[_] => {
1593                return Err(DeserializeError::GarbledMessage(format!(
1594                    "missing tag ({:?}) separator",
1595                    self.current_tag
1596                )))
1597            }
1598            _ => {}
1599        }
1600        for i in 0..self.buf.len() {
1601            // SAFETY: i is between 0 and buf.len()
1602            if let b'\x01' = unsafe { self.buf.get_unchecked(i) } {
1603                // -1 to drop separator, separator on idx 0 is checked separately
1604                let data = &self.buf[0..i - 1];
1605                self.buf = &self.buf[i + 1..];
1606                return Ok(data.into());
1607            }
1608        }
1609
1610        Err(DeserializeError::GarbledMessage(format!(
1611            "no more data to parse tag {:?}",
1612            self.current_tag
1613        )))
1614    }
1615
1616    /// Deserialize sequence of character digits without commas or decimals.
1617    /// Value must be positive. Fields of datatype Length are referred to as
1618    /// Length fields.
1619    ///
1620    /// The Length field must be associated with a field of datatype data.
1621    ///
1622    /// The Length field must specify the number of octets of the value
1623    /// contained in the associated data field up to but not including
1624    /// the terminating `<SOH>`.
1625    pub fn deserialize_length(&mut self) -> Result<Length, DeserializeError> {
1626        match deserialize_length(self.buf) {
1627            Ok((leftover, len)) => {
1628                self.buf = leftover;
1629                Ok(len)
1630            }
1631            Err(DeserializeErrorInternal::Incomplete) => Err(DeserializeError::GarbledMessage(
1632                format!("no more data to parse tag {:?}", self.current_tag),
1633            )),
1634            Err(DeserializeErrorInternal::Error(reject)) => {
1635                Err(self.reject(self.current_tag, reject))
1636            }
1637        }
1638    }
1639
1640    /// Deserialize raw data with no format or content restrictions,
1641    /// or a character string encoded as specified by MessageEncoding(347).
1642    /// Fields of datatype data must have an associated field of type Length.
1643    /// Fields of datatype data must be immediately preceded by their
1644    /// associated Length field.
1645    pub fn deserialize_data(&mut self, len: usize) -> Result<Data, DeserializeError> {
1646        if self.buf.is_empty() {
1647            return Err(DeserializeError::GarbledMessage(format!(
1648                "no more data to parse tag {:?}",
1649                self.current_tag
1650            )));
1651        }
1652
1653        // Data length + separator (SOH)
1654        if self.buf.len() < len + 1 {
1655            return Err(DeserializeError::GarbledMessage(format!(
1656                "no more data to parse tag {:?}",
1657                self.current_tag
1658            )));
1659        }
1660
1661        // SAFETY: length checked above
1662        if let b'\x01' = unsafe { *self.buf.get_unchecked(len + 1) } {
1663            // Missing separator
1664            return Err(DeserializeError::GarbledMessage(format!(
1665                "missing tag ({:?}) separator",
1666                self.current_tag
1667            )));
1668        }
1669
1670        let data = &self.buf[0..len];
1671        // Skip data and separator
1672        self.buf = &self.buf[len + 1..];
1673        Ok(data.into())
1674    }
1675
1676    /// Deserialize XML document with characterstring repertoire specified
1677    /// as value of XML encoding declaration.
1678    ///
1679    /// # Requirements
1680    /// - A field of datatype XMLData must contain a well-formed document,
1681    ///   as defined by the W3C XML recommendation.
1682    /// - Fields of datatype XMLData must have an associated field of type
1683    ///   Length.
1684    /// - Fields of datatype XMLData must be immediately preceded by their
1685    ///   associated Length field.
1686    pub fn deserialize_xml(&mut self, len: usize) -> Result<XmlData, DeserializeError> {
1687        match self.buf {
1688            [] => {
1689                return Err(DeserializeError::GarbledMessage(format!(
1690                    "no more data to parse tag {:?}",
1691                    self.current_tag
1692                )))
1693            }
1694            [b'\x01', ..] => {
1695                return Err(self.reject(
1696                    self.current_tag,
1697                    ParseRejectReason::TagSpecifiedWithoutAValue,
1698                ))
1699            }
1700            _ => {}
1701        }
1702
1703        // XML length + separator (SOH)
1704        if self.buf.len() < len + 1 {
1705            return Err(DeserializeError::GarbledMessage(format!(
1706                "no more data to parse tag {:?}",
1707                self.current_tag
1708            )));
1709        }
1710
1711        // SAFETY: length checked above
1712        if let b'\x01' = unsafe { *self.buf.get_unchecked(len + 1) } {
1713            // Missing separator
1714            return Err(DeserializeError::GarbledMessage(format!(
1715                "missing tag ({:?}) separator",
1716                self.current_tag
1717            )));
1718        }
1719
1720        // TODO: XML validation, ParseRejectReason::XmlValidationError when invalid
1721        let xml = &self.buf[0..len];
1722        // Skip XML and separator
1723        self.buf = &self.buf[len + 1..];
1724        Ok(xml.into())
1725    }
1726
1727    // fn deserialize_tenor(input: &[u8]) -> Result<Tenor, ParseRejectReason>;
1728
1729    // TODO: it would be nice to have on generic function for all `*_enum`
1730    //       deserializations
1731
1732    pub fn deserialize_int_enum<T>(&mut self) -> Result<T, DeserializeError>
1733    where
1734        T: TryFrom<Int, Error = ParseRejectReason>,
1735    {
1736        T::try_from(self.deserialize_int()?).map_err(|reason| self.reject(self.current_tag, reason))
1737    }
1738
1739    pub fn deserialize_num_in_group_enum<T>(&mut self) -> Result<T, DeserializeError>
1740    where
1741        T: TryFrom<NumInGroup, Error = ParseRejectReason>,
1742    {
1743        T::try_from(self.deserialize_num_in_group()?)
1744            .map_err(|reason| self.reject(self.current_tag, reason))
1745    }
1746
1747    pub fn deserialize_char_enum<T>(&mut self) -> Result<T, DeserializeError>
1748    where
1749        T: TryFrom<Char, Error = ParseRejectReason>,
1750    {
1751        let value = self.deserialize_char()?;
1752        T::try_from(value).map_err(|reason| self.reject(self.current_tag, reason))
1753    }
1754
1755    pub fn deserialize_string_enum<T>(&mut self) -> Result<T, DeserializeError>
1756    where
1757        for<'a> T: TryFrom<&'a FixStr, Error = ParseRejectReason>,
1758    {
1759        let value = self.deserialize_str()?;
1760        T::try_from(value).map_err(|reason| self.reject(self.current_tag, reason))
1761    }
1762
1763    pub fn deserialize_multiple_char_value_enum<T>(&mut self) -> Result<Vec<T>, DeserializeError>
1764    where
1765        T: TryFrom<Char, Error = ParseRejectReason>,
1766    {
1767        let values = self.deserialize_multiple_char_value()?;
1768        let mut result = Vec::with_capacity(values.len());
1769        for value in values {
1770            result
1771                .push(T::try_from(value).map_err(|reason| self.reject(self.current_tag, reason))?);
1772        }
1773        Ok(result)
1774    }
1775
1776    pub fn deserialize_multiple_string_value_enum<T>(&mut self) -> Result<Vec<T>, DeserializeError>
1777    where
1778        for<'a> T: TryFrom<&'a FixStr, Error = ParseRejectReason>,
1779    {
1780        let values = self.deserialize_multiple_string_value()?;
1781        let mut result = Vec::with_capacity(values.len());
1782        for value in values {
1783            result
1784                .push(T::try_from(&value).map_err(|reason| self.reject(self.current_tag, reason))?);
1785        }
1786        Ok(result)
1787    }
1788}
1789
1790#[cfg(test)]
1791mod tests {
1792    use std::str::FromStr;
1793
1794    use assert_matches::assert_matches;
1795    use chrono::{DateTime, NaiveDate, NaiveTime, TimeZone, Utc};
1796
1797    use super::{deserialize_tag, raw_message, Deserializer, RawMessage};
1798    use crate::{
1799        deserializer::{deserialize_checksum, RawMessageError},
1800        fields::{LocalMktDate, Price, TimePrecision},
1801        messages::BEGIN_STRING,
1802    };
1803
1804    #[test]
1805    fn deserialize_tag_ok() {
1806        assert_matches!(deserialize_tag(b"8=FIXT1.1\x01", b"8="), Ok(b"FIXT1.1\x01"));
1807    }
1808
1809    #[test]
1810    fn deserialize_tag_incomplete() {
1811        assert_matches!(
1812            deserialize_tag(b"", b"8="),
1813            Err(RawMessageError::Incomplete)
1814        );
1815
1816        assert_matches!(
1817            deserialize_tag(b"8", b"8="),
1818            Err(RawMessageError::Incomplete)
1819        );
1820    }
1821
1822    #[test]
1823    fn deserialize_tag_garbled() {
1824        assert_matches!(
1825            deserialize_tag(b"89FIXT1.1\x01", b"8="),
1826            Err(RawMessageError::Garbled)
1827        );
1828    }
1829
1830    #[test]
1831    fn deserialize_checksum_ok() {
1832        assert_matches!(deserialize_checksum(b"123\x01"), Ok((b"", 123)));
1833
1834        assert_matches!(
1835            deserialize_checksum(b"123\x01more data"),
1836            Ok((b"more data", 123))
1837        );
1838    }
1839
1840    #[test]
1841    fn deserialize_checksum_incomplete() {
1842        assert_matches!(deserialize_checksum(b"1"), Err(RawMessageError::Incomplete));
1843
1844        assert_matches!(
1845            deserialize_checksum(b"12"),
1846            Err(RawMessageError::Incomplete)
1847        );
1848
1849        assert_matches!(
1850            deserialize_checksum(b"123"),
1851            Err(RawMessageError::Incomplete)
1852        );
1853    }
1854
1855    #[test]
1856    fn deserialize_checksum_garbled() {
1857        assert_matches!(
1858            deserialize_checksum(b"A23\x01"),
1859            Err(RawMessageError::InvalidChecksum)
1860        );
1861
1862        assert_matches!(
1863            deserialize_checksum(b"1234"),
1864            Err(RawMessageError::InvalidChecksum)
1865        );
1866        assert_matches!(
1867            deserialize_checksum(b"1234\x01"),
1868            Err(RawMessageError::InvalidChecksum)
1869        );
1870    }
1871
1872    #[test]
1873    fn raw_message_ok() {
1874        let input = b"8=MSG_BODY\x019=19\x01<lots of tags here>10=143\x01";
1875        assert!(raw_message(input).is_ok());
1876    }
1877
1878    #[test]
1879    fn raw_message_from_chunks_ok() {
1880        let input = &[
1881            b"8=MSG_BOD".as_slice(),
1882            b"Y\x019=19\x01<lots".as_slice(),
1883            b" of tags here>10=143\x01".as_slice(),
1884            b"leftover".as_slice(),
1885        ];
1886        let mut buf = Vec::new();
1887        let mut i = input.iter();
1888        {
1889            buf.extend_from_slice(i.next().unwrap());
1890            assert!(matches!(
1891                raw_message(&buf),
1892                Err(RawMessageError::Incomplete)
1893            ));
1894        }
1895        {
1896            buf.extend_from_slice(i.next().unwrap());
1897            assert!(matches!(
1898                raw_message(&buf),
1899                Err(RawMessageError::Incomplete)
1900            ));
1901        }
1902        {
1903            buf.extend_from_slice(i.next().unwrap());
1904            assert!(matches!(raw_message(&buf), Ok(([], _))));
1905        }
1906        {
1907            buf.extend_from_slice(i.next().unwrap());
1908            assert!(matches!(raw_message(&buf), Ok((b"leftover", _))));
1909        }
1910    }
1911
1912    fn deserializer(body: &[u8]) -> Deserializer {
1913        let raw_message = RawMessage {
1914            begin_string: BEGIN_STRING,
1915            body,
1916            checksum: 0,
1917        };
1918
1919        Deserializer {
1920            raw_message,
1921            buf: body,
1922            msg_type: None,
1923            seq_num: Some(1),
1924            current_tag: None,
1925            tmp_tag: None,
1926        }
1927    }
1928
1929    #[test]
1930    fn deserialize_str_ok() {
1931        let input = b"lorem ipsum\x01\x00";
1932        let mut deserializer = deserializer(input);
1933        let buf = deserializer
1934            .deserialize_str()
1935            .expect("failed to deserialize utc timestamp");
1936        assert_eq!(buf, "lorem ipsum");
1937        assert_eq!(deserializer.buf, &[b'\x00']);
1938    }
1939
1940    #[test]
1941    fn deserialize_string_ok() {
1942        let input = b"lorem ipsum\x01\x00";
1943        let mut deserializer = deserializer(input);
1944        let buf = deserializer
1945            .deserialize_string()
1946            .expect("failed to deserialize utc timestamp");
1947        assert_eq!(buf, "lorem ipsum");
1948        assert_eq!(deserializer.buf, &[b'\x00']);
1949    }
1950
1951    #[test]
1952    fn deserialize_utc_timestamp_ok() {
1953        let input = b"20190605-11:51:27\x01\x00";
1954        let mut deserializer = deserializer(input);
1955        let utc_timestamp = deserializer
1956            .deserialize_utc_timestamp()
1957            .expect("failed to deserialize utc timestamp");
1958        let date_time: DateTime<Utc> = Utc.from_utc_datetime(
1959            &NaiveDate::from_ymd_opt(2019, 6, 5)
1960                .unwrap()
1961                .and_hms_opt(11, 51, 27)
1962                .unwrap(),
1963        );
1964        assert_eq!(utc_timestamp.timestamp(), date_time);
1965        assert_eq!(utc_timestamp.precision(), TimePrecision::Secs);
1966        assert_eq!(deserializer.buf, &[b'\x00']);
1967    }
1968
1969    #[test]
1970    fn deserialize_utc_timestamp_with_millis_ok() {
1971        let input = b"20190605-11:51:27.848\x01\x00";
1972        let mut deserializer = deserializer(input);
1973        let utc_timestamp = deserializer
1974            .deserialize_utc_timestamp()
1975            .expect("failed to deserialize utc timestamp");
1976        let date_time = Utc.from_utc_datetime(
1977            &NaiveDate::from_ymd_opt(2019, 6, 5)
1978                .unwrap()
1979                .and_hms_milli_opt(11, 51, 27, 848)
1980                .unwrap(),
1981        );
1982        assert_eq!(utc_timestamp.timestamp(), date_time);
1983        assert_eq!(utc_timestamp.precision(), TimePrecision::Millis);
1984        assert_eq!(deserializer.buf, &[b'\x00']);
1985    }
1986
1987    #[test]
1988    fn deserialize_utc_timestamp_with_micros_ok() {
1989        let input = b"20190605-11:51:27.848757\x01\x00";
1990        let mut deserializer = deserializer(input);
1991        let utc_timestamp = deserializer
1992            .deserialize_utc_timestamp()
1993            .expect("failed to deserialize utc timestamp");
1994        let date_time = Utc.from_utc_datetime(
1995            &NaiveDate::from_ymd_opt(2019, 6, 5)
1996                .unwrap()
1997                .and_hms_micro_opt(11, 51, 27, 848757)
1998                .unwrap(),
1999        );
2000        assert_eq!(utc_timestamp.timestamp(), date_time);
2001        assert_eq!(utc_timestamp.precision(), TimePrecision::Micros);
2002        assert_eq!(deserializer.buf, &[b'\x00']);
2003    }
2004
2005    #[test]
2006    fn deserialize_utc_timestamp_with_nanos_ok() {
2007        let input = b"20190605-11:51:27.848757123\x01\x00";
2008        let mut deserializer = deserializer(input);
2009        let utc_timestamp = deserializer
2010            .deserialize_utc_timestamp()
2011            .expect("failed to deserialize utc timestamp");
2012        let date_time = Utc.from_utc_datetime(
2013            &NaiveDate::from_ymd_opt(2019, 6, 5)
2014                .unwrap()
2015                .and_hms_nano_opt(11, 51, 27, 848757123)
2016                .unwrap(),
2017        );
2018        assert_eq!(utc_timestamp.timestamp(), date_time);
2019        assert_eq!(utc_timestamp.precision(), TimePrecision::Nanos);
2020        assert_eq!(deserializer.buf, &[b'\x00']);
2021    }
2022
2023    #[test]
2024    fn deserialize_utc_timestamp_with_picos_ok() {
2025        let input = b"20190605-11:51:27.848757123999\x01\x00";
2026        let mut deserializer = deserializer(input);
2027        let utc_timestamp = deserializer
2028            .deserialize_utc_timestamp()
2029            .expect("failed to deserialize utc timestamp");
2030        let date_time = Utc.from_utc_datetime(
2031            &NaiveDate::from_ymd_opt(2019, 6, 5)
2032                .unwrap()
2033                .and_hms_nano_opt(11, 51, 27, 848757123)
2034                .unwrap(),
2035        );
2036        assert_eq!(utc_timestamp.timestamp(), date_time);
2037        assert_eq!(utc_timestamp.precision(), TimePrecision::Nanos);
2038        assert_eq!(deserializer.buf, &[b'\x00']);
2039    }
2040
2041    /// FIXME: it seems that timeonly deserialization has not been working for some time now
2042    #[ignore]
2043    #[test]
2044    fn deserialize_utc_timeonly_ok() {
2045        let input = b"11:51:27\x01\x00";
2046        let mut deserializer = deserializer(input);
2047        let utc_timeonly = deserializer
2048            .deserialize_utc_time_only()
2049            .expect("failed to deserialize utc timeonly");
2050        let time: NaiveTime = NaiveTime::from_hms_opt(11, 51, 27).unwrap();
2051        assert_eq!(utc_timeonly.timestamp(), time);
2052        assert_eq!(utc_timeonly.precision(), TimePrecision::Secs);
2053        assert_eq!(deserializer.buf, &[b'\x00']);
2054    }
2055
2056    #[test]
2057    fn deserialize_local_mkt_date_ok() {
2058        let input = b"20220530\x01\x00";
2059        let mut deserializer = deserializer(input);
2060        let local_mkt_date = deserializer
2061            .deserialize_local_mkt_date()
2062            .expect("failed to deserialize utc timestamp");
2063        assert_eq!(
2064            local_mkt_date,
2065            LocalMktDate::from_ymd_opt(2022, 5, 30).unwrap()
2066        );
2067        assert_eq!(deserializer.buf, &[b'\x00']);
2068    }
2069
2070    #[test]
2071    fn deserialize_price_ok() {
2072        let values: &[(&[u8], Price)] = &[
2073            (b"97\x01\x00", Price::from_str("97").expect("Wrong decimal")),
2074            (
2075                b"97.\x01\x00",
2076                Price::from_str("97.").expect("Wrong decimal"),
2077            ),
2078            (
2079                b"97.0347\x01\x00",
2080                Price::from_str("97.0347").expect("Wrong decimal"),
2081            ),
2082        ];
2083        for (input, value) in values {
2084            let mut deserializer = deserializer(input);
2085            let price = deserializer
2086                .deserialize_price()
2087                .expect("failed to deserialize price");
2088            assert_eq!(price, *value);
2089            assert_eq!(deserializer.buf, &[b'\x00']);
2090        }
2091    }
2092}