#![crate_name = "meos"]
#![crate_type = "lib"]
#![cfg_attr(doc, doc = include_str!("../README.md"))]
#![doc(html_logo_url = "https://libmeos.org/brand.svg")]
#![allow(refining_impl_trait)]
#![allow(clippy::non_canonical_partial_ord_impl)]
#![warn(clippy::pedantic)]
#![allow(clippy::missing_panics_doc)]
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::doc_lazy_continuation)]
#![allow(clippy::return_self_not_must_use)]
#![allow(clippy::used_underscore_binding)]
#![allow(clippy::cast_possible_wrap)]
#![allow(clippy::cast_possible_truncation)]
#![allow(clippy::must_use_candidate)]
#![allow(clippy::cast_sign_loss)]
use std::{
ffi::{CStr, CString},
fmt::Debug,
sync::Once,
};
use bitmask_enum::bitmask;
use boxes::Box as MeosBox;
pub use meos_sys as sys;
mod boxes;
pub use boxes::{Box, STBox, TBox};
mod collections;
pub use collections::base::{Collection, Span, SpanSet};
pub use collections::datetime::{DateSpan, DateSpanSet, TsTzSpan, TsTzSpanSet};
pub use collections::number::*;
mod errors;
pub use errors::ParseError;
mod temporal;
pub use temporal::*;
pub(crate) mod utils;
static START: Once = Once::new();
#[allow(dead_code)]
extern "C" fn finalize() {
unsafe {
meos_sys::meos_finalize();
}
}
pub trait BoundingBox: Collection {}
impl<T> BoundingBox for T where T: MeosBox {}
unsafe extern "C" fn error_handler(_error_level: i32, _error_code: i32, message: *const i8) {
let message = CStr::from_ptr(message).to_str().unwrap();
panic!("{}", message);
}
pub fn meos_initialize() {
START.call_once(|| unsafe {
#[cfg(feature = "bundled")]
{
let path = CString::new(env!("MEOS_SPATIAL_REF_SYS_CSV")).unwrap();
meos_sys::meos_set_spatial_ref_sys_csv(path.as_ptr());
}
meos_sys::meos_initialize();
meos_sys::meos_initialize_error_handler(Some(error_handler));
});
}
pub fn meos_initialize_timezone(tz: &str) {
unsafe {
#[allow(clippy::missing_panics_doc)]
let ptr = CString::new(tz).expect("Wrong timezone format");
meos_sys::meos_initialize_timezone(ptr.as_ptr());
}
}
fn factory<T: MeosEnum>(temporal: *mut meos_sys::Temporal) -> T {
let temporal_type: TemporalSubtype = unsafe { u32::from(temporal.read().subtype).into() };
match temporal_type {
TemporalSubtype::Instant => T::from_instant(temporal.cast()),
TemporalSubtype::Sequence => T::from_sequence(temporal.cast()),
TemporalSubtype::SequenceSet => T::from_sequence_set(temporal.cast()),
TemporalSubtype::Any => unreachable!(),
}
}
#[bitmask(u8)]
pub enum WKBVariant {
NDR = meos_sys::WKB_NDR as u8,
XDR = meos_sys::WKB_XDR as u8,
Extended = meos_sys::WKB_EXTENDED as u8,
}
#[derive(Debug, PartialEq)]
pub enum TemporalSubtype {
Any = meos_sys::tempSubtype_ANYTEMPSUBTYPE as isize,
Instant = meos_sys::tempSubtype_TINSTANT as isize,
Sequence = meos_sys::tempSubtype_TSEQUENCE as isize,
SequenceSet = meos_sys::tempSubtype_TSEQUENCESET as isize,
}
impl From<u32> for TemporalSubtype {
fn from(value: u32) -> Self {
match value {
meos_sys::tempSubtype_TINSTANT => TemporalSubtype::Instant,
meos_sys::tempSubtype_TSEQUENCE => TemporalSubtype::Sequence,
meos_sys::tempSubtype_TSEQUENCESET => TemporalSubtype::SequenceSet,
_ => TemporalSubtype::Any, }
}
}
pub trait MeosEnum: Debug + Sized + Temporal {
fn from_instant(inner: *mut meos_sys::TInstant) -> Self;
fn from_sequence(inner: *mut meos_sys::TSequence) -> Self;
fn from_sequence_set(inner: *mut meos_sys::TSequenceSet) -> Self;
fn from_mfjson(mfjson: &str) -> Self;
fn from_wkb(wkb: &[u8]) -> Self {
factory::<Self>(unsafe { meos_sys::temporal_from_wkb(wkb.as_ptr(), wkb.len()) })
}
fn from_hexwkb(hexwkb: &[u8]) -> Self {
let c_hexwkb = CString::new(hexwkb).unwrap();
unsafe {
let inner = meos_sys::temporal_from_hexwkb(c_hexwkb.as_ptr());
factory::<Self>(inner)
}
}
fn from_merge(temporals: &[Self]) -> Self {
let mut t_list: Vec<*mut meos_sys::Temporal> = temporals
.iter()
.map(|t| Self::inner(t).cast_mut())
.collect();
factory::<Self>(unsafe {
meos_sys::temporal_merge_array(t_list.as_mut_ptr(), temporals.len() as i32)
})
}
fn as_mfjson(
&self,
with_bbox: bool,
variant: JSONCVariant,
precision: i32,
srs: &str,
) -> String {
let srs = CString::new(srs).unwrap();
let out_str = unsafe {
meos_sys::temporal_as_mfjson(
self.inner(),
with_bbox,
variant as i32,
precision,
srs.as_ptr(),
)
};
let c_str = unsafe { CStr::from_ptr(out_str) };
let str = c_str.to_str().unwrap().to_owned();
unsafe { libc::free(out_str.cast()) };
str
}
fn as_wkb(&self, variant: WKBVariant) -> &[u8] {
unsafe {
let mut size: usize = 0;
let ptr = meos_sys::temporal_as_wkb(self.inner(), variant.into(), &raw mut size);
std::slice::from_raw_parts(ptr, size)
}
}
fn as_hexwkb(&self, variant: WKBVariant) -> &[u8] {
unsafe {
let mut size: usize = 0;
let hexwkb_ptr =
meos_sys::temporal_as_hexwkb(self.inner(), variant.into(), &raw mut size);
CStr::from_ptr(hexwkb_ptr).to_bytes()
}
}
}
macro_rules! impl_from_str {
($type:ty) => {
paste::paste! {
impl FromStr for $type {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
CString::new(s).map_err(|_| ParseError).map(|string| {
let inner = unsafe { meos_sys::[<$type:lower _in>](string.as_ptr()) };
factory::<Self>(inner)
})
}
}}
};
}
pub(crate) use impl_from_str;