use std::ffi::c_char;
use crate::error::{Status, gpkg_error_t, set_error, set_library_error};
use crate::handle::{Container, LayerHandle};
use crate::util::{borrow_str, out_string};
#[expect(
non_camel_case_types,
reason = "the C name is the type's name; cbindgen emits it verbatim"
)]
pub type gpkg_layer_t = LayerHandle;
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_layer_open(
gpkg: *const Container,
name: *const c_char,
error: *mut gpkg_error_t,
) -> *mut gpkg_layer_t {
unsafe { open_layer(gpkg, name, error, false) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_attributes_open(
gpkg: *const Container,
name: *const c_char,
error: *mut gpkg_error_t,
) -> *mut gpkg_layer_t {
unsafe { open_layer(gpkg, name, error, true) }
}
unsafe fn open_layer(
gpkg: *const Container,
name: *const c_char,
error: *mut gpkg_error_t,
attributes: bool,
) -> *mut gpkg_layer_t {
if gpkg.is_null() {
unsafe { set_error(error, Status::BadArgument, "gpkg handle is NULL") };
return std::ptr::null_mut();
}
let Some(name) = (unsafe { borrow_str(name, error, "layer name") }) else {
return std::ptr::null_mut();
};
let container = unsafe { &*gpkg };
let opened = if attributes {
container.attributes(name)
} else {
container.layer(name)
};
match opened {
Ok(handle) => Box::into_raw(Box::new(handle)),
Err(err) => {
unsafe { set_library_error(error, &err) };
std::ptr::null_mut()
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_layer_open_with_columns(
gpkg: *const Container,
name: *const c_char,
columns: *const *const c_char,
columns_len: usize,
error: *mut gpkg_error_t,
) -> *mut gpkg_layer_t {
unsafe { open_layer_with_columns(gpkg, name, columns, columns_len, error, false) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_attributes_open_with_columns(
gpkg: *const Container,
name: *const c_char,
columns: *const *const c_char,
columns_len: usize,
error: *mut gpkg_error_t,
) -> *mut gpkg_layer_t {
unsafe { open_layer_with_columns(gpkg, name, columns, columns_len, error, true) }
}
unsafe fn open_layer_with_columns(
gpkg: *const Container,
name: *const c_char,
columns: *const *const c_char,
columns_len: usize,
error: *mut gpkg_error_t,
attributes: bool,
) -> *mut gpkg_layer_t {
if gpkg.is_null() || (columns.is_null() && columns_len != 0) {
unsafe { set_error(error, Status::BadArgument, "gpkg handle or columns is NULL") };
return std::ptr::null_mut();
}
let Some(name) = (unsafe { borrow_str(name, error, "layer name") }) else {
return std::ptr::null_mut();
};
let mut names = Vec::with_capacity(columns_len);
for index in 0..columns_len {
let slot = unsafe { columns.add(index) };
let column = unsafe { *slot };
let Some(text) = (unsafe { borrow_str(column, error, "column name") }) else {
return std::ptr::null_mut();
};
names.push(text);
}
let container = unsafe { &*gpkg };
match container.layer_with_columns(name, &names, attributes) {
Ok(handle) => Box::into_raw(Box::new(handle)),
Err(err) => {
unsafe { set_library_error(error, &err) };
std::ptr::null_mut()
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_layer_free(layer: *mut gpkg_layer_t) {
if layer.is_null() {
return;
}
drop(unsafe { Box::from_raw(layer) });
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_layer_name(
layer: *const gpkg_layer_t,
error: *mut gpkg_error_t,
) -> *mut c_char {
if layer.is_null() {
unsafe { set_error(error, Status::BadArgument, "layer handle is NULL") };
return std::ptr::null_mut();
}
let name = unsafe { (*layer).layer().table_name().to_owned() };
unsafe { out_string(&name, error) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_layer_count(
layer: *const gpkg_layer_t,
out: *mut u64,
error: *mut gpkg_error_t,
) -> Status {
if layer.is_null() || out.is_null() {
unsafe { set_error(error, Status::BadArgument, "layer handle or out is NULL") };
return Status::BadArgument;
}
match unsafe { (*layer).layer().count() } {
Ok(count) => {
unsafe { *out = count };
Status::Ok
}
Err(err) => {
unsafe { set_library_error(error, &err) };
Status::from(&err)
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_layer_names_count(
gpkg: *const Container,
out: *mut usize,
error: *mut gpkg_error_t,
) -> Status {
if gpkg.is_null() || out.is_null() {
unsafe { set_error(error, Status::BadArgument, "gpkg handle or out is NULL") };
return Status::BadArgument;
}
match unsafe { (*gpkg).gpkg().layers() } {
Ok(layers) => {
unsafe { *out = layers.len() };
Status::Ok
}
Err(err) => {
unsafe { set_library_error(error, &err) };
Status::from(&err)
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gpkg_layer_name_at(
gpkg: *const Container,
index: usize,
error: *mut gpkg_error_t,
) -> *mut c_char {
if gpkg.is_null() {
unsafe { set_error(error, Status::BadArgument, "gpkg handle is NULL") };
return std::ptr::null_mut();
}
let layers = match unsafe { (*gpkg).gpkg().layers() } {
Ok(layers) => layers,
Err(err) => {
unsafe { set_library_error(error, &err) };
return std::ptr::null_mut();
}
};
let Some(layer) = layers.get(index) else {
unsafe { set_error(error, Status::NotFound, "layer index out of range") };
return std::ptr::null_mut();
};
let name = layer.table_name().to_owned();
unsafe { out_string(&name, error) }
}