use zarrs::{
array::{
Array, ArrayBytes, ArrayShardedExt, ArrayShardedReadableExt, ArrayShardedReadableExtCache,
ArraySubset, CodecOptions, chunk_shape_to_array_shape,
},
storage::ReadableStorageTraits,
};
use crate::{LAST_ERROR, ZarrsResult};
use super::{ZarrsArray, ZarrsArrayEnum, array_fn};
#[doc(hidden)]
pub struct ZarrsShardIndexCache_T(pub ArrayShardedReadableExtCache);
impl std::ops::Deref for ZarrsShardIndexCache_T {
type Target = ArrayShardedReadableExtCache;
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub type ZarrsShardIndexCache = *mut ZarrsShardIndexCache_T;
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zarrsArrayGetSubChunkGridShape(
array: ZarrsArray,
dimensionality: usize,
pSubChunkGridShape: *mut u64,
) -> ZarrsResult {
if array.is_null() {
return ZarrsResult::ZARRS_ERROR_NULL_PTR;
}
let array = unsafe { &**array };
let subchunk_grid_shape = array_fn!(array, subchunk_grid_shape);
if subchunk_grid_shape.len() != dimensionality {
return ZarrsResult::ZARRS_ERROR_INCOMPATIBLE_DIMENSIONALITY;
}
let pSubChunkShape =
unsafe { std::slice::from_raw_parts_mut(pSubChunkGridShape, dimensionality) };
pSubChunkShape.copy_from_slice(&subchunk_grid_shape);
ZarrsResult::ZARRS_SUCCESS
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zarrsArrayGetSubChunkShape(
array: ZarrsArray,
dimensionality: usize,
pIsSharded: *mut bool,
pSubChunkShape: *mut u64,
) -> ZarrsResult {
if array.is_null() {
return ZarrsResult::ZARRS_ERROR_NULL_PTR;
}
let array = unsafe { &**array };
let subchunk_shape = array_fn!(array, subchunk_shape);
match subchunk_shape {
Some(subchunk_shape) => {
let pSubChunkShape =
unsafe { std::slice::from_raw_parts_mut(pSubChunkShape, dimensionality) };
pSubChunkShape.copy_from_slice(&chunk_shape_to_array_shape(&subchunk_shape));
unsafe { *pIsSharded = true };
}
None => {
unsafe { *pIsSharded = false };
}
}
ZarrsResult::ZARRS_SUCCESS
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zarrsCreateShardIndexCache(
array: ZarrsArray,
pShardIndexCache: *mut ZarrsShardIndexCache,
) -> ZarrsResult {
if array.is_null() {
return ZarrsResult::ZARRS_ERROR_NULL_PTR;
}
let array = unsafe { &**array };
match array {
ZarrsArrayEnum::R(array) => {
unsafe {
*pShardIndexCache = Box::into_raw(Box::new(ZarrsShardIndexCache_T(
ArrayShardedReadableExtCache::new(array),
)));
}
}
ZarrsArrayEnum::RW(array) => {
unsafe {
*pShardIndexCache = Box::into_raw(Box::new(ZarrsShardIndexCache_T(
ArrayShardedReadableExtCache::new(array),
)));
}
}
ZarrsArrayEnum::RWL(array) => {
unsafe {
*pShardIndexCache = Box::into_raw(Box::new(ZarrsShardIndexCache_T(
ArrayShardedReadableExtCache::new(array),
)));
}
}
_ => {
*LAST_ERROR.lock().unwrap() = "storage does not have read capability".to_string();
return ZarrsResult::ZARRS_ERROR_STORAGE_CAPABILITY;
}
}
ZarrsResult::ZARRS_SUCCESS
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zarrsDestroyShardIndexCache(
shardIndexCache: ZarrsShardIndexCache,
) -> ZarrsResult {
if shardIndexCache.is_null() {
ZarrsResult::ZARRS_ERROR_NULL_PTR
} else {
unsafe { shardIndexCache.to_owned().drop_in_place() };
ZarrsResult::ZARRS_SUCCESS
}
}
fn zarrsArrayRetrieveSubChunkImpl<T: ReadableStorageTraits + ?Sized + 'static>(
array: &Array<T>,
cache: &ArrayShardedReadableExtCache,
chunk_indices: &[u64],
chunk_bytes_length: usize,
chunk_bytes: *mut u8,
) -> ZarrsResult {
match array.retrieve_subchunk_opt::<ArrayBytes>(cache, chunk_indices, &CodecOptions::default())
{
Ok(bytes) => {
let Ok(bytes) = bytes.into_fixed() else {
*LAST_ERROR.lock().unwrap() =
"variable size data types are not supported".to_string();
return ZarrsResult::ZARRS_ERROR_UNSUPPORTED_DATA_TYPE;
};
if bytes.len() != chunk_bytes_length {
*LAST_ERROR.lock().unwrap() = format!(
"chunk_bytes_length {chunk_bytes_length} does not match decoded chunk size {}",
bytes.len()
);
ZarrsResult::ZARRS_ERROR_BUFFER_LENGTH
} else {
unsafe { std::ptr::copy(bytes.as_ptr(), chunk_bytes, chunk_bytes_length) };
ZarrsResult::ZARRS_SUCCESS
}
}
Err(err) => {
*LAST_ERROR.lock().unwrap() = err.to_string();
ZarrsResult::ZARRS_ERROR_ARRAY
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zarrsArrayRetrieveSubChunk(
array: ZarrsArray,
cache: ZarrsShardIndexCache,
dimensionality: usize,
pChunkIndices: *const u64,
chunkBytesCount: usize,
pChunkBytes: *mut u8,
) -> ZarrsResult {
if array.is_null() || cache.is_null() {
return ZarrsResult::ZARRS_ERROR_NULL_PTR;
}
let array = unsafe { &**array };
let cache = unsafe { &**cache };
let chunk_indices = unsafe { std::slice::from_raw_parts(pChunkIndices, dimensionality) };
match array {
ZarrsArrayEnum::R(array) => zarrsArrayRetrieveSubChunkImpl(
array,
cache,
chunk_indices,
chunkBytesCount,
pChunkBytes,
),
ZarrsArrayEnum::RL(array) => zarrsArrayRetrieveSubChunkImpl(
array,
cache,
chunk_indices,
chunkBytesCount,
pChunkBytes,
),
ZarrsArrayEnum::RW(array) => zarrsArrayRetrieveSubChunkImpl(
array,
cache,
chunk_indices,
chunkBytesCount,
pChunkBytes,
),
ZarrsArrayEnum::RWL(array) => zarrsArrayRetrieveSubChunkImpl(
array,
cache,
chunk_indices,
chunkBytesCount,
pChunkBytes,
),
_ => {
*LAST_ERROR.lock().unwrap() = "storage does not have read capability".to_string();
ZarrsResult::ZARRS_ERROR_STORAGE_CAPABILITY
}
}
}
fn zarrsArrayRetrieveSubsetShardedImpl<T: ReadableStorageTraits + ?Sized + 'static>(
array: &Array<T>,
cache: &ArrayShardedReadableExtCache,
array_subset: &ArraySubset,
subset_bytes_length: usize,
subset_bytes: *mut u8,
) -> ZarrsResult {
match array.retrieve_array_subset_sharded_opt::<ArrayBytes>(
cache,
array_subset,
&CodecOptions::default(),
) {
Ok(bytes) => {
let Ok(bytes) = bytes.into_fixed() else {
*LAST_ERROR.lock().unwrap() =
"variable size data types are not supported".to_string();
return ZarrsResult::ZARRS_ERROR_UNSUPPORTED_DATA_TYPE;
};
if bytes.len() != subset_bytes_length {
*LAST_ERROR.lock().unwrap() = format!(
"subset_bytes_length {subset_bytes_length} does not match decoded subset size {}",
bytes.len()
);
ZarrsResult::ZARRS_ERROR_BUFFER_LENGTH
} else {
unsafe { std::ptr::copy(bytes.as_ptr(), subset_bytes, subset_bytes_length) };
ZarrsResult::ZARRS_SUCCESS
}
}
Err(err) => {
*LAST_ERROR.lock().unwrap() = err.to_string();
ZarrsResult::ZARRS_ERROR_ARRAY
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zarrsArrayRetrieveSubsetSharded(
array: ZarrsArray,
cache: ZarrsShardIndexCache,
dimensionality: usize,
pSubsetStart: *const u64,
pSubsetShape: *const u64,
subsetBytesCount: usize,
pSubsetBytes: *mut u8,
) -> ZarrsResult {
if array.is_null() || cache.is_null() {
return ZarrsResult::ZARRS_ERROR_NULL_PTR;
}
let array = unsafe { &**array };
let cache = unsafe { &**cache };
let subset_start = unsafe { std::slice::from_raw_parts(pSubsetStart, dimensionality) };
let subset_shape = unsafe { std::slice::from_raw_parts(pSubsetShape, dimensionality) };
let array_subset = ArraySubset::from(
std::iter::zip(subset_start, subset_shape).map(|(&start, &shape)| start..start + shape),
);
match array {
ZarrsArrayEnum::R(array) => zarrsArrayRetrieveSubsetShardedImpl(
array,
cache,
&array_subset,
subsetBytesCount,
pSubsetBytes,
),
ZarrsArrayEnum::RL(array) => zarrsArrayRetrieveSubsetShardedImpl(
array,
cache,
&array_subset,
subsetBytesCount,
pSubsetBytes,
),
ZarrsArrayEnum::RW(array) => zarrsArrayRetrieveSubsetShardedImpl(
array,
cache,
&array_subset,
subsetBytesCount,
pSubsetBytes,
),
ZarrsArrayEnum::RWL(array) => zarrsArrayRetrieveSubsetShardedImpl(
array,
cache,
&array_subset,
subsetBytesCount,
pSubsetBytes,
),
_ => {
*LAST_ERROR.lock().unwrap() = "storage does not have read capability".to_string();
ZarrsResult::ZARRS_ERROR_STORAGE_CAPABILITY
}
}
}