pub mod array_read;
pub mod array_read_write;
pub mod array_sharded;
pub mod array_write;
pub mod data_type;
use std::ffi::{c_char, CString};
use ffi_support::FfiStr;
use zarrs::{
array::{chunk_shape_to_array_shape, Array, ArrayMetadata, DataType},
array_subset::ArraySubset,
};
use crate::{
storage::{ZarrsStorage, ZarrsStorageEnum},
ZarrsDataType, ZarrsResult, LAST_ERROR,
};
#[doc(hidden)]
#[allow(clippy::upper_case_acronyms)]
pub enum ZarrsArrayEnum {
R(Array<dyn zarrs::storage::ReadableStorageTraits>),
W(Array<dyn zarrs::storage::WritableStorageTraits>),
L(Array<dyn zarrs::storage::ListableStorageTraits>),
RL(Array<dyn zarrs::storage::ReadableListableStorageTraits>),
RW(Array<dyn zarrs::storage::ReadableWritableStorageTraits>),
RWL(Array<dyn zarrs::storage::ReadableWritableListableStorageTraits>),
}
macro_rules! array_fn {
($array:expr, $fn:ident ) => {
match $array {
crate::array::ZarrsArrayEnum::R(array) => array.$fn(),
crate::array::ZarrsArrayEnum::W(array) => array.$fn(),
crate::array::ZarrsArrayEnum::L(array) => array.$fn(),
crate::array::ZarrsArrayEnum::RL(array) => array.$fn(),
crate::array::ZarrsArrayEnum::RW(array) => array.$fn(),
crate::array::ZarrsArrayEnum::RWL(array) => array.$fn(),
}
};
($array:expr, $fn:ident, $( $args:expr ),* ) => {
match $array {
crate::array::ZarrsArrayEnum::R(array) => array.$fn($( $args ),*),
crate::array::ZarrsArrayEnum::W(array) => array.$fn($( $args ),*),
crate::array::ZarrsArrayEnum::L(array) => array.$fn($( $args ),*),
crate::array::ZarrsArrayEnum::RL(array) => array.$fn($( $args ),*),
crate::array::ZarrsArrayEnum::RW(array) => array.$fn($( $args ),*),
crate::array::ZarrsArrayEnum::RWL(array) => array.$fn($( $args ),*),
}
};
}
pub(crate) use array_fn;
#[doc(hidden)]
pub struct ZarrsArray_T(pub ZarrsArrayEnum);
impl std::ops::Deref for ZarrsArray_T {
type Target = ZarrsArrayEnum;
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub type ZarrsArray = *mut ZarrsArray_T;
#[no_mangle]
pub unsafe extern "C" fn zarrsOpenArrayRW(
storage: ZarrsStorage,
path: FfiStr,
pArray: *mut ZarrsArray,
) -> ZarrsResult {
if storage.is_null() {
*LAST_ERROR = "storage is null".to_string();
return ZarrsResult::ZARRS_ERROR_NULL_PTR;
}
let storage = &**storage;
if let ZarrsStorageEnum::RW(storage) = storage {
match Array::open(storage.clone(), path.into()) {
Ok(array) => {
*pArray = Box::into_raw(Box::new(ZarrsArray_T(ZarrsArrayEnum::RW(array))));
ZarrsResult::ZARRS_SUCCESS
}
Err(err) => {
*LAST_ERROR = err.to_string();
ZarrsResult::ZARRS_ERROR_ARRAY
}
}
} else {
*LAST_ERROR = "storage does not support read and write".to_string();
ZarrsResult::ZARRS_ERROR_STORAGE_CAPABILITY
}
}
#[no_mangle]
pub unsafe extern "C" fn zarrsCreateArrayRW(
storage: ZarrsStorage,
path: FfiStr,
metadata: FfiStr,
pArray: *mut ZarrsArray,
) -> ZarrsResult {
if storage.is_null() {
*LAST_ERROR = "storage is null".to_string();
return ZarrsResult::ZARRS_ERROR_NULL_PTR;
}
let storage = &**storage;
let metadata = match ArrayMetadata::try_from(metadata.as_str()) {
Ok(metadata) => metadata,
Err(err) => {
*LAST_ERROR = err.to_string();
return ZarrsResult::ZARRS_ERROR_INVALID_METADATA;
}
};
if let ZarrsStorageEnum::RW(storage) = storage {
match Array::new_with_metadata(storage.clone(), path.into(), metadata) {
Ok(array) => {
*pArray = Box::into_raw(Box::new(ZarrsArray_T(ZarrsArrayEnum::RW(array))));
ZarrsResult::ZARRS_SUCCESS
}
Err(err) => {
*LAST_ERROR = err.to_string();
ZarrsResult::ZARRS_ERROR_ARRAY
}
}
} else {
*LAST_ERROR = "storage does not support read and write".to_string();
ZarrsResult::ZARRS_ERROR_STORAGE_CAPABILITY
}
}
#[no_mangle]
pub unsafe extern "C" fn zarrsDestroyArray(array: ZarrsArray) -> ZarrsResult {
if array.is_null() {
ZarrsResult::ZARRS_ERROR_NULL_PTR
} else {
unsafe { array.to_owned().drop_in_place() };
ZarrsResult::ZARRS_SUCCESS
}
}
#[no_mangle]
pub unsafe extern "C" fn zarrsArrayGetDimensionality(
array: ZarrsArray,
dimensionality: *mut usize,
) -> ZarrsResult {
if array.is_null() {
return ZarrsResult::ZARRS_ERROR_NULL_PTR;
}
let array = &**array;
*dimensionality = array_fn!(array, dimensionality);
ZarrsResult::ZARRS_SUCCESS
}
#[no_mangle]
pub unsafe extern "C" fn zarrsArrayGetShape(
array: ZarrsArray,
dimensionality: usize,
pShape: *mut u64,
) -> ZarrsResult {
if array.is_null() {
return ZarrsResult::ZARRS_ERROR_NULL_PTR;
}
let array = &**array;
let shape = array_fn!(array, shape);
let pShape = unsafe { std::slice::from_raw_parts_mut(pShape, dimensionality) };
pShape.copy_from_slice(shape);
ZarrsResult::ZARRS_SUCCESS
}
#[no_mangle]
pub unsafe extern "C" fn zarrsArrayGetDataType(
array: ZarrsArray,
pDataType: *mut ZarrsDataType,
) -> ZarrsResult {
if array.is_null() {
return ZarrsResult::ZARRS_ERROR_NULL_PTR;
}
let array = &**array;
let data_type = array_fn!(array, data_type);
*pDataType = match data_type {
DataType::Bool => ZarrsDataType::ZARRS_BOOL,
DataType::Int8 => ZarrsDataType::ZARRS_INT8,
DataType::Int16 => ZarrsDataType::ZARRS_INT16,
DataType::Int32 => ZarrsDataType::ZARRS_INT32,
DataType::Int64 => ZarrsDataType::ZARRS_INT64,
DataType::UInt8 => ZarrsDataType::ZARRS_UINT8,
DataType::UInt16 => ZarrsDataType::ZARRS_UINT16,
DataType::UInt32 => ZarrsDataType::ZARRS_UINT32,
DataType::UInt64 => ZarrsDataType::ZARRS_UINT64,
DataType::Float16 => ZarrsDataType::ZARRS_FLOAT16,
DataType::Float32 => ZarrsDataType::ZARRS_FLOAT32,
DataType::Float64 => ZarrsDataType::ZARRS_FLOAT64,
DataType::BFloat16 => ZarrsDataType::ZARRS_BFLOAT16,
DataType::Complex64 => ZarrsDataType::ZARRS_COMPLEX64,
DataType::Complex128 => ZarrsDataType::ZARRS_COMPLEX128,
DataType::RawBits(_) => ZarrsDataType::ZARRS_RAW_BITS,
_ => ZarrsDataType::ZARRS_UNDEFINED,
};
ZarrsResult::ZARRS_SUCCESS
}
#[no_mangle]
pub unsafe extern "C" fn zarrsArrayGetChunkGridShape(
array: ZarrsArray,
dimensionality: usize,
pChunkGridShape: *mut u64,
) -> ZarrsResult {
if array.is_null() {
return ZarrsResult::ZARRS_ERROR_NULL_PTR;
}
let array = &**array;
let chunk_grid_shape = array_fn!(array, chunk_grid_shape);
if let Some(chunk_grid_shape) = chunk_grid_shape {
let pChunkGridShape =
unsafe { std::slice::from_raw_parts_mut(pChunkGridShape, dimensionality) };
pChunkGridShape.copy_from_slice(&chunk_grid_shape);
ZarrsResult::ZARRS_SUCCESS
} else {
ZarrsResult::ZARRS_ERROR_UNKNOWN_CHUNK_GRID_SHAPE
}
}
#[no_mangle]
pub unsafe extern "C" fn zarrsArrayGetChunksInSubset(
array: ZarrsArray,
dimensionality: usize,
pSubsetStart: *const u64,
pSubsetShape: *const u64,
pChunksStart: *mut u64,
pChunksShape: *mut u64,
) -> ZarrsResult {
if array.is_null() {
return ZarrsResult::ZARRS_ERROR_NULL_PTR;
}
let array = &**array;
let pSubsetStart = unsafe { std::slice::from_raw_parts(pSubsetStart, dimensionality) };
let pSubsetShape = unsafe { std::slice::from_raw_parts(pSubsetShape, dimensionality) };
let array_subset = unsafe {
ArraySubset::new_with_start_shape_unchecked(pSubsetStart.to_vec(), pSubsetShape.to_vec())
};
let shape = array_fn!(array, chunks_in_array_subset, &array_subset);
if let Ok(Some(chunks_subset)) = shape {
let pChunksStart = unsafe { std::slice::from_raw_parts_mut(pChunksStart, dimensionality) };
pChunksStart.copy_from_slice(chunks_subset.start());
let pChunksShape = unsafe { std::slice::from_raw_parts_mut(pChunksShape, dimensionality) };
pChunksShape.copy_from_slice(chunks_subset.shape());
ZarrsResult::ZARRS_SUCCESS
} else {
ZarrsResult::ZARRS_ERROR_UNKNOWN_INTERSECTING_CHUNKS
}
}
#[no_mangle]
pub unsafe extern "C" fn zarrsArrayGetChunkSize(
array: ZarrsArray,
dimensionality: usize,
pChunkIndices: *const u64,
chunkSize: *mut usize,
) -> ZarrsResult {
if array.is_null() {
return ZarrsResult::ZARRS_ERROR_NULL_PTR;
}
let array = &**array;
let chunk_indices = std::slice::from_raw_parts(pChunkIndices, dimensionality);
let chunk_representation = array_fn!(array, chunk_array_representation, chunk_indices);
match chunk_representation {
Ok(chunk_representation) => {
if let Some(chunk_size) = chunk_representation.fixed_size() {
*chunkSize = chunk_size;
ZarrsResult::ZARRS_SUCCESS
} else {
*LAST_ERROR = "variable size data types are not supported".to_string();
ZarrsResult::ZARRS_ERROR_UNSUPPORTED_DATA_TYPE
}
}
Err(err) => {
*LAST_ERROR = err.to_string();
ZarrsResult::ZARRS_ERROR_INVALID_INDICES
}
}
}
#[no_mangle]
pub unsafe extern "C" fn zarrsArrayGetChunkOrigin(
array: ZarrsArray,
dimensionality: usize,
pChunkIndices: *const u64,
pChunkOrigin: *mut u64,
) -> ZarrsResult {
if array.is_null() {
return ZarrsResult::ZARRS_ERROR_NULL_PTR;
}
let array = &**array;
let chunk_indices = std::slice::from_raw_parts(pChunkIndices, dimensionality);
let chunk_origin = array_fn!(array, chunk_origin, chunk_indices);
match chunk_origin {
Ok(chunk_origin) => {
let pChunkOrigin =
unsafe { std::slice::from_raw_parts_mut(pChunkOrigin, dimensionality) };
pChunkOrigin.copy_from_slice(&chunk_origin);
ZarrsResult::ZARRS_SUCCESS
}
Err(err) => {
*LAST_ERROR = err.to_string();
ZarrsResult::ZARRS_ERROR_INVALID_INDICES
}
}
}
#[no_mangle]
pub unsafe extern "C" fn zarrsArrayGetChunkShape(
array: ZarrsArray,
dimensionality: usize,
pChunkIndices: *const u64,
pChunkShape: *mut u64,
) -> ZarrsResult {
if array.is_null() {
return ZarrsResult::ZARRS_ERROR_NULL_PTR;
}
let array = &**array;
let chunk_indices = std::slice::from_raw_parts(pChunkIndices, dimensionality);
let chunk_shape = array_fn!(array, chunk_shape, chunk_indices);
match chunk_shape {
Ok(chunk_shape) => {
let pChunkShape =
unsafe { std::slice::from_raw_parts_mut(pChunkShape, dimensionality) };
pChunkShape.copy_from_slice(&chunk_shape_to_array_shape(&chunk_shape));
ZarrsResult::ZARRS_SUCCESS
}
Err(err) => {
*LAST_ERROR = err.to_string();
ZarrsResult::ZARRS_ERROR_INVALID_INDICES
}
}
}
#[no_mangle]
pub unsafe extern "C" fn zarrsArrayGetSubsetSize(
array: ZarrsArray,
dimensionality: usize,
pSubsetShape: *const u64,
subsetSize: *mut usize,
) -> ZarrsResult {
if array.is_null() {
return ZarrsResult::ZARRS_ERROR_NULL_PTR;
}
let array = &**array;
let subset_shape = std::slice::from_raw_parts(pSubsetShape, dimensionality);
let data_type = array_fn!(array, data_type);
let Some(data_type_size) = data_type.fixed_size() else {
*LAST_ERROR = "variable size data types are not supported".to_string();
return ZarrsResult::ZARRS_ERROR_UNSUPPORTED_DATA_TYPE;
};
*subsetSize = usize::try_from(subset_shape.iter().product::<u64>()).unwrap() * data_type_size;
ZarrsResult::ZARRS_SUCCESS
}
#[no_mangle]
pub unsafe extern "C" fn zarrsArrayGetMetadataString(
array: ZarrsArray,
pretty: bool,
pMetadataString: *mut *const c_char,
) -> ZarrsResult {
if array.is_null() {
return ZarrsResult::ZARRS_ERROR_NULL_PTR;
}
let array = &**array;
let metadata = array_fn!(array, metadata);
let metadata_str = if pretty {
serde_json::to_string_pretty(&metadata)
} else {
serde_json::to_string(&metadata)
};
if let Ok(metadata_str) = metadata_str {
if let Ok(cstring) = CString::new(metadata_str) {
*pMetadataString = cstring.into_raw();
return ZarrsResult::ZARRS_SUCCESS;
}
}
*LAST_ERROR = "error converting metadata to a json string".to_string();
ZarrsResult::ZARRS_ERROR_INVALID_METADATA
}
#[no_mangle]
pub unsafe extern "C" fn zarrsArrayGetAttributesString(
array: ZarrsArray,
pretty: bool,
pAttributesString: *mut *const c_char,
) -> ZarrsResult {
if array.is_null() {
return ZarrsResult::ZARRS_ERROR_NULL_PTR;
}
let array = &**array;
let attributes = array_fn!(array, attributes);
let attributes_str = if pretty {
serde_json::to_string_pretty(&attributes)
} else {
serde_json::to_string(&attributes)
};
if let Ok(attributes_str) = attributes_str {
if let Ok(cstring) = CString::new(attributes_str) {
*pAttributesString = cstring.into_raw();
return ZarrsResult::ZARRS_SUCCESS;
}
}
*LAST_ERROR = "error converting attributes to a json string".to_string();
ZarrsResult::ZARRS_ERROR_INVALID_METADATA
}