hotfix_dictionary/
field.rs1use crate::string::SmartString;
2use crate::{Datatype, Dictionary, FixDatatype, TagU32};
3
4pub trait IsFieldDefinition {
5 fn tag(&self) -> TagU32;
7
8 fn name(&self) -> &str;
10
11 fn location(&self) -> FieldLocation;
13}
14
15#[derive(Debug, Copy, Clone)]
20pub struct Field<'a>(&'a Dictionary, &'a FieldData);
21
22#[derive(Clone, Debug)]
25pub struct FieldData {
26 pub(crate) name: SmartString,
28 pub(crate) tag: u32,
31 pub(crate) data_type_name: SmartString,
33 pub(crate) associated_data_tag: Option<usize>,
36 pub(crate) value_restrictions: Option<Vec<FieldEnumData>>,
37 pub(crate) required: bool,
39 pub(crate) description: Option<String>,
40}
41
42#[derive(Clone, Debug)]
43pub(crate) struct FieldEnumData {
44 pub(crate) value: String,
45 pub(crate) description: String,
46}
47
48#[derive(Debug)]
51#[allow(dead_code)]
52pub struct FieldEnum<'a>(&'a Dictionary, &'a FieldEnumData);
53
54impl<'a> FieldEnum<'a> {
55 pub fn value(&self) -> &str {
57 &self.1.value[..]
58 }
59
60 pub fn description(&self) -> &str {
62 &self.1.description[..]
63 }
64}
65
66impl<'a> Field<'a> {
67 pub fn new(dictionary: &'a Dictionary, field_data: &'a FieldData) -> Self {
68 Self(dictionary, field_data)
69 }
70
71 pub fn doc_url_onixs(&self, version: &str) -> String {
72 let v = match version {
73 "FIX.4.0" => "4.0",
74 "FIX.4.1" => "4.1",
75 "FIX.4.2" => "4.2",
76 "FIX.4.3" => "4.3",
77 "FIX.4.4" => "4.4",
78 "FIX.5.0" => "5.0",
79 "FIX.5.0SP1" => "5.0.SP1",
80 "FIX.5.0SP2" => "5.0.SP2",
81 "FIXT.1.1" => "FIXT.1.1",
82 s => s,
83 };
84 format!(
85 "https://www.onixs.biz/fix-dictionary/{}/tagNum_{}.html",
86 v,
87 self.1.tag.to_string().as_str()
88 )
89 }
90
91 pub fn is_num_in_group(&self) -> bool {
92 fn nth_char_is_uppercase(s: &str, i: usize) -> bool {
93 s.chars().nth(i).map(|c| c.is_ascii_uppercase()) == Some(true)
94 }
95
96 self.fix_datatype().base_type() == FixDatatype::NumInGroup
97 || self.name().ends_with("Len")
98 || (self.name().starts_with("No") && nth_char_is_uppercase(self.name(), 2))
99 }
100
101 pub fn fix_datatype(&self) -> FixDatatype {
103 self.data_type().basetype()
104 }
105
106 pub fn name(&self) -> &str {
109 self.1.name.as_str()
110 }
111
112 pub fn tag(&self) -> TagU32 {
115 TagU32::new(self.1.tag).unwrap()
116 }
117
118 pub fn enums(&self) -> Option<impl Iterator<Item = FieldEnum<'_>>> {
121 self.1
122 .value_restrictions
123 .as_ref()
124 .map(move |v| v.iter().map(move |f| FieldEnum(self.0, f)))
125 }
126
127 pub fn data_type(&self) -> Datatype<'_> {
129 self.0
130 .datatype_by_name(self.1.data_type_name.as_str())
131 .unwrap()
132 }
133
134 pub fn data_tag(&self) -> Option<TagU32> {
135 self.1
136 .associated_data_tag
137 .map(|tag| TagU32::new(tag as u32).unwrap())
138 }
139
140 pub fn required_in_xml_messages(&self) -> bool {
141 self.1.required
142 }
143
144 pub fn description(&self) -> Option<&str> {
145 self.1.description.as_deref()
146 }
147}
148
149impl<'a> IsFieldDefinition for Field<'a> {
150 fn tag(&self) -> TagU32 {
151 TagU32::new(self.1.tag).expect("Invalid FIX tag (0)")
152 }
153
154 fn name(&self) -> &str {
155 self.1.name.as_str()
156 }
157
158 fn location(&self) -> FieldLocation {
159 FieldLocation::Body }
161}
162
163#[derive(Debug, Copy, Clone, PartialEq, Eq)]
165pub enum FieldLocation {
166 Header,
168 Body,
170 Trailer,
172}