rustyfix_dictionary/
builder.rs

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