Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions crates/hotfix-dictionary/src/builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use crate::message_definition::MessageData;
use crate::{ComponentData, DatatypeData, Dictionary, FieldData};

pub struct DictionaryBuilder {
dict: Dictionary,
}

impl DictionaryBuilder {
pub fn new<S: ToString>(version: S) -> Self {
Self {
dict: Dictionary::new(version),
}
}

pub fn dict(&self) -> &Dictionary {
&self.dict
}

pub(crate) fn add_field(&mut self, field: FieldData) {
self.dict
.field_tags_by_name
.insert(field.name.clone(), field.tag);
self.dict.fields_by_tags.insert(field.tag, field);
}

pub(crate) fn add_message(&mut self, message: MessageData) {
self.dict
.message_msgtypes_by_name
.insert(message.name.clone(), message.msg_type.clone());
self.dict
.messages_by_msgtype
.insert(message.msg_type.clone(), message);
}

pub(crate) fn add_component(&mut self, component: ComponentData) {
self.dict
.components_by_name
.insert(component.name.clone(), component);
}

pub(crate) fn add_datatype(&mut self, datatype: DatatypeData) {
self.dict
.data_types_by_name
.insert(datatype.datatype.name().into(), datatype);
}
}

impl From<DictionaryBuilder> for Dictionary {
fn from(builder: DictionaryBuilder) -> Self {
builder.dict
}
}
79 changes: 79 additions & 0 deletions crates/hotfix-dictionary/src/component.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use smartstring::alias::String as SmartString;

use crate::{Dictionary, Field, LayoutItem, LayoutItemData, LayoutItemKind};

/// A [`Component`] is an ordered collection of fields and/or other components.
/// There are two kinds of components: (1) common blocks and (2) repeating
/// groups. Common blocks are merely commonly reused sequences of the same
/// fields/components
/// which are given names for simplicity, i.e. they serve as "macros". Repeating
/// groups, on the other hand, are components which can appear zero or more times
/// inside FIX messages (or other components, for that matter).
#[derive(Clone, Debug)]
pub struct Component<'a>(pub(crate) &'a Dictionary, pub(crate) &'a ComponentData);

#[derive(Clone, Debug)]
pub(crate) struct ComponentData {
/// **Primary key.** The unique integer identifier of this component
/// type.
pub(crate) id: usize,
pub(crate) component_type: FixmlComponentAttributes,
pub(crate) layout_items: Vec<LayoutItemData>,
/// The human-readable name of the component.
pub(crate) name: SmartString,
}

impl<'a> Component<'a> {
/// Returns the unique numberic ID of `self`.
pub fn id(&self) -> u32 {
self.1.id as u32
}

/// Returns the name of `self`. The name of every [`Component`] is unique
/// across a [`Dictionary`].
pub fn name(&self) -> &str {
self.1.name.as_str()
}

/// Returns `true` if and only if `self` is a "group" component; `false`
/// otherwise.
pub fn is_group(&self) -> bool {
match self.1.component_type {
FixmlComponentAttributes::Block { is_repeating, .. } => is_repeating,
_ => false,
}
}

/// Returns an [`Iterator`] over all items that are part of `self`.
pub fn items(&self) -> impl Iterator<Item = LayoutItem<'_>> {
self.1
.layout_items
.iter()
.map(move |data| LayoutItem(self.0, data))
}

/// Checks whether `field` appears in the definition of `self` and returns
/// `true` if it does, `false` otherwise.
pub fn contains_field(&self, field: &Field) -> bool {
self.items().any(|layout_item| {
if let LayoutItemKind::Field(f) = layout_item.kind() {
f.tag() == field.tag()
} else {
false
}
})
}
}

/// Component type (FIXML-specific information).
#[derive(Clone, Debug, PartialEq)]
#[allow(dead_code)]
pub enum FixmlComponentAttributes {
Xml,
Block {
is_repeating: bool,
is_implicit: bool,
is_optimized: bool,
},
Message,
}
Loading