hotfix_message/encoding/
field_access.rs

1use std::iter::FusedIterator;
2use std::ops::Range;
3
4use crate::encoding::Buffer;
5
6/// Either a field that is missing or has an invalid value.
7#[derive(Debug, thiserror::Error)]
8pub enum FieldValueError<E> {
9    /// No such field was found.
10    #[error("Missing field tag")]
11    Missing,
12    /// The field was found, but can't be parsed.
13    #[error("Invalid field value: {0}")]
14    Invalid(#[from] E),
15}
16
17impl<E> PartialEq<FieldValueError<E>> for FieldValueError<E> {
18    fn eq(&self, other: &FieldValueError<E>) -> bool {
19        matches!(
20            (self, other),
21            (FieldValueError::Missing, FieldValueError::Missing)
22        )
23    }
24}
25
26impl<E> From<Option<E>> for FieldValueError<E> {
27    fn from(e: Option<E>) -> Self {
28        match e {
29            Some(e) => FieldValueError::Invalid(e),
30            None => FieldValueError::Missing,
31        }
32    }
33}
34
35/// Provides (de)serialization logic for a Rust type as FIX field values.
36///
37/// See the [`field_types`](crate::field_types) module for more information.
38pub trait FieldType<'a>
39where
40    Self: Sized,
41{
42    /// The error type that can arise during deserialization.
43    type Error;
44    /// A type with values that customize the serialization algorithm, e.g.
45    /// padding information.
46    type SerializeSettings: Default;
47
48    /// Writes `self` to `buffer` using default settings.
49    #[inline]
50    fn serialize<B>(&self, buffer: &mut B) -> usize
51    where
52        B: Buffer,
53    {
54        self.serialize_with(buffer, Self::SerializeSettings::default())
55    }
56
57    /// Writes `self` to `buffer` using custom serialization `settings`.
58    fn serialize_with<B>(&self, buffer: &mut B, settings: Self::SerializeSettings) -> usize
59    where
60        B: Buffer;
61
62    /// Parses and deserializes from `data`.
63    fn deserialize(data: &'a [u8]) -> Result<Self, Self::Error>;
64
65    /// Like [`FieldType::deserialize`], but it's allowed to skip *some* amount of
66    /// input checking. Invalid inputs might not trigger errors and instead be
67    /// deserialized as random values.
68    ///
69    /// # Safety
70    ///
71    /// This method remains 100% safe even on malformed inputs.
72    fn deserialize_lossy(data: &'a [u8]) -> Result<Self, Self::Error> {
73        Self::deserialize(data)
74    }
75
76    /// Serializes `self` to a [`Vec`] of bytes, allocated on the fly.
77    fn to_bytes(&self) -> Vec<u8> {
78        let mut buffer = Vec::new();
79        self.serialize(&mut buffer);
80        buffer
81    }
82
83    /// Allocates a [`String`] representation of `self`, using [`FieldType::to_bytes`].
84    ///
85    /// # Panics
86    ///
87    /// This function will panic if the underlying byte representation is not
88    /// valid UTF-8. As such, you should only *ever* use this function for
89    /// [`FieldType`] implementors that are guaranteed to be representable with
90    /// valid UTF-8 (like numbers with ASCII digits).
91    fn to_string(&self) -> String {
92        String::from_utf8(self.to_bytes()).expect("Invalid UTF-8 representation of FIX field.")
93    }
94}
95
96/// Provides random (i.e. non-sequential) access to FIX fields and groups within
97/// messages.
98///
99/// # Methods
100///
101/// [`FieldMap`] provides two kinds of methods:
102///
103/// 1. Group getters: [`FieldMap::group`] and
104///    [`FieldMap::group_opt`].
105///
106/// 2. Field getters: [`FieldMap::get_raw`], [`FieldMap::get`],
107///    etc..
108///
109/// The most basic form of field access is done via
110/// [`FieldMap::get_raw`], which performs no deserialization at all: it
111/// simply returns the bytes contents associated with a FIX field, if found.
112///
113/// Building upon [`FieldMap::get_raw`] and [`FieldType`], the other
114/// field access methods all provide some utility deserialization logic. These
115/// methods all have the `get_` prefix, with the following considerations:
116///
117/// - `get_lossy` methods perform "lossy" deserialization via
118///   [`FieldType::deserialize_lossy`]. Unlike lossless deserialization, these
119///   methods may skip some error checking logic and thus prove to be faster.
120///   Memory-safety is still guaranteed, but malformed FIX fields won't be
121///   detected 100% of the time.
122/// - `get_opt` methods work exactly like their non-`_opt` counterparties, but they
123///   have a different return type: instead of returning [`Err(None)`] for missing
124///   fields, these methods return [`None`] for missing fields and
125///   [`Some(Ok(field))`] for existing fields.
126///
127/// # Type parameters
128///
129/// This trait is generic over a type `F`, which must univocally identify FIX
130/// fields (besides FIX repeating groups, which allow repetitions).
131#[allow(dead_code)]
132pub trait FieldMap<F> {
133    /// The type returned by [`FieldMap::group`] and
134    /// [`FieldMap::group_opt`].
135    type Group: RepeatingGroup<Entry = Self>;
136
137    /// Looks for a `field` within `self` and then returns its raw byte
138    /// contents, if it exists.
139    fn get_raw(&self, field: F) -> Option<&[u8]>;
140
141    /// Looks for a group that starts with `field` within `self`.
142    fn group(
143        &self,
144        field: F,
145    ) -> Result<Self::Group, FieldValueError<<usize as FieldType<'_>>::Error>>;
146
147    /// Like [`FieldMap::group`], but doesn't return an [`Err`] if the
148    /// group is missing.
149    #[inline]
150    fn group_opt(&self, field: F) -> Result<Option<Self::Group>, <usize as FieldType<'_>>::Error> {
151        match self.group(field) {
152            Ok(group) => Ok(Some(group)),
153            Err(FieldValueError::Missing) => Ok(None),
154            Err(FieldValueError::Invalid(e)) => Err(e),
155        }
156    }
157
158    /// Looks for a `field` within `self` and then decodes its raw byte contents
159    /// via [`FieldType::deserialize`], if found.
160    #[inline]
161    fn get<'a, V>(&'a self, field: F) -> Result<V, FieldValueError<V::Error>>
162    where
163        V: FieldType<'a>,
164    {
165        self.get_opt(field)
166            .map_err(FieldValueError::Invalid)
167            .and_then(|opt| opt.ok_or(FieldValueError::Missing))
168    }
169
170    /// Like [`FieldMap::get`], but with lossy deserialization.
171    #[inline]
172    fn get_lossy<'a, V>(&'a self, field: F) -> Result<V, FieldValueError<V::Error>>
173    where
174        V: FieldType<'a>,
175    {
176        self.get_lossy_opt(field)
177            .map_err(FieldValueError::Invalid)
178            .and_then(|opt| opt.ok_or(FieldValueError::Missing))
179    }
180
181    /// Like [`FieldMap::get`], but doesn't return an [`Err`] if `field`
182    /// is missing.
183    #[inline]
184    fn get_opt<'a, V>(&'a self, field: F) -> Result<Option<V>, V::Error>
185    where
186        V: FieldType<'a>,
187    {
188        self.get_raw(field).map(V::deserialize).transpose()
189    }
190
191    /// Like [`FieldMap::get_opt`], but with lossy deserialization.
192    #[inline]
193    fn get_lossy_opt<'a, V>(&'a self, field: F) -> Result<Option<V>, V::Error>
194    where
195        V: FieldType<'a>,
196    {
197        self.get_raw(field).map(V::deserialize_lossy).transpose()
198    }
199}
200
201/// Provides access to entries within a FIX repeating group.
202#[allow(dead_code)]
203pub trait RepeatingGroup: Sized {
204    /// The type of entries in this FIX repeating group. Must implement
205    /// [`FieldMap`].
206    type Entry;
207
208    /// Returns the number of FIX group entries in `self`.
209    fn len(&self) -> usize;
210
211    /// Returns the `i` -th entry in `self`, if present.
212    fn get(&self, i: usize) -> Option<Self::Entry>;
213
214    /// Creates and returns an [`Iterator`] over the entries in `self`.
215    /// Iteration MUST be done in sequential order, i.e. in which they appear in
216    /// the original FIX message.
217    fn entries(&self) -> GroupEntries<'_, Self> {
218        GroupEntries {
219            group: self,
220            range: 0..self.len(),
221        }
222    }
223}
224
225/// An [`Iterator`] over the entries of a FIX repeating group.
226///
227/// This `struct` is created by the method [`RepeatingGroup::entries`]. It
228/// also implements [`FusedIterator`], [`DoubleEndedIterator`], and
229/// [`ExactSizeIterator`].
230#[derive(Debug, Clone)]
231#[allow(dead_code)]
232pub struct GroupEntries<'a, G> {
233    group: &'a G,
234    range: Range<usize>,
235}
236
237impl<'a, G> Iterator for GroupEntries<'a, G>
238where
239    G: RepeatingGroup,
240{
241    type Item = G::Entry;
242
243    fn next(&mut self) -> Option<Self::Item> {
244        let i = self.range.next()?;
245        self.group.get(i)
246    }
247
248    fn size_hint(&self) -> (usize, Option<usize>) {
249        self.range.size_hint()
250    }
251}
252
253impl<'a, G> FusedIterator for GroupEntries<'a, G> where G: RepeatingGroup {}
254impl<'a, G> ExactSizeIterator for GroupEntries<'a, G> where G: RepeatingGroup {}
255
256impl<'a, G> DoubleEndedIterator for GroupEntries<'a, G>
257where
258    G: RepeatingGroup,
259{
260    fn next_back(&mut self) -> Option<Self::Item> {
261        let i = self.range.next_back()?;
262        self.group.get(i)
263    }
264}