1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
/****************************************************************
* *
* Copyright (c) 2021 YottaDB LLC and/or its subsidiaries. *
* All rights reserved. *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
* under a license. If you do not know the terms of *
* the license, please stop and do not read further. *
* *
****************************************************************/
//! A 'Call In' is an FFI call from Rust to M.
//!
//! Call-ins usually go through `ci_t`, but `cip_t` is also available for better performance.
//!
//! # See also
//! - [Using External Calls](https://docs.yottadb.com/ProgrammersGuide/extrout.html#using-external-calls)
use std::ffi::{CString, CStr};
use crate::craw::ci_name_descriptor;
use super::{resize_call, YDBResult, TpToken};
/// The descriptor for a call-in table opened with [`ci_tab_open`].
///
/// `CallInTableDescriptor::default()` returns a table which,
/// when called with [`ci_tab_switch`], uses the environment variable `ydb_ci`.
/// This is also the table that is used if `ci_tab_switch_t` is never called.
///
/// [`ci_tab_open`]: crate::Context::ci_tab_open
/// [`ci_tab_switch`]: crate::Context::ci_tab_switch
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct CallInTableDescriptor(usize);
/// Open the call-in table stored in `file` and return its file descriptor.
///
/// See also [Context::ci_tab_open](crate::context_api::Context::ci_tab_open).
pub(crate) fn ci_tab_open_t(
tptoken: TpToken, err_buffer: Vec<u8>, file: &CStr,
) -> YDBResult<(CallInTableDescriptor, Vec<u8>)> {
use crate::craw::ydb_ci_tab_open_t;
// this cast is safe because YDB never modifies the string
let ptr = file.as_ptr() as *mut _;
let mut ret_val: usize = 0;
let buf = resize_call(tptoken, err_buffer, |tptoken, err_buffer_p| unsafe {
ydb_ci_tab_open_t(tptoken, err_buffer_p, ptr, &mut ret_val)
})?;
Ok((CallInTableDescriptor(ret_val), buf))
}
/// Switch the active call-in table to `new_handle`. Returns the previously active table.
///
/// See also [Context::ci_tab_switch](crate::context_api::Context::ci_tab_switch).
pub(crate) fn ci_tab_switch_t(
tptoken: TpToken, err_buffer: Vec<u8>, new_handle: CallInTableDescriptor,
) -> YDBResult<(CallInTableDescriptor, Vec<u8>)> {
use crate::craw::ydb_ci_tab_switch_t;
let mut ret_val: usize = 0;
let buf = resize_call(tptoken, err_buffer, |tptoken, err_buffer_p| unsafe {
ydb_ci_tab_switch_t(tptoken, err_buffer_p, new_handle.0, &mut ret_val)
})?;
Ok((CallInTableDescriptor(ret_val), buf))
}
/// A call-in descriptor for use with [`cip_t!`].
///
/// This represents an M function described in a call-in table.
/// The descriptor is lazily initialized on the first call to `cip_t!`,
/// and future calls will be much faster to execute.
///
/// [`cip_t!`]: crate::cip_t!
pub struct CallInDescriptor(ci_name_descriptor);
impl CallInDescriptor {
/// Create a new `descriptor` that will call `routine`.
pub fn new(routine: CString) -> Self {
use crate::craw::ydb_string_t;
use std::os::raw::c_ulong;
let string = ydb_string_t {
length: routine.as_bytes().len() as c_ulong,
address: routine.into_raw(),
};
Self(ci_name_descriptor { rtn_name: string, handle: std::ptr::null_mut() })
}
/// Consume this descriptor and return the original routine
pub fn into_cstr(self) -> CString {
let cstr = unsafe { CString::from_raw(self.0.rtn_name.address) };
std::mem::forget(self);
cstr
}
// this needs to be public so it can be used in a macro
#[doc(hidden)]
pub fn as_mut_ptr(&mut self) -> *mut ci_name_descriptor {
&mut self.0
}
}
impl Drop for CallInDescriptor {
fn drop(&mut self) {
// TODO: this is doing the same thing as `into_cstr`
drop(unsafe { CString::from_raw(self.0.rtn_name.address) })
}
}