1use std::fmt;
4
5use cugraph_sys::{bool_t, cugraph_data_type_id_t, cugraph_graph_properties_t};
6
7use crate::error::{Error, ErrorKind};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11pub enum DataType {
12 Int8,
13 Int16,
14 Int32,
15 Int64,
16 Uint8,
17 Uint16,
18 Uint32,
19 Uint64,
20 Float32,
21 Float64,
22 SizeT,
23 Bool,
24}
25
26impl fmt::Display for DataType {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 let name = match self {
29 Self::Int8 => "Int8",
30 Self::Int16 => "Int16",
31 Self::Int32 => "Int32",
32 Self::Int64 => "Int64",
33 Self::Uint8 => "Uint8",
34 Self::Uint16 => "Uint16",
35 Self::Uint32 => "Uint32",
36 Self::Uint64 => "Uint64",
37 Self::Float32 => "Float32",
38 Self::Float64 => "Float64",
39 Self::SizeT => "SizeT",
40 Self::Bool => "Bool",
41 };
42 f.write_str(name)
43 }
44}
45
46impl DataType {
47 pub fn size_of(&self) -> usize {
49 match self {
50 DataType::Int8 | DataType::Uint8 | DataType::Bool => 1,
51 DataType::Int16 | DataType::Uint16 => 2,
52 DataType::Int32 | DataType::Uint32 | DataType::Float32 => 4,
53 DataType::Int64 | DataType::Uint64 | DataType::Float64 | DataType::SizeT => 8,
54 }
55 }
56
57 pub fn is_supported_index_type(&self) -> bool {
62 matches!(self, DataType::Int32 | DataType::Int64)
63 }
64
65 pub fn is_float(&self) -> bool {
69 matches!(self, DataType::Float32 | DataType::Float64)
70 }
71}
72
73impl From<DataType> for cugraph_data_type_id_t {
74 fn from(dt: DataType) -> Self {
75 match dt {
76 DataType::Int8 => cugraph_data_type_id_t::INT8,
77 DataType::Int16 => cugraph_data_type_id_t::INT16,
78 DataType::Int32 => cugraph_data_type_id_t::INT32,
79 DataType::Int64 => cugraph_data_type_id_t::INT64,
80 DataType::Uint8 => cugraph_data_type_id_t::UINT8,
81 DataType::Uint16 => cugraph_data_type_id_t::UINT16,
82 DataType::Uint32 => cugraph_data_type_id_t::UINT32,
83 DataType::Uint64 => cugraph_data_type_id_t::UINT64,
84 DataType::Float32 => cugraph_data_type_id_t::FLOAT32,
85 DataType::Float64 => cugraph_data_type_id_t::FLOAT64,
86 DataType::SizeT => cugraph_data_type_id_t::SIZE_T,
87 DataType::Bool => cugraph_data_type_id_t::BOOL,
88 }
89 }
90}
91
92impl TryFrom<cugraph_data_type_id_t> for DataType {
93 type Error = Error;
94
95 fn try_from(dt: cugraph_data_type_id_t) -> std::result::Result<Self, Self::Error> {
96 match dt {
97 cugraph_data_type_id_t::INT8 => Ok(DataType::Int8),
98 cugraph_data_type_id_t::INT16 => Ok(DataType::Int16),
99 cugraph_data_type_id_t::INT32 => Ok(DataType::Int32),
100 cugraph_data_type_id_t::INT64 => Ok(DataType::Int64),
101 cugraph_data_type_id_t::UINT8 => Ok(DataType::Uint8),
102 cugraph_data_type_id_t::UINT16 => Ok(DataType::Uint16),
103 cugraph_data_type_id_t::UINT32 => Ok(DataType::Uint32),
104 cugraph_data_type_id_t::UINT64 => Ok(DataType::Uint64),
105 cugraph_data_type_id_t::FLOAT32 => Ok(DataType::Float32),
106 cugraph_data_type_id_t::FLOAT64 => Ok(DataType::Float64),
107 cugraph_data_type_id_t::SIZE_T => Ok(DataType::SizeT),
108 cugraph_data_type_id_t::BOOL => Ok(DataType::Bool),
109 _ => Err(Error::new(ErrorKind::UnsupportedType, "DataType::try_from")
110 .with_message(format!("unknown cugraph_data_type_id_t value: {}", dt.0))),
111 }
112 }
113}
114
115mod sealed {
116 pub trait Sealed {}
117}
118
119pub trait CugraphElement: Copy + sealed::Sealed {
124 fn data_type() -> DataType;
126}
127
128macro_rules! impl_cugraph_element {
129 ($($rust_ty:ty => $variant:ident),+ $(,)?) => {
130 $(
131 impl sealed::Sealed for $rust_ty {}
132 impl CugraphElement for $rust_ty {
133 fn data_type() -> DataType {
134 DataType::$variant
135 }
136 }
137 )+
138 };
139}
140
141impl_cugraph_element! {
142 i8 => Int8,
143 i16 => Int16,
144 i32 => Int32,
145 i64 => Int64,
146 u8 => Uint8,
147 u16 => Uint16,
148 u32 => Uint32,
149 u64 => Uint64,
150 usize => SizeT,
151 f32 => Float32,
152 f64 => Float64,
153}
154
155#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
157pub struct GraphProperties {
158 pub is_symmetric: bool,
159 pub is_multigraph: bool,
160}
161
162impl GraphProperties {
163 pub fn directed() -> Self {
167 Self { is_symmetric: false, is_multigraph: false }
168 }
169
170 pub fn undirected() -> Self {
172 Self { is_symmetric: true, is_multigraph: false }
173 }
174}
175
176impl Default for GraphProperties {
177 fn default() -> Self {
179 Self::directed()
180 }
181}
182
183impl fmt::Display for GraphProperties {
184 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185 let symmetry = if self.is_symmetric { "symmetric" } else { "directed" };
186 let kind = if self.is_multigraph { "multigraph" } else { "simple graph" };
187 write!(f, "{symmetry} {kind}")
188 }
189}
190
191impl From<GraphProperties> for cugraph_graph_properties_t {
192 fn from(props: GraphProperties) -> Self {
193 cugraph_graph_properties_t {
194 is_symmetric: to_bool_t(props.is_symmetric),
195 is_multigraph: to_bool_t(props.is_multigraph),
196 }
197 }
198}
199
200pub(crate) fn to_bool_t(b: bool) -> bool_t {
202 if b { bool_t::TRUE } else { bool_t::FALSE }
203}
204
205pub(crate) fn try_from_bool_t(b: bool_t) -> Option<bool> {
208 if b == bool_t::TRUE {
209 Some(true)
210 } else if b == bool_t::FALSE {
211 Some(false)
212 } else {
213 None
214 }
215}
216
217#[cfg(test)]
218mod tests {
219 use super::*;
220
221 #[test]
222 fn test_data_type_roundtrip() {
223 let variants = [
224 DataType::Int8,
225 DataType::Int16,
226 DataType::Int32,
227 DataType::Int64,
228 DataType::Uint8,
229 DataType::Uint16,
230 DataType::Uint32,
231 DataType::Uint64,
232 DataType::Float32,
233 DataType::Float64,
234 DataType::SizeT,
235 DataType::Bool,
236 ];
237 for dt in &variants {
238 let c_dt: cugraph_data_type_id_t = (*dt).into();
239 let back = DataType::try_from(c_dt).expect("known cugraph_data_type_id_t");
240 assert_eq!(*dt, back, "roundtrip failed for {:?}", dt);
241 }
242 }
243
244 #[test]
245 fn test_data_type_try_from_unknown_value_returns_descriptive_error() {
246 let err = DataType::try_from(cugraph_data_type_id_t(255)).expect_err("unknown dtype should fail");
247 assert_eq!(err.kind(), ErrorKind::UnsupportedType);
248 assert_eq!(err.operation(), "DataType::try_from");
249 assert!(err.message().contains("255"));
250 }
251
252 #[test]
253 fn test_bool_conversion() {
254 assert_eq!(to_bool_t(true), bool_t::TRUE);
255 assert_eq!(to_bool_t(false), bool_t::FALSE);
256 assert_eq!(try_from_bool_t(bool_t::TRUE), Some(true));
257 assert_eq!(try_from_bool_t(bool_t::FALSE), Some(false));
258 assert_eq!(try_from_bool_t(bool_t(2)), None);
259 }
260
261 #[test]
262 fn test_graph_properties_to_c() {
263 let props = GraphProperties::undirected();
264 let c_props: cugraph_graph_properties_t = props.into();
265 assert_eq!(c_props.is_symmetric, bool_t::TRUE);
266 assert_eq!(c_props.is_multigraph, bool_t::FALSE);
267 }
268
269 #[test]
270 fn test_cugraph_element_size_matches_data_type() {
271 assert_eq!(std::mem::size_of::<i8>(), i8::data_type().size_of());
273 assert_eq!(std::mem::size_of::<i16>(), i16::data_type().size_of());
274 assert_eq!(std::mem::size_of::<i32>(), i32::data_type().size_of());
275 assert_eq!(std::mem::size_of::<i64>(), i64::data_type().size_of());
276 assert_eq!(std::mem::size_of::<u8>(), u8::data_type().size_of());
277 assert_eq!(std::mem::size_of::<u16>(), u16::data_type().size_of());
278 assert_eq!(std::mem::size_of::<u32>(), u32::data_type().size_of());
279 assert_eq!(std::mem::size_of::<u64>(), u64::data_type().size_of());
280 assert_eq!(std::mem::size_of::<f32>(), f32::data_type().size_of());
281 assert_eq!(std::mem::size_of::<f64>(), f64::data_type().size_of());
282 }
283}