hotfix_dictionary/
layout.rs

1use smartstring::alias::String as SmartString;
2use std::fmt;
3
4use crate::component::Component;
5use crate::{Dictionary, Field};
6
7pub fn display_layout_item(indent: u32, item: LayoutItem, f: &mut fmt::Formatter) -> fmt::Result {
8    for _ in 0..indent {
9        write!(f, " ")?;
10    }
11    match item.kind() {
12        LayoutItemKind::Field(_) => {
13            writeln!(
14                f,
15                "<field name='{}' required='{}' />",
16                item.tag_text(),
17                item.required(),
18            )?;
19        }
20        LayoutItemKind::Group(_, _fields) => {
21            writeln!(
22                f,
23                "<group name='{}' required='{}' />",
24                item.tag_text(),
25                item.required(),
26            )?;
27            writeln!(f, "</group>")?;
28        }
29        LayoutItemKind::Component(_c) => {
30            writeln!(
31                f,
32                "<component name='{}' required='{}' />",
33                item.tag_text(),
34                item.required(),
35            )?;
36            writeln!(f, "</component>")?;
37        }
38    }
39    Ok(())
40}
41
42#[derive(Clone, Debug)]
43pub(crate) enum LayoutItemKindData {
44    Component {
45        name: SmartString,
46    },
47    Group {
48        len_field_tag: u32,
49        items: Vec<LayoutItemData>,
50    },
51    Field {
52        tag: u32,
53    },
54}
55
56#[derive(Clone, Debug)]
57pub(crate) struct LayoutItemData {
58    pub(crate) required: bool,
59    pub(crate) kind: LayoutItemKindData,
60}
61
62fn layout_item_kind<'a>(item: &'a LayoutItemKindData, dict: &'a Dictionary) -> LayoutItemKind<'a> {
63    match item {
64        LayoutItemKindData::Component { name } => {
65            LayoutItemKind::Component(dict.component_by_name(name).unwrap())
66        }
67        LayoutItemKindData::Group {
68            len_field_tag,
69            items: items_data,
70        } => {
71            let items = items_data
72                .iter()
73                .map(|item_data| LayoutItem(dict, item_data))
74                .collect::<Vec<_>>();
75            let len_field = dict.field_by_tag(*len_field_tag).unwrap();
76            LayoutItemKind::Group(len_field, items)
77        }
78        LayoutItemKindData::Field { tag } => {
79            LayoutItemKind::Field(dict.field_by_tag(*tag).unwrap())
80        }
81    }
82}
83
84/// An entry in a sequence of FIX field definitions.
85#[derive(Clone, Debug)]
86pub struct LayoutItem<'a>(pub(crate) &'a Dictionary, pub(crate) &'a LayoutItemData);
87
88/// The kind of element contained in a [`Message`].
89#[derive(Debug)]
90pub enum LayoutItemKind<'a> {
91    /// This component item is another component.
92    Component(Component<'a>),
93    /// This component item is a FIX repeating group.
94    Group(Field<'a>, Vec<LayoutItem<'a>>),
95    /// This component item is a FIX field.
96    Field(Field<'a>),
97}
98
99impl<'a> LayoutItem<'a> {
100    /// Returns `true` if `self` is required in order to have a valid definition
101    /// of its parent container, `false` otherwise.
102    pub fn required(&self) -> bool {
103        self.1.required
104    }
105
106    /// Returns the [`LayoutItemKind`] of `self`.
107    pub fn kind(&self) -> LayoutItemKind<'_> {
108        layout_item_kind(&self.1.kind, self.0)
109    }
110
111    /// Returns the human-readable name of `self`.
112    pub fn tag_text(&self) -> String {
113        match &self.1.kind {
114            LayoutItemKindData::Component { name } => {
115                self.0.component_by_name(name).unwrap().name().to_string()
116            }
117            LayoutItemKindData::Group {
118                len_field_tag,
119                items: _items,
120            } => self
121                .0
122                .field_by_tag(*len_field_tag)
123                .unwrap()
124                .name()
125                .to_string(),
126            LayoutItemKindData::Field { tag } => {
127                self.0.field_by_tag(*tag).unwrap().name().to_string()
128            }
129        }
130    }
131}
132
133pub(crate) type LayoutItems = Vec<LayoutItemData>;