1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
use blaze_proc::error;
use std::{
    fmt::{Debug, Display},
    sync::Arc,
};

pub type Result<T> = ::core::result::Result<T, Error>;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ErrorCode {
    Kind(ErrorKind),
    Unknown(i32),
}

impl ErrorCode {
    #[inline(always)]
    pub const fn as_i32(self) -> i32 {
        return match self {
            Self::Kind(x) => x as i32,
            Self::Unknown(x) => x,
        };
    }

    #[inline]
    pub fn try_into_known(&mut self) -> Option<ErrorKind> {
        match *self {
            Self::Kind(x) => Some(x),
            Self::Unknown(id) => match ErrorKind::try_from(id) {
                Ok(x) => {
                    *self = Self::Kind(x);
                    return Some(x);
                }
                Err(_) => return None,
            },
        }
    }
}

impl From<ErrorKind> for ErrorCode {
    #[inline(always)]
    fn from(x: ErrorKind) -> Self {
        Self::Kind(x)
    }
}

impl From<i32> for ErrorCode {
    #[inline(always)]
    fn from(x: i32) -> Self {
        ErrorKind::try_from(x).into()
    }
}

impl From<::core::result::Result<ErrorKind, i32>> for ErrorCode {
    #[inline(always)]
    fn from(x: ::core::result::Result<ErrorKind, i32>) -> Self {
        match x {
            Ok(x) => Self::Kind(x),
            Err(e) => Self::Unknown(e),
        }
    }
}

#[derive(Clone)]
#[non_exhaustive]
pub struct Error {
    pub ty: ErrorCode,
    pub desc: Option<Arc<dyn Send + Sync + Display>>,
}

impl Error {
    #[inline(always)]
    pub fn new<D: 'static + Send + Sync + Display>(ty: impl Into<ErrorCode>, desc: D) -> Self {
        Self::from_parts(ty, Some(Arc::new(desc)))
    }

    #[inline(always)]
    pub fn from_parts(
        ty: impl Into<ErrorCode>,
        desc: Option<Arc<dyn Send + Sync + Display>>,
    ) -> Self {
        Self {
            ty: ty.into(),
            desc,
        }
    }

    #[inline(always)]
    pub fn from_type(ty: impl Into<ErrorCode>) -> Self {
        Self {
            ty: ty.into(),
            desc: None,
        }
    }

    #[inline(always)]
    pub fn as_i32(self) -> i32 {
        return self.ty.as_i32();
    }
}

impl<T: Into<ErrorCode>> From<T> for Error {
    #[inline(always)]
    fn from(ty: T) -> Self {
        Self::from_type(ty)
    }
}

impl Debug for Error {
    #[inline(always)]
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        Display::fmt(&self, f)
    }
}

impl Display for Error {
    #[inline]
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        Debug::fmt(&self.ty, f)?;

        if let Some(ref desc) = self.desc {
            write!(f, ": {desc}")?;
        }

        Ok(())
    }
}

impl Display for ErrorCode {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ErrorCode::Kind(e) => write!(f, "{e}"),
            ErrorCode::Unknown(e) => write!(f, "Unknown error: {e}"),
        }
    }
}

impl Display for ErrorKind {
    #[inline]
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        Display::fmt(&(*self as i32), f)
    }
}

impl std::error::Error for Error {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        Some(&self.ty)
    }
}

impl std::error::Error for ErrorCode {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            ErrorCode::Kind(e) => Some(e),
            ErrorCode::Unknown(_) => None,
        }
    }
}

impl std::error::Error for ErrorKind {}

#[deprecated(since = "0.1.0", note = "use `ErrorKind` instead")]
pub type ErrorType = ErrorKind;

