1use std::{ffi::CString, fmt};
2
3use quickfix_ffi::{
4 FixDictionary_delete, FixDictionary_getBool, FixDictionary_getDay, FixDictionary_getDouble,
5 FixDictionary_getInt, FixDictionary_getStringLen, FixDictionary_hasKey, FixDictionary_new,
6 FixDictionary_readString, FixDictionary_setBool, FixDictionary_setDay, FixDictionary_setDouble,
7 FixDictionary_setInt, FixDictionary_setString, FixDictionary_t,
8};
9
10use crate::{
11 utils::{ffi_code_to_bool, ffi_code_to_result},
12 DayOfWeek, ForeignPropertyGetter, ForeignPropertySetter, QuickFixError,
13};
14
15pub struct Dictionary(pub(crate) FixDictionary_t);
17
18impl Dictionary {
19 pub fn new() -> Self {
21 Self::default()
22 }
23
24 pub fn with_name(name: &str) -> Result<Self, QuickFixError> {
26 let c_name = CString::new(name)?;
27 unsafe { FixDictionary_new(c_name.as_ptr()) }
28 .map(Self)
29 .ok_or_else(QuickFixError::from_last_error)
30 }
31
32 pub fn contains(&self, key: &str) -> Result<bool, QuickFixError> {
34 let c_key = CString::new(key)?;
35 ffi_code_to_bool(unsafe { FixDictionary_hasKey(self.0, c_key.as_ptr()) })
36 }
37
38 pub fn get<T>(&self, key: &str) -> Result<T, QuickFixError>
40 where
41 Self: ForeignPropertyGetter<T>,
42 {
43 let c_key = CString::new(key)?;
44 self.ffi_get(c_key)
45 }
46
47 pub fn set<T>(&mut self, key: &str, value: T) -> Result<(), QuickFixError>
49 where
50 Self: ForeignPropertySetter<T>,
51 {
52 let c_key = CString::new(key)?;
53 self.ffi_set(c_key, value)
54 }
55}
56
57impl ForeignPropertyGetter<String> for Dictionary {
58 fn ffi_get(&self, key: CString) -> Result<String, QuickFixError> {
59 unsafe {
60 let buffer_len = FixDictionary_getStringLen(self.0, key.as_ptr())
62 .try_into()
63 .map_err(|_err| QuickFixError::from_last_error())?;
64
65 let mut buffer = vec![0_u8; buffer_len as usize];
67 assert_eq!(buffer.len(), buffer_len as usize);
68
69 ffi_code_to_result(FixDictionary_readString(
71 self.0,
72 key.as_ptr(),
73 buffer.as_mut_ptr().cast(),
74 buffer_len,
75 ))?;
76
77 let text = CString::from_vec_with_nul(buffer).unwrap_or_default();
83 Ok(text.to_string_lossy().to_string())
84 }
85 }
86}
87
88impl ForeignPropertySetter<String> for Dictionary {
89 fn ffi_set(&mut self, key: CString, value: String) -> Result<(), QuickFixError> {
90 self.ffi_set(key, value.as_str())
91 }
92}
93
94impl ForeignPropertySetter<&str> for Dictionary {
95 fn ffi_set(&mut self, key: CString, value: &str) -> Result<(), QuickFixError> {
96 let c_value = CString::new(value)?;
97 ffi_code_to_result(unsafe {
98 FixDictionary_setString(self.0, key.as_ptr(), c_value.as_ptr())
99 })
100 }
101}
102
103impl ForeignPropertyGetter<i32> for Dictionary {
104 fn ffi_get(&self, key: CString) -> Result<i32, QuickFixError> {
105 Ok(unsafe { FixDictionary_getInt(self.0, key.as_ptr()) })
106 }
107}
108
109impl ForeignPropertySetter<i32> for Dictionary {
110 fn ffi_set(&mut self, key: CString, value: i32) -> Result<(), QuickFixError> {
111 ffi_code_to_result(unsafe { FixDictionary_setInt(self.0, key.as_ptr(), value) })
112 }
113}
114
115impl ForeignPropertyGetter<f64> for Dictionary {
116 fn ffi_get(&self, key: CString) -> Result<f64, QuickFixError> {
117 Ok(unsafe { FixDictionary_getDouble(self.0, key.as_ptr()) })
118 }
119}
120
121impl ForeignPropertySetter<f64> for Dictionary {
122 fn ffi_set(&mut self, key: CString, value: f64) -> Result<(), QuickFixError> {
123 ffi_code_to_result(unsafe { FixDictionary_setDouble(self.0, key.as_ptr(), value) })
124 }
125}
126
127impl ForeignPropertyGetter<bool> for Dictionary {
128 fn ffi_get(&self, key: CString) -> Result<bool, QuickFixError> {
129 ffi_code_to_bool(unsafe { FixDictionary_getBool(self.0, key.as_ptr()) })
130 }
131}
132
133impl ForeignPropertySetter<bool> for Dictionary {
134 fn ffi_set(&mut self, key: CString, value: bool) -> Result<(), QuickFixError> {
135 ffi_code_to_result(unsafe { FixDictionary_setBool(self.0, key.as_ptr(), value as i8) })
136 }
137}
138
139impl ForeignPropertyGetter<DayOfWeek> for Dictionary {
140 fn ffi_get(&self, key: CString) -> Result<DayOfWeek, QuickFixError> {
141 DayOfWeek::try_from(unsafe { FixDictionary_getDay(self.0, key.as_ptr()) })
142 }
143}
144
145impl ForeignPropertySetter<DayOfWeek> for Dictionary {
146 fn ffi_set(&mut self, key: CString, value: DayOfWeek) -> Result<(), QuickFixError> {
147 ffi_code_to_result(unsafe { FixDictionary_setDay(self.0, key.as_ptr(), value as i32) })
148 }
149}
150
151impl fmt::Debug for Dictionary {
152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 f.debug_tuple("Dictionary").finish()
154 }
155}
156
157impl Default for Dictionary {
158 fn default() -> Self {
159 Self::with_name("").expect("Fail to allocate Dictionary")
160 }
161}
162
163impl Drop for Dictionary {
164 fn drop(&mut self) {
165 unsafe { FixDictionary_delete(self.0) }
166 }
167}