cl3/
info_type.rs

1// Copyright (c) 2020-2024 Via Technology Ltd.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use libc::{intptr_t, size_t};
16use opencl_sys::{
17    CL_LUID_SIZE_KHR, CL_UUID_SIZE_KHR, cl_image_format, cl_int, cl_name_version, cl_uchar,
18    cl_uint, cl_ulong,
19};
20use std::fmt;
21
22/// A Rust enum to handle `OpenCL` API "Info" function return types.
23/// Each of the data types may be extracted from the enum using its associated
24/// From trait or `to_*` function.
25///
26/// # Panics
27///
28/// The From traits and `to_*` functions will panic if they are called for the
29/// incorrect data type.
30#[derive(Debug)]
31pub enum InfoType {
32    Int(i32),
33    Uint(u32),
34    Ulong(u64),
35    Size(usize),
36    Ptr(isize),
37    Luid([u8; CL_LUID_SIZE_KHR]),
38    Uuid([u8; CL_UUID_SIZE_KHR]),
39    VecUchar(Vec<u8>),
40    VecUshort(Vec<u32>),
41    VecUlong(Vec<u64>),
42    VecSize(Vec<usize>),
43    VecIntPtr(Vec<isize>),
44    VecNameVersion(Vec<cl_name_version>),
45    VecImageFormat(Vec<cl_image_format>),
46    VecVecUchar(Vec<Vec<u8>>),
47}
48
49/// A macro to help create the `InfoType` From traits.
50macro_rules! match_info_type {
51    ($value:expr, $variant:path) => {
52        match $value {
53            $variant(x) => x,
54            _ => panic!("value is not an {}", stringify!($variant)),
55        }
56    };
57}
58
59impl From<InfoType> for i32 {
60    fn from(value: InfoType) -> Self {
61        match_info_type!(value, InfoType::Int)
62    }
63}
64
65impl From<InfoType> for u32 {
66    fn from(value: InfoType) -> Self {
67        match_info_type!(value, InfoType::Uint)
68    }
69}
70
71impl From<InfoType> for u64 {
72    fn from(value: InfoType) -> Self {
73        match_info_type!(value, InfoType::Ulong)
74    }
75}
76
77impl From<InfoType> for usize {
78    fn from(value: InfoType) -> Self {
79        match_info_type!(value, InfoType::Size)
80    }
81}
82
83impl From<InfoType> for isize {
84    fn from(value: InfoType) -> Self {
85        match_info_type!(value, InfoType::Ptr)
86    }
87}
88
89impl From<InfoType> for [u8; CL_LUID_SIZE_KHR] {
90    fn from(value: InfoType) -> Self {
91        match_info_type!(value, InfoType::Luid)
92    }
93}
94
95impl From<InfoType> for [u8; CL_UUID_SIZE_KHR] {
96    fn from(value: InfoType) -> Self {
97        match_info_type!(value, InfoType::Uuid)
98    }
99}
100
101impl From<InfoType> for Vec<u8> {
102    fn from(value: InfoType) -> Self {
103        match_info_type!(value, InfoType::VecUchar)
104    }
105}
106
107impl From<InfoType> for Vec<u32> {
108    fn from(value: InfoType) -> Self {
109        match_info_type!(value, InfoType::VecUshort)
110    }
111}
112
113impl From<InfoType> for Vec<u64> {
114    fn from(value: InfoType) -> Self {
115        match_info_type!(value, InfoType::VecUlong)
116    }
117}
118
119impl From<InfoType> for Vec<usize> {
120    fn from(value: InfoType) -> Self {
121        match_info_type!(value, InfoType::VecSize)
122    }
123}
124
125impl From<InfoType> for Vec<isize> {
126    fn from(value: InfoType) -> Self {
127        match_info_type!(value, InfoType::VecIntPtr)
128    }
129}
130
131impl From<InfoType> for Vec<cl_name_version> {
132    fn from(value: InfoType) -> Self {
133        match_info_type!(value, InfoType::VecNameVersion)
134    }
135}
136
137impl From<InfoType> for Vec<cl_image_format> {
138    fn from(value: InfoType) -> Self {
139        match_info_type!(value, InfoType::VecImageFormat)
140    }
141}
142
143impl From<InfoType> for Vec<Vec<u8>> {
144    fn from(value: InfoType) -> Self {
145        match_info_type!(value, InfoType::VecVecUchar)
146    }
147}
148
149impl From<InfoType> for String {
150    /// Get a `Vec<cl_uchar>` aka `Vec<u8>` as a String.
151    /// Note: it uses `from_utf8_lossy` to convert any invalid characters to
152    /// `std::char::REPLACEMENT_CHARACTER`.
153    ///
154    /// returns a utf8 String.
155    fn from(info_type: InfoType) -> Self {
156        let mut a = Vec::<u8>::from(info_type);
157
158        // remove all trailing nulls, if any
159        while a.last() == Some(&0) {
160            a.pop();
161        }
162
163        // convert invalid characters to std::char::REPLACEMENT_CHARACTER
164        Self::from_utf8_lossy(&a).into_owned()
165    }
166}
167
168impl fmt::Display for InfoType {
169    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
170        match self {
171            Self::VecUchar(a) => {
172                let b = String::from_utf8_lossy(a).into_owned();
173                write!(f, "{b}")
174            }
175
176            // Formats a LUID the same way as `clinfo`.
177            // See: https://github.com/Oblomov/clinfo/blob/master/src/clinfo.c
178            Self::Luid(a) => {
179                write!(
180                    f,
181                    "{:x}{:x}-{:x}{:x}{:x}{:x}{:x}{:x}",
182                    a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]
183                )
184            }
185
186            // Formats a UUID according to RFC4122.
187            Self::Uuid(a) => {
188                write!(
189                    f,
190                    "{:x}{:x}{:x}{:x}-{:x}{:x}-{:x}{:x}-{:x}{:x}-{:x}{:x}{:x}{:x}{:x}{:x}",
191                    a[0],
192                    a[1],
193                    a[2],
194                    a[3],
195                    a[4],
196                    a[5],
197                    a[6],
198                    a[7],
199                    a[8],
200                    a[9],
201                    a[10],
202                    a[11],
203                    a[12],
204                    a[13],
205                    a[14],
206                    a[15],
207                )
208            }
209
210            Self::VecNameVersion(a) => {
211                let mut s = String::default();
212                for b in a {
213                    s.push('\n');
214
215                    s.push_str(&b.version.to_string());
216                    s.push_str(": ");
217                    s.push_str(&String::from_utf8_lossy(&b.name));
218                }
219
220                write!(f, "{s}")
221            }
222
223            Self::VecImageFormat(a) => {
224                let mut s = String::default();
225
226                for b in a {
227                    s.push('\n');
228
229                    s.push_str(&b.image_channel_order.to_string());
230                    s.push_str(": ");
231                    s.push_str(&b.image_channel_data_type.to_string());
232                }
233
234                write!(f, "{s}")
235            }
236
237            // Note: underlying type may not be a vector of Strings.
238            // If so use Debug trait instead
239            Self::VecVecUchar(a) => {
240                let mut s = String::default();
241                for b in a {
242                    s.push('\n');
243                    s.push_str(&String::from_utf8_lossy(b));
244                }
245
246                write!(f, "{s}")
247            }
248
249            _ => panic!("not a Displayable type, use Debug instead"),
250        }
251    }
252}
253
254impl InfoType {
255    #[must_use]
256    pub fn to_int(self) -> cl_int {
257        i32::from(self)
258    }
259
260    #[must_use]
261    pub fn to_uint(self) -> cl_uint {
262        u32::from(self)
263    }
264
265    #[must_use]
266    pub fn to_ulong(self) -> cl_ulong {
267        u64::from(self)
268    }
269
270    #[must_use]
271    pub fn to_size(self) -> size_t {
272        usize::from(self)
273    }
274
275    #[must_use]
276    pub fn to_ptr(self) -> intptr_t {
277        isize::from(self)
278    }
279
280    #[must_use]
281    pub fn to_luid(self) -> [u8; CL_LUID_SIZE_KHR] {
282        self.into()
283    }
284
285    #[must_use]
286    pub fn to_uuid(self) -> [u8; CL_UUID_SIZE_KHR] {
287        self.into()
288    }
289
290    #[must_use]
291    pub fn to_vec_uchar(self) -> Vec<cl_uchar> {
292        Vec::<u8>::from(self)
293    }
294
295    #[must_use]
296    pub fn to_vec_ulong(self) -> Vec<cl_ulong> {
297        Vec::<u64>::from(self)
298    }
299
300    #[must_use]
301    pub fn to_vec_size(self) -> Vec<size_t> {
302        Vec::<usize>::from(self)
303    }
304
305    #[must_use]
306    pub fn to_vec_intptr(self) -> Vec<intptr_t> {
307        Vec::<isize>::from(self)
308    }
309
310    #[must_use]
311    pub fn to_vec_name_version(self) -> Vec<cl_name_version> {
312        Vec::<cl_name_version>::from(self)
313    }
314
315    #[must_use]
316    pub fn to_vec_image_format(self) -> Vec<cl_image_format> {
317        Vec::<cl_image_format>::from(self)
318    }
319
320    #[must_use]
321    pub fn to_vec_vec_uchar(self) -> Vec<Vec<cl_uchar>> {
322        Vec::<Vec<u8>>::from(self)
323    }
324}
325#[cfg(test)]
326mod tests {
327    use crate::device::{
328        CL_DEVICE_MAX_WORK_ITEM_SIZES, CL_DEVICE_NAME, CL_DEVICE_PARTITION_PROPERTIES,
329        CL_DEVICE_TYPE, CL_DEVICE_TYPE_ALL, CL_DEVICE_VENDOR_ID, CL_DRIVER_VERSION, get_device_ids,
330        get_device_info,
331    };
332    use crate::platform::{
333        CL_PLATFORM_NAME, CL_PLATFORM_VERSION, get_platform_ids, get_platform_info,
334    };
335
336    #[test]
337    fn test_debug_display_info() {
338        let platform_ids = get_platform_ids().unwrap();
339        println!("Number of platforms: {}", platform_ids.len());
340        assert!(0 < platform_ids.len());
341
342        // Choose the first platform
343        let platform_id = platform_ids[0];
344
345        // Test Display trait
346        let value = get_platform_info(platform_id, CL_PLATFORM_NAME).unwrap();
347        println!("CL_PLATFORM_NAME: {}", value);
348
349        let value = get_platform_info(platform_id, CL_PLATFORM_VERSION).unwrap();
350        println!("CL_PLATFORM_VERSION: {}", value);
351
352        let device_ids = get_device_ids(platform_id, CL_DEVICE_TYPE_ALL).unwrap();
353        println!("Platform[0]->number of devices: {}", device_ids.len());
354        assert!(0 < device_ids.len());
355
356        // Choose the first device
357        let device_id = device_ids[0];
358
359        let value = get_device_info(device_id, CL_DEVICE_NAME).unwrap();
360        println!("CL_DEVICE_NAME: {}", value);
361
362        let value = get_device_info(device_id, CL_DRIVER_VERSION).unwrap();
363        println!("CL_DRIVER_VERSION: {}", value);
364
365        // Test Debug trait
366        let value = get_device_info(device_id, CL_DEVICE_TYPE).unwrap();
367        println!("CL_DEVICE_TYPE: {:?}", value);
368
369        let value = get_device_info(device_id, CL_DEVICE_VENDOR_ID).unwrap();
370        println!("CL_DEVICE_VENDOR_ID: {:?}", value);
371
372        let value = get_device_info(device_id, CL_DEVICE_MAX_WORK_ITEM_SIZES).unwrap();
373        println!("CL_DEVICE_MAX_WORK_ITEM_SIZES len: {:?}", value);
374
375        let value = get_device_info(device_id, CL_DEVICE_PARTITION_PROPERTIES).unwrap();
376        println!("CL_DEVICE_PARTITION_PROPERTIES: {:?}", value);
377    }
378}