1use ni_syscfg_sys::*;
2use std::ffi::CString;
3use std::time::Duration;
4
5use crate::error::{api_status, Result};
6use crate::experts::ExpertType;
7use crate::handles::close_handle;
8use crate::hardware_filter::{FilterMode, HardwareFilter};
9use crate::parameters::ApiBool;
10use crate::resources::HardwareResourceList;
11
12#[repr(i32)]
13#[derive(Clone, Copy, Debug)]
14pub enum Locale {
15 Default = NISysCfgLocale_NISysCfgLocaleDefault,
16 ChineseSimplified = NISysCfgLocale_NISysCfgLocaleChineseSimplified,
17 English = NISysCfgLocale_NISysCfgLocaleEnglish,
18 French = NISysCfgLocale_NISysCfgLocaleFrench,
19 German = NISysCfgLocale_NISysCfgLocaleGerman,
20 Japanese = NISysCfgLocale_NISysCfgLocaleJapanese,
21 Korean = NISysCfgLocale_NISysCfgLocaleKorean,
22}
23
24pub struct SessionConfig<'a> {
25 target: &'a str,
26 username: Option<CString>,
27 password: Option<CString>,
28 locale: Locale,
29 force_refresh: bool,
30 timeout: Duration,
31}
32
33impl<'a> SessionConfig<'a> {
34 pub fn new() -> Self {
35 Self {
36 target: "",
37 username: None,
38 password: None,
39 locale: Locale::Default,
40 force_refresh: false,
41 timeout: Duration::from_secs(1),
42 }
43 }
44
45 pub fn target(mut self, target: &'a str) -> Self {
46 self.target = target;
47 self
48 }
49
50 pub fn username(mut self, username: &str) -> Result<Self> {
51 self.username = Some(CString::new(username)?);
52 Ok(self)
53 }
54
55 pub fn password(mut self, password: &str) -> Result<Self> {
56 self.password = Some(CString::new(password)?);
57 Ok(self)
58 }
59
60 pub fn locale(mut self, locale: Locale) -> Self {
61 self.locale = locale;
62 self
63 }
64
65 pub fn force_refresh(mut self, force_refresh: bool) -> Self {
66 self.force_refresh = force_refresh;
67 self
68 }
69
70 pub fn timeout(mut self, timeout: Duration) -> Self {
71 self.timeout = timeout;
72 self
73 }
74
75 pub fn connect(&self) -> Result<Session> {
76 fn optional_cstring_to_ptr(input: &Option<CString>) -> *const i8 {
77 if let Some(inner) = input {
78 inner.as_ptr()
79 } else {
80 std::ptr::null()
81 }
82 }
83
84 let mut handle: NISysCfgSessionHandle = std::ptr::null_mut();
85
86 let username = optional_cstring_to_ptr(&self.username);
87
88 let password = optional_cstring_to_ptr(&self.password);
89
90 unsafe {
91 api_status(NISysCfgInitializeSession(
92 CString::new(self.target)?.as_ptr(),
93 username,
94 password,
95 self.locale as NISysCfgLocale,
96 ApiBool::from(self.force_refresh) as NISysCfgBool,
97 self.timeout.as_millis() as u32,
98 std::ptr::null_mut(),
99 &mut handle,
100 ))?;
101 }
102
103 Ok(Session::new_from_handle(handle))
104 }
105}
106
107pub struct Session {
112 handle: NISysCfgSessionHandle,
113}
114
115impl Session {
116 fn new_from_handle(handle: NISysCfgSessionHandle) -> Self {
117 Self { handle }
118 }
119
120 pub(crate) fn handle(&self) -> &NISysCfgSessionHandle {
121 &self.handle
122 }
123
124 pub fn create_filter(&self) -> Result<HardwareFilter> {
126 HardwareFilter::new(&self)
127 }
128
129 pub fn find_hardware(
169 &self,
170 filtering: Option<&HardwareFilter>,
171 experts: Option<&[ExpertType]>,
172 ) -> Result<HardwareResourceList> {
173 let mut list_handle: NISysCfgEnumResourceHandle = std::ptr::null_mut();
174
175 let (filter_mode, filter_handle) = if let Some(filter) = filtering {
176 (filter.mode(), filter.handle())
177 } else {
178 (
179 FilterMode::MatchValuesAll,
180 std::ptr::null_mut() as NISysCfgFilterHandle,
181 )
182 };
183
184 let expert_list = if let Some(list) = experts {
185 expert_list_to_text(list)?
186 } else {
187 CString::new("")?
188 };
189
190 unsafe {
191 api_status(NISysCfgFindHardware(
192 self.handle,
193 filter_mode as i32,
194 filter_handle,
195 expert_list.as_ptr(),
196 &mut list_handle,
197 ))?;
198 }
199
200 Ok(HardwareResourceList::from_handle(list_handle, self))
201 }
202}
203
204fn expert_list_to_text(list: &[ExpertType]) -> Result<CString> {
206 let list_string = list
207 .iter()
208 .map(|ex| ex.to_programmatic_string())
209 .collect::<Vec<String>>()
210 .join(",");
211 Ok(CString::new(list_string)?)
212}
213
214impl Drop for Session {
215 fn drop(&mut self) {
216 let _ = close_handle(self.handle);
217 }
218}
219
220#[cfg(test)]
221mod tests {
222
223 use super::*;
224
225 #[test]
226 fn expert_list_to_string() {
227 let list = vec![
229 ExpertType::Unknown("test1".to_string()),
230 ExpertType::Unknown("test2".to_string()),
231 ];
232
233 let result = expert_list_to_text(&list).unwrap();
234
235 assert_eq!(result.to_str().unwrap(), "test1,test2");
236 }
237
238 #[test]
239 fn expert_list_to_string_single() {
240 let list = vec![ExpertType::Unknown("test1".to_string())];
242
243 let result = expert_list_to_text(&list).unwrap();
244
245 assert_eq!(result.to_str().unwrap(), "test1");
246 }
247
248 #[test]
249 fn expert_list_to_string_empty() {
250 let list = vec![];
252
253 let result = expert_list_to_text(&list).unwrap();
254
255 assert_eq!(result.to_str().unwrap(), "");
256 }
257}