1#![allow(deprecated)]
2
3use std::{ffi::NulError, fmt};
4
5use singe_cuda::error::Error as CudaError;
6use singe_npp_sys as sys;
7use thiserror::Error;
8
9use crate::types::Size;
10
11macro_rules! npp_statuses {
12 ($($variant:ident => $raw:ident,)*) => {
13 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14 #[non_exhaustive]
15 pub enum Status {
16 $($variant,)*
17 Unknown(i32),
18 }
19
20 impl Status {
21 pub fn description(self) -> String {
22 match sys::NppStatus::try_from(self.raw()) {
23 Ok(status) => format!("{status:?}")
24 .trim_start_matches("NPP_")
25 .replace('_', " ")
26 .to_ascii_lowercase(),
27 Err(_) => String::from("unknown npp error"),
28 }
29 }
30
31 pub const fn raw(self) -> i32 {
32 match self {
33 $(Self::$variant => sys::NppStatus::$raw as _,)*
34 Self::Unknown(code) => code,
35 }
36 }
37 }
38
39 impl TryFrom<i32> for Status {
40 type Error = i32;
41
42 fn try_from(code: i32) -> std::result::Result<Self, i32> {
43 match code {
44 $(code if code == sys::NppStatus::$raw as i32 => Ok(Self::$variant),)*
45 code => Err(code),
46 }
47 }
48 }
49
50 impl From<sys::NppStatus> for Status {
51 fn from(status: sys::NppStatus) -> Self {
52 Self::try_from(status as i32).unwrap_or_else(Self::Unknown)
53 }
54 }
55
56 impl TryFrom<Status> for sys::NppStatus {
57 type Error = Status;
58
59 fn try_from(status: Status) -> std::result::Result<Self, Status> {
60 match status {
61 $(Status::$variant => Ok(Self::$raw),)*
62 Status::Unknown(_) => Err(status),
63 }
64 }
65 }
66
67 impl fmt::Display for Status {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 match self {
70 $(Self::$variant => f.write_str(stringify!($raw)),)*
71 Self::Unknown(code) => write!(f, "UNKNOWN_NPP_STATUS({code})"),
72 }
73 }
74 }
75 };
76}
77
78npp_statuses! {
79 Success => NPP_SUCCESS,
80 NotSupportedModeError => NPP_NOT_SUPPORTED_MODE_ERROR,
81 LibraryVersionMismatchError => NPP_LIBRARY_VERSION_MISMATCH_ERROR,
82 InvalidHostPointerError => NPP_INVALID_HOST_POINTER_ERROR,
83 InvalidDevicePointerError => NPP_INVALID_DEVICE_POINTER_ERROR,
84 LutPaletteBitsizeError => NPP_LUT_PALETTE_BITSIZE_ERROR,
85 ZeroCrossingModeNotSupportedError => NPP_ZC_MODE_NOT_SUPPORTED_ERROR,
86 NotSufficientComputeCapability => NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY,
87 TextureBindError => NPP_TEXTURE_BIND_ERROR,
88 WrongIntersectionRoiError => NPP_WRONG_INTERSECTION_ROI_ERROR,
89 HaarClassifierPixelMatchError => NPP_HAAR_CLASSIFIER_PIXEL_MATCH_ERROR,
90 MemfreeError => NPP_MEMFREE_ERROR,
91 MemsetError => NPP_MEMSET_ERROR,
92 MemcpyError => NPP_MEMCPY_ERROR,
93 AlignmentError => NPP_ALIGNMENT_ERROR,
94 CudaKernelExecutionError => NPP_CUDA_KERNEL_EXECUTION_ERROR,
95 StreamContextError => NPP_STREAM_CTX_ERROR,
96 RoundModeNotSupportedError => NPP_ROUND_MODE_NOT_SUPPORTED_ERROR,
97 QualityIndexError => NPP_QUALITY_INDEX_ERROR,
98 ResizeNoOperationError => NPP_RESIZE_NO_OPERATION_ERROR,
99 OverflowError => NPP_OVERFLOW_ERROR,
100 NotEvenStepError => NPP_NOT_EVEN_STEP_ERROR,
101 HistogramNumberOfLevelsError => NPP_HISTOGRAM_NUMBER_OF_LEVELS_ERROR,
102 LutNumberOfLevelsError => NPP_LUT_NUMBER_OF_LEVELS_ERROR,
103 CorruptedDataError => NPP_CORRUPTED_DATA_ERROR,
104 ChannelOrderError => NPP_CHANNEL_ORDER_ERROR,
105 ZeroMaskValueError => NPP_ZERO_MASK_VALUE_ERROR,
106 QuadrangleError => NPP_QUADRANGLE_ERROR,
107 RectangleError => NPP_RECTANGLE_ERROR,
108 CoefficientError => NPP_COEFFICIENT_ERROR,
109 NumberOfChannelsError => NPP_NUMBER_OF_CHANNELS_ERROR,
110 ChannelOfInterestError => NPP_COI_ERROR,
111 DivisorError => NPP_DIVISOR_ERROR,
112 ChannelError => NPP_CHANNEL_ERROR,
113 StrideError => NPP_STRIDE_ERROR,
114 ResizeFactorError => NPP_RESIZE_FACTOR_ERROR,
115 InterpolationError => NPP_INTERPOLATION_ERROR,
116 MirrorFlipError => NPP_MIRROR_FLIP_ERROR,
117 BadArgumentError => NPP_BAD_ARGUMENT_ERROR,
118 NoMemoryError => NPP_NO_MEMORY_ERROR,
119 NotImplementedError => NPP_NOT_IMPLEMENTED_ERROR,
120 Error => NPP_ERROR,
121 ErrorReserved => NPP_ERROR_RESERVED,
122 NullPointerError => NPP_NULL_POINTER_ERROR,
123 RangeError => NPP_RANGE_ERROR,
124 SizeError => NPP_SIZE_ERROR,
125 StepError => NPP_STEP_ERROR,
126 AnchorError => NPP_ANCHOR_ERROR,
127 MaskSizeError => NPP_MASK_SIZE_ERROR,
128 Moment00ZeroError => NPP_MOMENT_00_ZERO_ERROR,
129 ThresholdNegativeLevelError => NPP_THRESHOLD_NEGATIVE_LEVEL_ERROR,
130 ThresholdError => NPP_THRESHOLD_ERROR,
131 ContextMatchError => NPP_CONTEXT_MATCH_ERROR,
132 FftFlagError => NPP_FFT_FLAG_ERROR,
133 FftOrderError => NPP_FFT_ORDER_ERROR,
134 ScaleRangeError => NPP_SCALE_RANGE_ERROR,
135 DataTypeError => NPP_DATA_TYPE_ERROR,
136 OutOfRangeError => NPP_OUT_OFF_RANGE_ERROR,
137 DivideByZeroError => NPP_DIVIDE_BY_ZERO_ERROR,
138 MemoryAllocationErr => NPP_MEMORY_ALLOCATION_ERR,
139 NoOperationWarning => NPP_NO_OPERATION_WARNING,
140 DivideByZeroWarning => NPP_DIVIDE_BY_ZERO_WARNING,
141 AffineQuadIncorrectWarning => NPP_AFFINE_QUAD_INCORRECT_WARNING,
142 WrongIntersectionRoiWarning => NPP_WRONG_INTERSECTION_ROI_WARNING,
143 WrongIntersectionQuadWarning => NPP_WRONG_INTERSECTION_QUAD_WARNING,
144 DoubleSizeWarning => NPP_DOUBLE_SIZE_WARNING,
145 MisalignedDstRoiWarning => NPP_MISALIGNED_DST_ROI_WARNING,
146}
147
148#[derive(Error, Debug)]
149#[non_exhaustive]
150pub enum Error {
151 #[error("cuda error: {0}")]
152 Cuda(#[from] CudaError),
153
154 #[error("npp error ({code}): {message}")]
155 Npp { code: Status, message: String },
156
157 #[error("string contains interior nul byte")]
158 InteriorNul,
159
160 #[error("unexpected null handle")]
161 NullHandle,
162
163 #[error("`{name}` is out of range")]
164 OutOfRange { name: String },
165
166 #[error("`{name}` must be greater than 0")]
167 ValueNotPositive { name: String },
168
169 #[error("`{name}` length mismatch (expected {expected}, got {actual})")]
170 LengthMismatch {
171 name: String,
172 expected: usize,
173 actual: usize,
174 },
175
176 #[error("`{name}` size mismatch (expected {expected}, got {actual})")]
177 SizeMismatch {
178 name: String,
179 expected: Size,
180 actual: Size,
181 },
182
183 #[error("stream belongs to a different cuda context")]
184 StreamContextMismatch,
185
186 #[error("unsupported operation: `{name}`")]
187 UnsupportedOperation { name: String },
188
189 #[error("missing required parameter: `{name}`")]
190 MissingParameter { name: String },
191}
192
193pub type Result<T> = std::result::Result<T, Error>;
194
195impl From<sys::NppStatus> for Error {
196 fn from(status: sys::NppStatus) -> Self {
197 let code = Status::from(status);
198 Self::from(code)
199 }
200}
201
202impl From<Status> for Error {
203 fn from(code: Status) -> Self {
204 Self::Npp {
205 code,
206 message: code.description(),
207 }
208 }
209}
210
211impl From<NulError> for Error {
212 fn from(_: NulError) -> Self {
213 Self::InteriorNul
214 }
215}
216
217#[macro_export]
218macro_rules! try_ffi {
219 ($expr:expr) => {{
220 let status = { $expr };
221 if status != singe_npp_sys::NppStatus::NPP_SUCCESS {
222 Err($crate::error::Error::from(status))
223 } else {
224 Ok(())
225 }
226 }};
227}