error! {
    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    pub enum ErrorKind {
        const CL_DEVICE_NOT_FOUND,
        const CL_DEVICE_NOT_AVAILABLE,
        const CL_COMPILER_NOT_AVAILABLE,
        const CL_MEM_OBJECT_ALLOCATION_FAILURE,
        const CL_OUT_OF_RESOURCES,
        const CL_OUT_OF_HOST_MEMORY,
        const CL_PROFILING_INFO_NOT_AVAILABLE,
        const CL_MEM_COPY_OVERLAP,
        const CL_IMAGE_FORMAT_MISMATCH,
        const CL_IMAGE_FORMAT_NOT_SUPPORTED,
        const CL_BUILD_PROGRAM_FAILURE,
        const CL_MAP_FAILURE,

        // #ifdef CL_VERSION_1_1
        const CL_MISALIGNED_SUB_BUFFER_OFFSET,
        const CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST,
        // #endif

        // #ifdef CL_VERSION_1_2
        const CL_COMPILE_PROGRAM_FAILURE,
        const CL_LINKER_NOT_AVAILABLE,
        const CL_LINK_PROGRAM_FAILURE,
        const CL_DEVICE_PARTITION_FAILED,
        const CL_KERNEL_ARG_INFO_NOT_AVAILABLE,
        // #endif

        const CL_INVALID_VALUE,
        const CL_INVALID_DEVICE_TYPE,
        const CL_INVALID_PLATFORM,
        const CL_INVALID_DEVICE,
        const CL_INVALID_CONTEXT,
        const CL_INVALID_QUEUE_PROPERTIES,
        const CL_INVALID_COMMAND_QUEUE,
        const CL_INVALID_HOST_PTR,
        const CL_INVALID_MEM_OBJECT,
        const CL_INVALID_IMAGE_FORMAT_DESCRIPTOR,
        const CL_INVALID_IMAGE_SIZE,
        const CL_INVALID_SAMPLER,
        const CL_INVALID_BINARY,
        const CL_INVALID_BUILD_OPTIONS,
        const CL_INVALID_PROGRAM,
        const CL_INVALID_PROGRAM_EXECUTABLE,
        const CL_INVALID_KERNEL_NAME,
        const CL_INVALID_KERNEL_DEFINITION,
        const CL_INVALID_KERNEL,
        const CL_INVALID_ARG_INDEX,
        const CL_INVALID_ARG_VALUE,
        const CL_INVALID_ARG_SIZE,
        const CL_INVALID_KERNEL_ARGS,
        const CL_INVALID_WORK_DIMENSION,
        const CL_INVALID_WORK_GROUP_SIZE,
        const CL_INVALID_WORK_ITEM_SIZE,
        const CL_INVALID_GLOBAL_OFFSET,
        const CL_INVALID_EVENT_WAIT_LIST,
        const CL_INVALID_EVENT,
        const CL_INVALID_OPERATION,
        const CL_INVALID_GL_OBJECT,
        const CL_INVALID_BUFFER_SIZE,
        const CL_INVALID_MIP_LEVEL,
        const CL_INVALID_GLOBAL_WORK_SIZE,

        // #ifdef CL_VERSION_1_1
        const CL_INVALID_PROPERTY,
        // #endif

        // #ifdef CL_VERSION_1_2
        const CL_INVALID_IMAGE_DESCRIPTOR,
        const CL_INVALID_COMPILER_OPTIONS,
        const CL_INVALID_LINKER_OPTIONS,
        const CL_INVALID_DEVICE_PARTITION_COUNT,
        // #endif

        // #ifdef CL_VERSION_2_0
        const CL_INVALID_PIPE_SIZE,
        const CL_INVALID_DEVICE_QUEUE,
        // #endif

        // #ifdef CL_VERSION_2_2
        const CL_INVALID_SPEC_ID,
        const CL_MAX_SIZE_RESTRICTION_EXCEEDED,
        // #endif

        NvidiaIllegalBufferAction = -9999
    }
}

const fn min_value<const N: usize>(iter: [i32; N]) -> i32 {
    let mut min = i32::MAX;
    let mut i = 0;

    while i < iter.len() {
        if iter[i] < min {
            min = iter[i]
        }

        i += 1;
    }

    min
}

const fn max_value<const N: usize>(iter: [i32; N]) -> i32 {
    let mut max = i32::MIN;
    let mut i = 0;

    while i < N {
        if iter[i] > max {
            max = iter[i]
        }

        i += 1;
    }

    max
}