1use crate::types::LVStatusCode;
59use num_enum::{IntoPrimitive, TryFromPrimitive};
60use thiserror::Error;
61
62impl<T> From<Result<T>> for LVStatusCode {
65 fn from(value: Result<T>) -> Self {
66 match value {
67 Ok(_) => LVStatusCode::SUCCESS,
68 Err(err) => (&err).into(),
69 }
70 }
71}
72impl From<&LVInteropError> for LVStatusCode {
73 fn from(value: &LVInteropError) -> Self {
74 match value {
75 LVInteropError::LabviewMgError(e) => e.into(),
76 LVInteropError::InternalError(e) => e.into(),
77 LVInteropError::LabviewError(e) => *e,
78 }
79 }
80}
81
82impl From<LVInteropError> for LVStatusCode {
83 fn from(value: LVInteropError) -> Self {
84 (&value).into()
85 }
86}
87
88impl From<LVStatusCode> for LVInteropError {
89 fn from(status: LVStatusCode) -> Self {
90 LVInteropError::LabviewError(status)
91 }
92}
93
94#[derive(Debug, Clone, Copy, PartialEq, Eq, Error, IntoPrimitive, TryFromPrimitive)]
113#[repr(i32)]
114pub enum MgError {
115 #[error("An input parameter is invalid.")]
116 MgArgErr = 1,
117 #[error("Memory is full.")]
118 MFullErr = 2,
119 #[error("End of file encountered.")]
120 FEof = 4,
121 #[error("File already open")]
122 FIsOpen = 5,
123 #[error("Generic file I/O error.")]
124 FIoErr = 6,
125 #[error("File not found")]
126 FNotFound = 7,
127 #[error("File permission error.")]
128 FNoPerm = 8,
129 #[error("Disk full")]
130 FDiskFull = 9,
131 #[error("Duplicate path")]
132 FDupPath = 10,
133 #[error("Too many files open.")]
134 FtMFOpen = 11,
135 #[error("Some system capacity necessary for operation is not enabled.")]
136 FNotEnabled = 12,
137 #[error(
138 "Failed to load dynamic library because of missing external symbols or dependencies, or because of an invalid file format."
139 )]
140 RfNotFound = 13,
141 #[error("Cannot add resource.")]
142 RAddFailed = 14,
143 #[error("Resource not found.")]
144 RNotFound = 15,
145 #[error("Image not found.")]
146 INotFound = 16,
147 #[error("Not enough memory to manipulate image.")]
148 IMemoryErr = 17,
149 #[error("DPen does not exist.")]
150 DPenNotExist = 18,
151 #[error("Configuration type invalid.")]
152 CfgBadType = 19,
153 #[error("Configuration token not found.")]
154 CfgTokenNotFound = 20,
155 #[error("Error occurred parsing configuration string.")]
156 CfgParseError = 21,
157 #[error("Configuration memory error.")]
158 CfgAllocError = 22,
159 #[error("Bad external code format.")]
160 EcLVSBFormatError = 23,
161 #[error("External subroutine not supported.")]
162 EcLVSBSubrError = 24,
163 #[error("External code not present.")]
164 EcLVSBNoCodeError = 25,
165 #[error("Null window.")]
166 WNullWindow = 26,
167 #[error("Destroy window error.")]
168 WDestroyMixup = 27,
169 #[error("Null menu.")]
170 MenuNullMenu = 28,
171 #[error("Print aborted")]
172 PAbortJob = 29,
173 #[error("Bad print record.")]
174 PBadPrintRecord = 30,
175 #[error("Print driver error.")]
176 PDriverError = 31,
177 #[error("Operating system error during print.")]
178 PWindowsError = 32,
179 #[error("Memory error during print.")]
180 PMemoryError = 33,
181 #[error("Print dialog error.")]
182 PDialogError = 34,
183 #[error("Generic print error.")]
184 PMiscError = 35,
185 #[error("Invalid device refnum.")]
186 DvInvalidRefnum = 36,
187 #[error("Device not found.")]
188 DvDeviceNotFound = 37,
189 #[error("Device parameter error.")]
190 DvParamErr = 38,
191 #[error("Device unit error.")]
192 DvUnitErr = 39,
193 #[error("Cannot open device.")]
194 DvOpenErr = 40,
195 #[error("Device call aborted.")]
196 DvAbortErr = 41,
197 #[error("Generic error.")]
198 BogusError = 42,
199 #[error("Operation cancelled by user.")]
200 CancelError = 43,
201 #[error("Object ID too low.")]
202 OMObjLowErr = 44,
203 #[error("Object ID too high.")]
204 OMObjHiErr = 45,
205 #[error("Object not in heap.")]
206 OMObjNotInHeapErr = 46,
207 #[error("Unknown heap.")]
208 OMOHeapNotKnownErr = 47,
209 #[error("Unknown object (invalid DefProc).")]
210 OMBadDPIdErr = 48,
211 #[error("Unknown object (DefProc not in table).")]
212 OMNoDPinTabErr = 49,
213 #[error("Message out of range.")]
214 OMMsgOutOfRangeErr = 50,
215 #[error("Null method.")]
216 OMMethodNullErr = 51,
217 #[error("Unknown message.")]
218 OMUnknownMsgErr = 52,
219 #[error("Manager call not supported.")]
220 MgNotSupported = 53,
221 #[error("The network address is ill-formed.")]
222 NcBadAddressErr = 54,
223 #[error("The network operation is in progress.")]
224 NcInProgress = 55,
225 #[error("The network operation exceeded the user-specified or system time limit.")]
226 NcTimeOutErr = 56,
227 #[error("The network connection is busy.")]
228 NcBusyErr = 57,
229 #[error("The network function is not supported by the system.")]
230 NcNotSupportedErr = 58,
231 #[error("The network is down, unreachable, or has been reset.")]
232 NcNetErr = 59,
233 #[error(
234 "The specified port or network address is currently in use. Select an available port or network address."
235 )]
236 NcAddrInUseErr = 60,
237 #[error("The system could not allocate the necessary memory.")]
238 NcSysOutOfMem = 61,
239 #[error("The system caused the network connection to be aborted.")]
240 NcSysConnAbortedErr = 62,
241 #[error("The network connection was refused by the server.")]
242 NcConnRefusedErr = 63,
243 #[error("The network connection is not yet established.")]
244 NcNotConnectedErr = 64,
245 #[error("The network connection is already established.")]
246 NcAlreadyConnectedErr = 65,
247 #[error("The network connection was closed by the peer.")]
248 NcConnClosedErr = 66,
249 #[error("Interapplication Manager initialization error.")]
250 AmInitErr = 67,
251 #[error("Bad occurrence.")]
252 OccBadOccurrenceErr = 68,
253 #[error("Handler does not know what occurrence to wait for.")]
254 OccWaitOnUnBoundHdlrErr = 69,
255 #[error("Occurrence queue overflow.")]
256 OccFunnyQOverFlowErr = 70,
257 #[error("File datalog type conflict.")]
258 FDataLogTypeConflict = 71,
259 #[error("Semaphore not signaled.")]
260 EcLVSBCannotBeCalledFromThread = 72,
261 #[error("Interapplication Manager unrecognized type error.")]
262 AmUnrecognizedType = 73,
263 #[error("Memory or data structure corrupt.")]
264 MCorruptErr = 74,
265 #[error("Failed to make temporary DLL.")]
266 EcLVSBErrorMakingTempDLL = 75,
267 #[error("Old CIN version.")]
268 EcLVSBOldCIN = 76,
269 #[error("Format specifier type mismatch.")]
270 FmtTypeMismatch = 81,
271 #[error("Unknown format specifier.")]
272 FmtUnknownConversion = 82,
273 #[error("Too few format specifiers.")]
274 FmtTooFew = 83,
275 #[error("Too many format specifiers.")]
276 FmtTooMany = 84,
277 #[error("Scan failed. The input string does not contain data in the expected format.")]
278 FmtScanError = 85,
279 #[error("Error converting to variant.")]
280 LvOLEConvertErr = 87,
281 #[error("Run-time menu error.")]
282 RtMenuErr = 88,
283 #[error("Another user tampered with the VI password.")]
284 PwdTampered = 89,
285 #[error("Variant attribute not found.")]
286 LvVariantAttrNotFound = 90,
287 #[error(
288 "The data type of the variant is not compatible with the data type wired to the type input."
289 )]
290 LvVariantTypeMismatch = 91,
291 #[error("The ActiveX event data was not available on the queue.")]
292 AxEventDataNotAvailable = 92,
293 #[error("ActiveX event information was not available.")]
294 AxEventStoreNotPresent = 93,
295 #[error("The occurrence associated with the ActiveX event was not found.")]
296 AxOccurrenceNotFound = 94,
297 #[error("The ActiveX event queue could not be created.")]
298 AxEventQueueNotCreated = 95,
299 #[error("ActiveX event information was not available in the type library.")]
300 AxEventInfoNotAvailable = 96,
301 #[error("A null or previously deleted refnum was passed in as an input.")]
302 OleNullRefnumPassed = 97,
303 #[error("IVI invalid downcast.")]
304 IviInvalidDowncast = 102,
305 #[error("No IVI class session opened.")]
306 IviInvalidClassSesn = 103,
307 #[error("Singlecast connections cannot send to multicast addresses.")]
308 NcSockNotMulticast = 108,
309 #[error("Multicast connections cannot send to singlecast addresses.")]
310 NcSockNotSinglecast = 109,
311 #[error("Specified IP address is not in multicast address range.")]
312 NcBadMulticastAddr = 110,
313 #[error("Cannot write to read-only multicast connection.")]
314 NcMcastSockReadOnly = 111,
315 #[error("Cannot read from write-only multicast connection.")]
316 NcMcastSockWriteOnly = 112,
317 #[error(
318 "A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram was smaller than the datagram itself."
319 )]
320 NcDatagramMsgSzErr = 113,
321 #[error(
322 "Unflatten or byte stream read operation failed due to corrupt, unexpected, or truncated data."
323 )]
324 DataCorruptErr = 116,
325 #[error(
326 "Directory path supplied where a file path is required. A file path with the filename is required, but the supplied path is a path to a directory."
327 )]
328 RequireFullPathErr = 117,
329 #[error("The supplied folder path does not exist.")]
330 FolderNotExistErr = 118,
331 #[error("Illegal combination of Bluetooth discoverable and non-connectable modes.")]
332 NcBtInvalidModeErr = 119,
333 #[error("Error setting Bluetooth mode.")]
334 NcBtSetModeErr = 120,
335 #[error("Invalid GUID string.")]
336 MgBtInvalidGUIDStrErr = 121,
337 #[error(
338 "The resource you are attempting to open was created in a more recent version of LabVIEW and is incompatible with this version."
339 )]
340 RVersInFuture = 122,
341}
342
343impl TryFrom<LVStatusCode> for MgError {
344 type Error = LVInteropError;
345 fn try_from(status: LVStatusCode) -> ::core::result::Result<Self, Self::Error> {
346 if status == LVStatusCode::SUCCESS {
348 return Err(InternalError::InvalidMgErrorCode.into());
349 }
350 match MgError::try_from_primitive(status.into()) {
351 Ok(code) => Ok(code),
352 Err(_) => Err(InternalError::InvalidMgErrorCode.into()),
353 }
354 }
355}
356
357impl From<&MgError> for LVStatusCode {
358 fn from(errcode: &MgError) -> LVStatusCode {
359 let erri32: i32 = *errcode as i32;
360 erri32.into()
361 }
362}
363
364impl From<MgError> for LVStatusCode {
365 fn from(errcode: MgError) -> LVStatusCode {
366 (&errcode).into()
367 }
368}
369
370#[derive(Error, Debug, Clone, PartialEq)]
398#[repr(i32)]
399pub enum InternalError {
400 #[error("LabVIEW Interop General Error. Probably because of a missing implementation.")]
401 Misc = 542_000,
402 #[error("LabVIEW API unavailable. Probably because it isn't being run in LabVIEW. Source Error: {0}")]
403 NoLabviewApi(String) = 542_001,
404 #[error("Invalid handle when valid handle is required")]
405 InvalidHandle = 542_002,
406 #[error("LabVIEW arrays can only have dimensions of i32 range.")]
407 ArrayDimensionsOutOfRange = 542_003,
408 #[error(
409 "Array dimensions don't match. You may require the link feature to enable auto-resizing."
410 )]
411 ArrayDimensionMismatch = 542_004,
412 #[error("Creating of handle in LabVIEW memory manager failed. Perhaps you are out of memory?")]
413 HandleCreationFailed = 542_005,
414 #[error("Invalid numeric status code for conversion into enumerated error code")]
415 InvalidMgErrorCode = 542_006,
416}
417
418impl From<&InternalError> for LVStatusCode {
419 fn from(err: &InternalError) -> LVStatusCode {
420 let err_i32: i32 = match err {
421 InternalError::Misc => 542_000,
422 InternalError::NoLabviewApi(_) => 542_001,
423 InternalError::InvalidHandle => 542_002,
424 InternalError::ArrayDimensionsOutOfRange => 542_003,
425 InternalError::ArrayDimensionMismatch => 542_004,
426 InternalError::HandleCreationFailed => 542_005,
427 InternalError::InvalidMgErrorCode => 542_006,
428 };
429 err_i32.into()
430 }
431}
432#[derive(Error, Debug, Clone, PartialEq)]
433pub enum LVInteropError {
434 #[error("Internal LabVIEW Manager Error: {0}")]
435 LabviewMgError(#[from] MgError),
436 #[error("Internal Error: {0}")]
437 InternalError(#[from] InternalError),
438 #[error("LabVIEW Error: {0}")]
439 LabviewError(LVStatusCode),
440}
441
442pub type Result<T> = std::result::Result<T, LVInteropError>;
443
444#[cfg(test)]
445mod tests {
446 use super::*;
447
448 #[test]
449 fn test_error_lvstatuscode_from_mgerror() {
450 let err = MgError::BogusError;
451 let status: LVStatusCode = err.into();
452
453 assert_eq!(LVStatusCode::from(42), status)
454 }
455
456 #[test]
457 fn test_error_lvinteroperror_from_lvstatuscode() {
458 let status = LVStatusCode::from(42);
459 let mg_err = MgError::try_from(status).unwrap();
460
461 let expected_code: LVStatusCode = 42.into();
462 assert_eq!(expected_code, mg_err.into());
463 }
464
465 #[test]
466 fn test_error_lvstatuscode_from_lvinteroperror() {
467 let err: LVInteropError = MgError::BogusError.into();
468 let status: LVStatusCode = LVStatusCode::from(42);
469 assert_eq!(status, err.into());
470
471 let err: LVInteropError =
472 InternalError::NoLabviewApi("Test Inner message".to_string()).into();
473 let status: LVStatusCode = LVStatusCode::from(542_001);
474
475 println!("{}", status);
476 assert_eq!(status, err.into());
477
478 }
485}