use crate::error::IntoBoxError;
use crate::ffi::tarantool as ffi;
use crate::tuple::{FunctionCtx, RawByteBuf, RawBytes, Tuple, TupleBuffer};
use serde::Serialize;
use std::os::raw::c_int;
use std::path::Path;
macro_rules! unwrap_or_report_err {
($res:expr) => {
match $res {
Ok(o) => o,
Err(e) => {
e.set_last_error();
-1
}
}
};
}
#[derive(Debug, Clone)]
pub struct Proc {
name: &'static str,
proc: ffi::Proc,
public: bool,
}
impl Proc {
#[inline(always)]
pub const fn new(name: &'static str, proc: ffi::Proc) -> Self {
Self {
name,
proc,
public: false,
}
}
#[inline(always)]
pub const fn with_public(mut self, public: bool) -> Self {
self.public = public;
self
}
#[inline(always)]
pub const fn name(&self) -> &'static str {
self.name
}
#[inline(always)]
pub const fn proc(&self) -> ffi::Proc {
self.proc
}
#[inline(always)]
pub const fn is_public(&self) -> bool {
self.public
}
}
#[cfg(feature = "stored_procs_slice")]
pub use stored_procs_slice::*;
#[cfg(feature = "stored_procs_slice")]
mod stored_procs_slice {
use super::*;
#[doc(hidden)]
#[::linkme::distributed_slice]
pub static TARANTOOL_MODULE_STORED_PROCS: [Proc] = [..];
#[inline(always)]
pub fn all_procs() -> &'static [Proc] {
&TARANTOOL_MODULE_STORED_PROCS
}
}
#[cfg(not(feature = "stored_procs_slice"))]
pub fn all_procs() -> &'static [Proc] {
panic!("`stored_procs_slice` feature is disabled, calling this function doesn't make sense");
}
pub fn module_path(sym: *const ()) -> Option<&'static Path> {
unsafe {
let mut info: libc::Dl_info = std::mem::zeroed();
if libc::dladdr(sym as _, &mut info) == 0 {
return None;
}
if info.dli_fname.is_null() {
return None;
}
let path = std::ffi::CStr::from_ptr(info.dli_fname);
let path: &std::ffi::OsStr = std::os::unix::ffi::OsStrExt::from_bytes(path.to_bytes());
Some(Path::new(path))
}
}
pub struct ReturnMsgpack<T>(pub T);
impl<T: Serialize> Return for ReturnMsgpack<T> {
#[inline(always)]
#[track_caller]
fn ret(self, ctx: FunctionCtx) -> c_int {
unwrap_or_report_err!(ctx.return_mp(&self.0))
}
}
pub trait Return: Sized {
fn ret(self, ctx: FunctionCtx) -> c_int;
}
impl Return for Tuple {
#[inline]
#[track_caller]
fn ret(self, ctx: FunctionCtx) -> c_int {
let res = ctx.return_tuple(&self);
unwrap_or_report_err!(res)
}
}
impl<E> Return for Result<Tuple, E>
where
E: IntoBoxError,
{
#[inline(always)]
#[track_caller]
fn ret(self, ctx: FunctionCtx) -> c_int {
unwrap_or_report_err!(self.map(|t| t.ret(ctx)))
}
}
impl Return for TupleBuffer {
#[inline]
#[track_caller]
fn ret(self, ctx: FunctionCtx) -> c_int {
let res = ctx.return_bytes(self.as_ref());
unwrap_or_report_err!(res)
}
}
impl<E> Return for Result<TupleBuffer, E>
where
E: IntoBoxError,
{
#[inline(always)]
#[track_caller]
fn ret(self, ctx: FunctionCtx) -> c_int {
unwrap_or_report_err!(self.map(|t| t.ret(ctx)))
}
}
impl Return for &RawBytes {
#[inline]
#[track_caller]
fn ret(self, ctx: FunctionCtx) -> c_int {
let res = ctx.return_bytes(self);
unwrap_or_report_err!(res)
}
}
impl<E> Return for Result<&RawBytes, E>
where
E: IntoBoxError,
{
#[inline(always)]
#[track_caller]
fn ret(self, ctx: FunctionCtx) -> c_int {
unwrap_or_report_err!(self.map(|t| t.ret(ctx)))
}
}
impl Return for RawByteBuf {
#[inline]
#[track_caller]
fn ret(self, ctx: FunctionCtx) -> c_int {
let res = ctx.return_bytes(&self);
unwrap_or_report_err!(res)
}
}
impl<E> Return for Result<RawByteBuf, E>
where
E: IntoBoxError,
{
#[inline(always)]
#[track_caller]
fn ret(self, ctx: FunctionCtx) -> c_int {
unwrap_or_report_err!(self.map(|t| t.ret(ctx)))
}
}
impl Return for () {
#[inline(always)]
fn ret(self, _: FunctionCtx) -> c_int {
0
}
}
impl<O, E> Return for Result<O, E>
where
O: Serialize,
E: IntoBoxError,
{
#[inline(always)]
#[track_caller]
fn ret(self, ctx: FunctionCtx) -> c_int {
match self {
Ok(o) => match ctx.return_mp(&o) {
Ok(_) => 0,
Err(e) => {
e.set_last_error();
-1
}
},
Err(e) => {
e.set_last_error();
-1
}
}
}
}
macro_rules! impl_return {
(impl $([ $( $tp:tt )* ])? for $t:ty) => {
impl $(< $($tp)* >)? Return for $t
where
Self: Serialize,
{
#[inline(always)]
#[track_caller]
fn ret(self, ctx: FunctionCtx) -> c_int {
unwrap_or_report_err!(ctx.return_mp(&self))
}
}
};
($( $t:ty )+) => {
$( impl_return!{ impl for $t } )+
}
}
impl_return! { impl[V] for Option<V> }
impl_return! { impl[V] for Vec<V> }
impl_return! { impl[V] for &'_ [V] }
impl_return! { impl[V, const N: usize] for [V; N] }
impl_return! { impl[K, V] for std::collections::HashMap<K, V> }
impl_return! { impl[K] for std::collections::HashSet<K> }
impl_return! { impl[K, V] for std::collections::BTreeMap<K, V> }
impl_return! { impl[K] for std::collections::BTreeSet<K> }
impl_return! {
bool
i8 u8 i16 u16 i32 u32 i64 u64 i128 u128 isize usize
f32 f64
String &'_ str
std::ffi::CString &'_ std::ffi::CStr
}
macro_rules! impl_return_for_tuple {
() => {};
($h:ident $($t:ident)*) => {
impl<$h, $($t),*> Return for ($h, $($t,)*)
where
Self: Serialize,
{
#[inline(always)]
#[track_caller]
fn ret(self, ctx: FunctionCtx) -> c_int {
unwrap_or_report_err!(ctx.return_mp(&self))
}
}
impl_return_for_tuple!{$($t)*}
}
}
impl_return_for_tuple! {A B C D E F G H I J K L M N O P Q}
#[cfg(feature = "extra_impls")]
impl Return for smol_str::SmolStr {
#[inline]
#[track_caller]
fn ret(self, ctx: FunctionCtx) -> c_int {
unwrap_or_report_err!(ctx.return_mp(&self))
}
}