rustyfix_dictionary/
builder.rs

1//! A builder API for creating a [`Dictionary`] from scratch.
2
3use crate::{Dictionary, FixDatatype, FixmlComponentAttributes};
4use smartstring::alias::String as SmartString;
5
6/// A public API for building a [`Dictionary`] from scratch.
7///
8/// It's better to normally rely on safe wrappers around this builder, such as
9/// [`Dictionary::from_quickfix_spec`]. This builder is nonetheless useful if
10/// you're building a [`Dictionary`] from some custom format.
11///
12/// # Warning
13/// [`DictionaryBuilder`] tries its best to enforce data consistency and
14/// correctness rules for the dictionaries it builds, but you shouldn't rely on
15/// it to catch all possible errors. Make sure the dictionaries you build are
16/// correct and consistent.
17pub struct DictionaryBuilder {
18    dict: Dictionary,
19}
20
21/// Builder utilities
22impl DictionaryBuilder {
23    pub fn new(dict: Dictionary) -> Self {
24        DictionaryBuilder { dict }
25    }
26
27    /// Returns the underlying [`Dictionary`] currently being built.
28    pub fn dict(&self) -> &Dictionary {
29        &self.dict
30    }
31
32    /// Returns the finished [`Dictionary`].
33    pub fn build(self) -> Dictionary {
34        self.dict
35    }
36
37    pub fn add_field(&mut self, field: FieldData) {
38        self.dict
39            .field_tags_by_name
40            .insert(field.name.clone(), field.tag);
41        self.dict.fields_by_tags.insert(field.tag, field);
42    }
43
44    pub fn add_message(&mut self, message: MessageData) {
45        self.dict
46            .message_msgtypes_by_name
47            .insert(message.name.clone(), message.msg_type.clone());
48        self.dict
49            .messages_by_msgtype
50            .insert(message.msg_type.clone(), message);
51    }
52
53    pub fn add_component(&mut self, component: ComponentData) {
54        self.dict
55            .components_by_name
56            .insert(component.name.clone(), component);
57    }
58
59    pub fn add_datatype(&mut self, datatype: DatatypeData) {
60        self.dict
61            .data_types_by_name
62            .insert(datatype.datatype.name().into(), datatype);
63    }
64
65    pub fn add_category(&mut self, category: CategoryData) {
66        self.dict
67            .categories_by_name
68            .insert(category.name.clone().into(), category);
69    }
70}
71
72/// A field is identified by a unique tag number and a name. Each field in a
73/// message is associated with a value.
74#[derive(Clone, Debug)]
75pub struct FieldData {
76    /// A human readable string representing the name of the field.
77    pub name: SmartString,
78    /// **Primary key.** A positive integer representing the unique
79    /// identifier for this field type.
80    pub tag: u32,
81    /// The datatype of the field.
82    pub data_type_name: SmartString,
83    /// The associated data field. If given, this field represents the length of
84    /// the referenced data field
85    pub associated_data_tag: Option<usize>,
86    pub value_restrictions: Option<Vec<FieldEnumData>>,
87    /// Abbreviated form of the Name, typically to specify the element name when
88    /// the field is used in an XML message. Can be overridden by BaseCategory /
89    /// BaseCategoryAbbrName.
90    pub abbr_name: Option<String>,
91    /// Specifies the base message category when field is used in an XML message.
92    pub base_category_id: Option<usize>,
93    /// If BaseCategory is specified, this is the XML element identifier to use
94    /// for this field, overriding AbbrName.
95    pub base_category_abbr_name: Option<String>,
96    /// Indicates whether the field is required in an XML message.
97    pub required: bool,
98    pub description: Option<String>,
99}
100
101#[derive(Clone, Debug)]
102pub struct CategoryData {
103    /// **Primary key**. A string uniquely identifying this category.
104    pub name: String,
105    /// The FIXML file name for a Category.
106    pub fixml_filename: String,
107}
108
109#[derive(Clone, Debug, PartialEq)]
110pub struct DatatypeData {
111    /// **Primary key.** Identifier of the datatype.
112    pub datatype: FixDatatype,
113    /// Human readable description of this Datatype.
114    pub description: String,
115    /// A string that contains examples values for a datatype
116    pub examples: Vec<String>,
117    // TODO: 'XML'.
118}
119
120#[derive(Clone, Debug)]
121pub struct AbbreviationData {
122    pub abbreviation: SmartString,
123    pub is_last: bool,
124}
125
126#[derive(Clone, Debug)]
127pub struct ComponentData {
128    /// **Primary key.** The unique integer identifier of this component
129    /// type.
130    pub id: usize,
131    pub component_type: FixmlComponentAttributes,
132    pub layout_items: Vec<LayoutItemData>,
133    pub category_name: SmartString,
134    /// The human readable name of the component.
135    pub name: SmartString,
136    /// The name for this component when used in an XML context.
137    pub abbr_name: Option<SmartString>,
138}
139
140#[derive(Clone, Debug)]
141#[allow(dead_code)]
142pub enum LayoutItemKindData {
143    Component {
144        name: SmartString,
145    },
146    Group {
147        len_field_tag: u32,
148        items: Vec<LayoutItemData>,
149    },
150    Field {
151        tag: u32,
152    },
153}
154
155#[derive(Clone, Debug)]
156pub struct LayoutItemData {
157    pub required: bool,
158    pub kind: LayoutItemKindData,
159}
160
161#[derive(Clone, Debug)]
162pub struct MessageData {
163    /// The unique integer identifier of this message type.
164    pub component_id: u32,
165    /// **Primary key**. The unique character identifier of this message
166    /// type; used literally in FIX messages.
167    pub msg_type: SmartString,
168    /// The name of this message type.
169    pub name: SmartString,
170    /// Identifier of the category to which this message belongs.
171    pub category_name: SmartString,
172    /// Identifier of the section to which this message belongs.
173    pub section_id: String,
174    pub layout_items: Vec<LayoutItemData>,
175    /// The abbreviated name of this message, when used in an XML context.
176    pub abbr_name: Option<SmartString>,
177    /// A boolean used to indicate if the message is to be generated as part
178    /// of FIXML.
179    pub required: bool,
180    pub description: String,
181    pub elaboration: Option<String>,
182}
183
184#[derive(Clone, Debug)]
185pub struct FieldEnumData {
186    pub value: String,
187    pub description: String,
188}