use crate::datatype::DatatypeTag;
use crate::error::{Error, Result};
use crate::ffi;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct StructField {
pub blocklength: i32,
pub displacement: i64,
pub basetype: DatatypeTag,
}
#[derive(Debug)]
pub struct CustomDatatype {
pub(crate) handle: i32,
}
unsafe impl Send for CustomDatatype {}
unsafe impl Sync for CustomDatatype {}
impl CustomDatatype {
fn validate_primitive_basetype(basetype: DatatypeTag) -> Result<()> {
match basetype {
DatatypeTag::FloatInt
| DatatypeTag::DoubleInt
| DatatypeTag::LongInt
| DatatypeTag::Int2
| DatatypeTag::ShortInt
| DatatypeTag::LongDoubleInt => Err(Error::InvalidOp),
DatatypeTag::F32
| DatatypeTag::F64
| DatatypeTag::I32
| DatatypeTag::I64
| DatatypeTag::U8
| DatatypeTag::U32
| DatatypeTag::U64
| DatatypeTag::Byte => Ok(()),
}
}
pub fn contiguous(count: i32, basetype: DatatypeTag) -> Result<Self> {
Self::validate_primitive_basetype(basetype)?;
let mut handle: i32 = -1;
let ret = unsafe { ffi::ferrompi_type_contiguous(count, basetype as i32, &mut handle) };
Error::check_with_op(ret, "type_contiguous")?;
Ok(CustomDatatype { handle })
}
pub fn vector(
count: i32,
blocklength: i32,
stride: i32,
basetype: DatatypeTag,
) -> Result<Self> {
Self::validate_primitive_basetype(basetype)?;
let mut handle: i32 = -1;
let ret = unsafe {
ffi::ferrompi_type_vector(count, blocklength, stride, basetype as i32, &mut handle)
};
Error::check_with_op(ret, "type_vector")?;
Ok(CustomDatatype { handle })
}
pub fn create_struct(fields: &[StructField]) -> Result<Self> {
let mut blocklengths: Vec<i32> = Vec::with_capacity(fields.len());
let mut displacements: Vec<i64> = Vec::with_capacity(fields.len());
let mut basetype_tags: Vec<i32> = Vec::with_capacity(fields.len());
for f in fields {
Self::validate_primitive_basetype(f.basetype)?;
blocklengths.push(f.blocklength);
displacements.push(f.displacement);
basetype_tags.push(f.basetype as i32);
}
let mut h: i32 = -1;
let ret = unsafe {
ffi::ferrompi_type_create_struct(
fields.len() as i32,
blocklengths.as_ptr(),
displacements.as_ptr(),
basetype_tags.as_ptr(),
&mut h,
)
};
Error::check_with_op(ret, "type_create_struct")?;
Ok(CustomDatatype { handle: h })
}
pub fn resized(&self, lb: i64, extent: i64) -> Result<Self> {
let mut h: i32 = -1;
let ret = unsafe { ffi::ferrompi_type_create_resized(self.handle, lb, extent, &mut h) };
Error::check_with_op(ret, "type_create_resized")?;
Ok(CustomDatatype { handle: h })
}
pub fn raw_handle(&self) -> i32 {
self.handle
}
}
impl Drop for CustomDatatype {
fn drop(&mut self) {
if self.handle >= 0 {
unsafe {
ffi::ferrompi_type_free(self.handle);
}
}
}
}
#[cfg(test)]
mod tests {
use super::{CustomDatatype, StructField};
use crate::datatype::DatatypeTag;
use crate::error::{Error, Result};
const _: () = {
#[allow(dead_code)]
fn check<T: Send + Sync>() {}
#[allow(dead_code)]
fn custom_datatype_send_sync_compile_time_assertion() {
check::<CustomDatatype>();
}
};
#[test]
fn custom_datatype_raw_handle_returns_stored_value() {
let dt = CustomDatatype { handle: 5 };
assert_eq!(dt.raw_handle(), 5);
std::mem::forget(dt);
}
#[test]
fn contiguous_rejects_indexed_basetype() {
let result = CustomDatatype::contiguous(10, DatatypeTag::FloatInt);
assert!(
matches!(result, Err(Error::InvalidOp)),
"expected Err(Error::InvalidOp), got: {:?}",
result
);
}
#[test]
fn vector_rejects_indexed_basetype() {
let result = CustomDatatype::vector(3, 2, 5, DatatypeTag::FloatInt);
assert!(
matches!(result, Err(Error::InvalidOp)),
"expected Err(Error::InvalidOp), got: {:?}",
result
);
}
#[test]
fn create_struct_rejects_indexed_basetype() {
let result = CustomDatatype::create_struct(&[StructField {
blocklength: 1,
displacement: 0,
basetype: DatatypeTag::FloatInt,
}]);
assert!(
matches!(result, Err(Error::InvalidOp)),
"expected Err(Error::InvalidOp), got: {:?}",
result
);
}
#[allow(dead_code)]
fn resized_signature_compiles(d: &CustomDatatype) -> Result<CustomDatatype> {
d.resized(0, 16)
}
}