use std::ffi::c_char;
use geopackage::SpatialIndexStatus;
use crate::error::{Status, gpkg_error_t, report, set_error, set_library_error};
use crate::handle::LayerHandle;
use crate::util::out_string;
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_layer_kind(
layer: *const LayerHandle,
error: *mut gpkg_error_t,
) -> *mut c_char {
let Some(handle) = (unsafe { checked(layer, error, "gpkg_layer_kind") }) else {
return std::ptr::null_mut();
};
let kind = handle.layer().kind().as_str();
unsafe { out_string(kind, error) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_layer_column_count(
layer: *const LayerHandle,
out: *mut usize,
error: *mut gpkg_error_t,
) -> Status {
if out.is_null() {
unsafe { set_error(error, Status::BadArgument, "out is NULL") };
return Status::BadArgument;
}
let Some(handle) = (unsafe { checked(layer, error, "gpkg_layer_column_count") }) else {
return Status::BadArgument;
};
let count = handle.layer().schema().columns.len();
unsafe { *out = count };
Status::Ok
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_layer_column_name(
layer: *const LayerHandle,
index: usize,
error: *mut gpkg_error_t,
) -> *mut c_char {
let Some(handle) = (unsafe { checked(layer, error, "gpkg_layer_column_name") }) else {
return std::ptr::null_mut();
};
let Some(column) = handle.layer().schema().columns.get(index) else {
unsafe { set_error(error, Status::NotFound, "column index out of range") };
return std::ptr::null_mut();
};
let name = column.name.clone();
unsafe { out_string(&name, error) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_layer_column_type(
layer: *const LayerHandle,
index: usize,
error: *mut gpkg_error_t,
) -> *mut c_char {
let Some(handle) = (unsafe { checked(layer, error, "gpkg_layer_column_type") }) else {
return std::ptr::null_mut();
};
let Some(column) = handle.layer().schema().columns.get(index) else {
unsafe { set_error(error, Status::NotFound, "column index out of range") };
return std::ptr::null_mut();
};
let declared = column.declared_type.clone();
unsafe { out_string(&declared, error) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_layer_column_is_primary_key(
layer: *const LayerHandle,
index: usize,
) -> bool {
if layer.is_null() {
return false;
}
let handle = unsafe { &*layer };
handle
.layer()
.schema()
.columns
.get(index)
.is_some_and(geopackage::Column::is_primary_key)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_layer_geometry_column(
layer: *const LayerHandle,
error: *mut gpkg_error_t,
) -> *mut c_char {
let Some(handle) = (unsafe { checked(layer, error, "gpkg_layer_geometry_column") }) else {
return std::ptr::null_mut();
};
let Some(geometry) = handle.layer().geometry_column() else {
return std::ptr::null_mut();
};
let name = geometry.column_name.clone();
unsafe { out_string(&name, error) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_layer_geometry_type(
layer: *const LayerHandle,
error: *mut gpkg_error_t,
) -> *mut c_char {
let Some(handle) = (unsafe { checked(layer, error, "gpkg_layer_geometry_type") }) else {
return std::ptr::null_mut();
};
let Some(geometry) = handle.layer().geometry_column() else {
return std::ptr::null_mut();
};
let name = geometry.geometry_type.to_string();
unsafe { out_string(&name, error) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_layer_srs_id(
layer: *const LayerHandle,
out: *mut i32,
error: *mut gpkg_error_t,
) -> Status {
if out.is_null() {
unsafe { set_error(error, Status::BadArgument, "out is NULL") };
return Status::BadArgument;
}
let Some(handle) = (unsafe { checked(layer, error, "gpkg_layer_srs_id") }) else {
return Status::BadArgument;
};
let Some(geometry) = handle.layer().geometry_column() else {
unsafe { set_error(error, Status::NotFound, "layer has no geometry column") };
return Status::NotFound;
};
unsafe { *out = geometry.srs_id };
Status::Ok
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_layer_extent(
layer: *const LayerHandle,
min_x: *mut f64,
min_y: *mut f64,
max_x: *mut f64,
max_y: *mut f64,
error: *mut gpkg_error_t,
) -> Status {
if min_x.is_null() || min_y.is_null() || max_x.is_null() || max_y.is_null() {
unsafe {
set_error(
error,
Status::BadArgument,
"an extent out-parameter is NULL",
)
};
return Status::BadArgument;
}
let Some(handle) = (unsafe { checked(layer, error, "gpkg_layer_extent") }) else {
return Status::BadArgument;
};
let extent = match handle.layer().extent() {
Ok(extent) => extent,
Err(err) => {
unsafe { set_library_error(error, &err) };
return Status::from(&err);
}
};
let Some(bbox) = extent else {
unsafe { set_error(error, Status::NotFound, "layer has no extent") };
return Status::NotFound;
};
unsafe {
*min_x = bbox.min_x;
}
unsafe {
*min_y = bbox.min_y;
}
unsafe {
*max_x = bbox.max_x;
}
unsafe {
*max_y = bbox.max_y;
}
Status::Ok
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_layer_spatial_index_status(
layer: *const LayerHandle,
error: *mut gpkg_error_t,
) -> *mut c_char {
let Some(handle) = (unsafe { checked(layer, error, "gpkg_layer_spatial_index_status") }) else {
return std::ptr::null_mut();
};
match handle.layer().spatial_index_status() {
Ok(status) => {
unsafe { out_string(status.as_str(), error) }
}
Err(err) => {
unsafe { set_library_error(error, &err) };
std::ptr::null_mut()
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_layer_has_spatial_index(
layer: *const LayerHandle,
out: *mut bool,
error: *mut gpkg_error_t,
) -> Status {
if out.is_null() {
unsafe { set_error(error, Status::BadArgument, "out is NULL") };
return Status::BadArgument;
}
let Some(handle) = (unsafe { checked(layer, error, "gpkg_layer_has_spatial_index") }) else {
return Status::BadArgument;
};
match handle.layer().has_spatial_index() {
Ok(has) => {
unsafe { *out = has };
Status::Ok
}
Err(err) => {
unsafe { set_library_error(error, &err) };
Status::from(&err)
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_layer_create_spatial_index(
layer: *const LayerHandle,
error: *mut gpkg_error_t,
) -> Status {
let Some(handle) = (unsafe { checked(layer, error, "gpkg_layer_create_spatial_index") }) else {
return Status::BadArgument;
};
unsafe { report(handle.layer().create_spatial_index(), error) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_layer_drop_spatial_index(
layer: *const LayerHandle,
error: *mut gpkg_error_t,
) -> Status {
let Some(handle) = (unsafe { checked(layer, error, "gpkg_layer_drop_spatial_index") }) else {
return Status::BadArgument;
};
unsafe { report(handle.layer().drop_spatial_index(), error) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_layer_repair_spatial_index(
layer: *const LayerHandle,
error: *mut gpkg_error_t,
) -> Status {
let Some(handle) = (unsafe { checked(layer, error, "gpkg_layer_repair_spatial_index") }) else {
return Status::BadArgument;
};
let status = match handle.layer().spatial_index_status() {
Ok(status) => status,
Err(err) => {
unsafe { set_library_error(error, &err) };
return Status::from(&err);
}
};
match status {
SpatialIndexStatus::Legacy | SpatialIndexStatus::Stale => {
unsafe { report(handle.layer().repair_spatial_index(), error) }
}
_ => Status::Ok,
}
}
unsafe fn checked<'a>(
layer: *const LayerHandle,
error: *mut gpkg_error_t,
what: &str,
) -> Option<&'a LayerHandle> {
if layer.is_null() {
unsafe {
set_error(
error,
Status::BadArgument,
&format!("{what}: layer is NULL"),
)
};
return None;
}
Some(unsafe { &*layer })
}