use std::convert::TryFrom;
use std::ffi::c_void;
use std::fmt::{Display, Error as FmtError, Formatter};
use std::marker::PhantomData;
use std::mem::MaybeUninit;
use std::ops::Deref;
use std::ptr;
use std::slice;
use std::str;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use crate::runtime::options;
use crate::sql::allocator::{self, Ref as AllocatorRef};
use crate::sql::{mcosql_error_code, result_from_code};
use crate::{exdb_sys, Error, Result};
use exdb_sys::mcosql_column_type;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Type {
Null = mcosql_column_type::CT_NULL as isize,
Bool = mcosql_column_type::CT_BOOL as isize,
Int1 = mcosql_column_type::CT_INT1 as isize,
Int2 = mcosql_column_type::CT_INT2 as isize,
Int4 = mcosql_column_type::CT_INT4 as isize,
Int8 = mcosql_column_type::CT_INT8 as isize,
UInt1 = mcosql_column_type::CT_UINT1 as isize,
UInt2 = mcosql_column_type::CT_UINT2 as isize,
UInt4 = mcosql_column_type::CT_UINT4 as isize,
UInt8 = mcosql_column_type::CT_UINT8 as isize,
Real4 = mcosql_column_type::CT_REAL4 as isize,
Real8 = mcosql_column_type::CT_REAL8 as isize,
Time = mcosql_column_type::CT_TIME as isize,
Numeric = mcosql_column_type::CT_NUMERIC as isize,
String = mcosql_column_type::CT_STRING as isize,
Binary = mcosql_column_type::CT_BINARY as isize,
Array = mcosql_column_type::CT_ARRAY as isize,
Blob = mcosql_column_type::CT_BLOB as isize,
Sequence = mcosql_column_type::CT_SEQUENCE as isize,
}
impl Type {
pub(crate) fn from_mco(v: mcosql_column_type::Type) -> Option<Self> {
match v {
mcosql_column_type::CT_NULL => Some(Type::Null),
mcosql_column_type::CT_BOOL => Some(Type::Bool),
mcosql_column_type::CT_INT1 => Some(Type::Int1),
mcosql_column_type::CT_INT2 => Some(Type::Int2),
mcosql_column_type::CT_INT4 => Some(Type::Int4),
mcosql_column_type::CT_INT8 => Some(Type::Int8),
mcosql_column_type::CT_UINT1 => Some(Type::UInt1),
mcosql_column_type::CT_UINT2 => Some(Type::UInt2),
mcosql_column_type::CT_UINT4 => Some(Type::UInt4),
mcosql_column_type::CT_UINT8 => Some(Type::UInt8),
mcosql_column_type::CT_REAL4 => Some(Type::Real4),
mcosql_column_type::CT_REAL8 => Some(Type::Real8),
mcosql_column_type::CT_TIME => Some(Type::Time),
mcosql_column_type::CT_NUMERIC => Some(Type::Numeric),
mcosql_column_type::CT_STRING => Some(Type::String),
mcosql_column_type::CT_BINARY => Some(Type::Binary),
mcosql_column_type::CT_ARRAY => Some(Type::Array),
mcosql_column_type::CT_BLOB => Some(Type::Blob),
mcosql_column_type::CT_SEQUENCE => Some(Type::Sequence),
_ => None,
}
}
}
#[repr(transparent)]
pub struct Value<'a> {
alloc: PhantomData<&'a AllocatorRef<'a>>,
h: exdb_sys::mcosql_rs_value,
}
impl<'a> Value<'a> {
fn from_handle(h: exdb_sys::mcosql_rs_value, _allocator: AllocatorRef<'a>) -> Self {
Value {
alloc: PhantomData,
h,
}
}
fn new_null() -> Result<Self> {
let mut h = MaybeUninit::uninit();
result_from_code(unsafe { exdb_sys::mcosql_rs_value_create_null(h.as_mut_ptr()) }).and(Ok(
Value {
alloc: PhantomData,
h: unsafe { h.assume_init() },
},
))
}
fn new_bool(val: bool) -> Result<Self> {
let ival = if val { 1 } else { 0 };
let mut h = MaybeUninit::uninit();
result_from_code(unsafe { exdb_sys::mcosql_rs_value_create_bool(ival, h.as_mut_ptr()) })
.and(Ok(Value {
alloc: PhantomData,
h: unsafe { h.assume_init() },
}))
}
fn new_int(val: i64, alloc: AllocatorRef<'a>) -> Result<Self> {
let mut h = MaybeUninit::uninit();
result_from_code(unsafe {
exdb_sys::mcosql_rs_value_create_int(alloc.h, val, h.as_mut_ptr())
})
.and(Ok(Value {
alloc: PhantomData,
h: unsafe { h.assume_init() },
}))
}
fn new_real(val: f64, alloc: AllocatorRef<'a>) -> Result<Self> {
let mut h = MaybeUninit::uninit();
result_from_code(unsafe {
exdb_sys::mcosql_rs_value_create_real(alloc.h, val, h.as_mut_ptr())
})
.and(Ok(Value {
alloc: PhantomData,
h: unsafe { h.assume_init() },
}))
}
fn new_string(val: &str, alloc: AllocatorRef<'a>) -> Result<Self> {
let mut h = MaybeUninit::uninit();
result_from_code(unsafe {
exdb_sys::mcosql_rs_value_create_string(
alloc.h,
val.as_ptr() as *const i8,
val.len() as exdb_sys::size_t,
h.as_mut_ptr(),
)
})
.and(Ok(Value {
alloc: PhantomData,
h: unsafe { h.assume_init() },
}))
}
fn new_binary(val: &[u8], alloc: AllocatorRef<'a>) -> Result<Self> {
let mut h = MaybeUninit::uninit();
result_from_code(unsafe {
exdb_sys::mcosql_rs_value_create_binary(
alloc.h,
val.as_ptr() as *const c_void,
val.len() as exdb_sys::size_t,
h.as_mut_ptr(),
)
})
.and(Ok(Value {
alloc: PhantomData,
h: unsafe { h.assume_init() },
}))
}
fn new_date_time(val: &SystemTime, alloc: AllocatorRef<'a>) -> Result<Self> {
let dur = val
.duration_since(UNIX_EPOCH)
.or(Err(Error::new_sql(mcosql_error_code::INVALID_TYPE_CAST)))?;
let prec = unsafe {
exdb_sys::mco_runtime_getoption(
options::mco_rt_defines::keys::MCO_RT_OPTION_DATETIME_PRECISION as i32,
)
} as u128;
let val;
if prec >= 1_000_000_000 {
val = dur.as_nanos() * (prec / 1_000_000_000);
} else if prec >= 1_000_000 {
val = dur.as_micros() * (prec / 1_000_000);
} else if prec >= 1_000 {
val = dur.as_millis() * (prec / 1_000);
} else {
val = (dur.as_secs() as u128) * prec;
}
let val =
u64::try_from(val).or(Err(Error::new_sql(mcosql_error_code::INVALID_TYPE_CAST)))?;
let mut h = MaybeUninit::uninit();
result_from_code(unsafe {
exdb_sys::mcosql_rs_value_create_datetime(alloc.h, val, h.as_mut_ptr())
})
.and(Ok(Value {
alloc: PhantomData,
h: unsafe { h.assume_init() },
}))
}
fn new_numeric(val_scaled: i64, prec: usize, alloc: AllocatorRef<'a>) -> Result<Self> {
let mut h = MaybeUninit::uninit();
result_from_code(unsafe {
exdb_sys::mcosql_rs_value_create_numeric(
alloc.h,
val_scaled,
prec as exdb_sys::size_t,
h.as_mut_ptr(),
)
})
.and(Ok(Value {
alloc: PhantomData,
h: unsafe { h.assume_init() },
}))
}
pub fn value_type(&self) -> Result<Type> {
let mut ty = MaybeUninit::uninit();
result_from_code(unsafe { exdb_sys::mcosql_rs_value_type(self.h, ty.as_mut_ptr()) }).and(
Type::from_mco(unsafe { ty.assume_init() })
.ok_or(Error::new_sql(mcosql_error_code::RUNTIME_ERROR)),
)
}
pub fn size(&self) -> Result<usize> {
let mut ret = MaybeUninit::uninit();
result_from_code(unsafe { exdb_sys::mcosql_rs_value_size(self.h, ret.as_mut_ptr()) })
.and(Ok(unsafe { ret.assume_init() } as usize))
}
pub fn is_null(&self) -> bool {
0 != unsafe { exdb_sys::mcosql_rs_value_is_null(self.h) }
}
pub fn is_true(&self) -> bool {
0 != unsafe { exdb_sys::mcosql_rs_value_is_true(self.h) }
}
pub fn to_i64(&self) -> Result<i64> {
let mut val = MaybeUninit::uninit();
result_from_code(unsafe { exdb_sys::mcosql_rs_value_int(self.h, val.as_mut_ptr()) })
.and(Ok(unsafe { val.assume_init() }))
}
pub fn to_real(&self) -> Result<f64> {
let mut val = MaybeUninit::uninit();
result_from_code(unsafe { exdb_sys::mcosql_rs_value_real(self.h, val.as_mut_ptr()) })
.and(Ok(unsafe { val.assume_init() }))
}
pub fn to_date_time(&self) -> Result<u64> {
let mut val = MaybeUninit::uninit();
result_from_code(unsafe { exdb_sys::mcosql_rs_value_datetime(self.h, val.as_mut_ptr()) })
.and(Ok(unsafe { val.assume_init() }))
}
pub fn to_system_time(&self) -> Result<SystemTime> {
let prec = unsafe {
exdb_sys::mco_runtime_getoption(
options::mco_rt_defines::keys::MCO_RT_OPTION_DATETIME_PRECISION as i32,
)
} as u64;
let dt = self.to_date_time()?;
let dur;
if prec >= 1_000_000_000 {
dur = Duration::from_nanos(dt / (prec / 1_000_000_000));
} else if prec >= 1_000_000 {
dur = Duration::from_micros(dt / (prec / 1_000_000));
} else if prec >= 1_000 {
dur = Duration::from_millis(dt / (prec / 1_000));
} else {
dur = Duration::from_secs(dt / prec);
}
UNIX_EPOCH
.checked_add(dur)
.ok_or(Error::new_sql(mcosql_error_code::INVALID_TYPE_CAST))
}
pub fn to_numeric(&self) -> Result<Numeric> {
if self.value_type()? == Type::Numeric {
let mut val = 0i64;
let mut prec: exdb_sys::size_t = 0;
result_from_code(unsafe {
exdb_sys::mcosql_rs_value_numeric(self.h, &mut val, &mut prec)
})
.and(
Numeric::new(val, prec as usize)
.ok_or(Error::new_sql(mcosql_error_code::INVALID_TYPE_CAST)),
)
} else {
Err(Error::new_sql(mcosql_error_code::INVALID_TYPE_CAST))
}
}
pub fn to_string(&self) -> Result<String> {
let alloc = allocator::Owned::new()?;
let mut h = MaybeUninit::uninit();
result_from_code(unsafe {
exdb_sys::mcosql_rs_value_string_ref(self.h, alloc.h, h.as_mut_ptr())
})?;
let sref = Ref::from_handle(unsafe { h.assume_init() }, &alloc);
let data = unsafe { slice::from_raw_parts(sref.pointer()? as *const u8, sref.size()?) };
let v = data.to_vec();
String::from_utf8(v).or(Err(Error::new_sql(mcosql_error_code::INVALID_TYPE_CAST)))
}
pub fn as_str(&self) -> Result<&str> {
if self.value_type()? != Type::String {
Err(Error::new_sql(mcosql_error_code::INVALID_TYPE_CAST))
} else {
let data = unsafe { slice::from_raw_parts(self.pointer()? as *const u8, self.size()?) };
str::from_utf8(data).or(Err(Error::new_sql(mcosql_error_code::INVALID_TYPE_CAST)))
}
}
pub fn to_binary(&self) -> Result<Vec<u8>> {
let alloc = allocator::Owned::new()?;
let mut h = MaybeUninit::uninit();
result_from_code(unsafe {
exdb_sys::mcosql_rs_value_binary(self.h, alloc.h, h.as_mut_ptr())
})?;
let sref = Ref::from_handle(unsafe { h.assume_init() }, &alloc);
let data = unsafe { slice::from_raw_parts(sref.pointer()? as *const u8, sref.size()?) };
Ok(data.to_vec())
}
pub fn as_bytes(&self) -> Result<&[u8]> {
if self.value_type()? != Type::Binary {
Err(Error::new_sql(mcosql_error_code::INVALID_TYPE_CAST))
} else {
Ok(unsafe { slice::from_raw_parts(self.pointer()? as *const u8, self.size()?) })
}
}
pub fn as_array(&self) -> Result<&Array> {
if let Type::Array = self.value_type()? {
Ok(unsafe { &*(self as *const Value as *const Array) })
} else {
Err(Error::new_sql(mcosql_error_code::INVALID_TYPE_CAST))
}
}
pub fn as_sequence(&self) -> Result<&Sequence> {
if let Type::Sequence = self.value_type()? {
Ok(unsafe { &*(self as *const Value as *const Sequence) })
} else {
Err(Error::new_sql(mcosql_error_code::INVALID_TYPE_CAST))
}
}
pub fn as_blob(&self) -> Result<&Blob> {
if let Type::Blob = self.value_type()? {
Ok(unsafe { &*(self as *const Value as *const Blob) })
} else {
Err(Error::new_sql(mcosql_error_code::INVALID_TYPE_CAST))
}
}
unsafe fn pointer(&self) -> Result<*const c_void> {
let mut p = MaybeUninit::uninit();
result_from_code(exdb_sys::mcosql_rs_value_ptr(self.h, p.as_mut_ptr()))
.and(Ok(p.assume_init()))
}
unsafe fn release(&self, alloc: AllocatorRef) -> Result<()> {
result_from_code(exdb_sys::mcosql_rs_value_release(alloc.h, self.h))
}
}
impl<'a> From<Array<'a>> for Value<'a> {
fn from(array: Array<'a>) -> Self {
array.val
}
}
impl<'a> From<Sequence<'a>> for Value<'a> {
fn from(seq: Sequence<'a>) -> Self {
seq.val
}
}
impl<'a> From<Blob<'a>> for Value<'a> {
fn from(blob: Blob<'a>) -> Self {
blob.val
}
}
pub struct Ref<'a> {
r: exdb_sys::mcosql_rs_value_ref,
owner: PhantomData<&'a ()>,
}
impl<'a> Ref<'a> {
pub(crate) fn from_handle<T>(r: exdb_sys::mcosql_rs_value_ref, _owner: &'a T) -> Self {
Ref {
r,
owner: PhantomData,
}
}
fn allocator(&'a self) -> AllocatorRef<'a> {
AllocatorRef::from_handle(self.r.allocator, self)
}
fn defused_clone(&'a self) -> Ref<'a> {
Ref {
r: exdb_sys::mcosql_rs_value_ref {
allocator: ptr::null_mut(),
ref_: self.r.ref_,
},
owner: PhantomData,
}
}
fn is_null_ref(&self) -> bool {
self.r.ref_.is_null()
}
fn release_value(&mut self) {
if !self.is_null_ref() && !self.r.allocator.is_null() {
let alloc = self.allocator();
let res = unsafe { self.release(alloc) };
debug_assert!(res.is_ok());
}
self.r.ref_ = ptr::null_mut();
}
unsafe fn replace_value(&mut self, new_value: exdb_sys::mcosql_rs_value) {
self.release_value();
self.r.ref_ = new_value;
}
}
impl<'a> Deref for Ref<'a> {
type Target = Value<'a>;
fn deref(&self) -> &Self::Target {
assert!(!self.is_null_ref());
unsafe { &*(&self.r.ref_ as *const exdb_sys::mcosql_rs_value as *const Value) }
}
}
impl<'a> Drop for Ref<'a> {
fn drop(&mut self) {
self.release_value();
}
}
#[repr(transparent)]
pub struct Array<'a> {
val: Value<'a>,
}
impl<'a> Array<'a> {
fn new<T: ArrayElem>(items: &[T], alloc: AllocatorRef<'a>) -> Result<Self> {
let mut h = MaybeUninit::uninit();
result_from_code(unsafe {
exdb_sys::mcosql_rs_value_create_array(
alloc.h,
T::static_type() as mcosql_column_type::Type,
items.len() as exdb_sys::size_t,
h.as_mut_ptr(),
)
})?;
let mut ret = Array {
val: Value::from_handle(unsafe { h.assume_init() }, alloc),
};
ret.set_body(items).and(Ok(ret))
}
fn is_plain(&self) -> bool {
let mut plain = 0i32;
let rc = unsafe { exdb_sys::mcosql_rs_array_is_plain(self.val.h, &mut plain) };
debug_assert_eq!(mcosql_error_code::SQL_OK, rc);
plain != 0
}
pub fn elem_type(&self) -> Result<Type> {
let mut ty = MaybeUninit::uninit();
result_from_code(unsafe {
exdb_sys::mcosql_rs_array_elem_type(self.val.h, ty.as_mut_ptr())
})
.and(
Type::from_mco(unsafe { ty.assume_init() })
.ok_or(Error::new_sql(mcosql_error_code::RUNTIME_ERROR)),
)
}
pub fn len(&self) -> Result<usize> {
self.val.size()
}
pub fn get_at(&self, at: usize) -> Result<Ref> {
let mut h = MaybeUninit::uninit();
result_from_code(unsafe {
exdb_sys::mcosql_rs_array_get_at(self.val.h, at as exdb_sys::size_t, h.as_mut_ptr())
})
.and(Ok(Ref::from_handle(unsafe { h.assume_init() }, self)))
}
fn allocator(&'a self) -> Result<AllocatorRef<'a>> {
let mut alloc_h = MaybeUninit::uninit();
result_from_code(unsafe {
exdb_sys::mcosql_rs_array_allocator(self.val.h, alloc_h.as_mut_ptr())
})
.and(Ok(AllocatorRef::from_handle(
unsafe { alloc_h.assume_init() },
self,
)))
}
fn set_body<T: ArrayElem>(&mut self, body: &[T]) -> Result<()> {
if body.len() != self.val.size()? {
Err(Error::new_sql(mcosql_error_code::RUNTIME_ERROR))
} else {
if self.is_plain() {
self.set_body_plain(body)
} else {
self.set_body_values(body)
}
}
}
fn set_body_values<T: ArrayElem>(&mut self, body: &[T]) -> Result<()> {
debug_assert!(!self.is_plain());
let alloc = self.allocator()?;
for i in 0..body.len() {
let val = body[i].to_value(alloc)?;
result_from_code(unsafe {
exdb_sys::mcosql_rs_array_set_at(self.val.h, i as exdb_sys::size_t, val.h)
})?;
}
Ok(())
}
fn set_body_plain<T: ArrayElem>(&mut self, body: &[T]) -> Result<()> {
debug_assert!(self.is_plain());
result_from_code(unsafe {
exdb_sys::mcosql_rs_array_set_body(
self.val.h,
body.as_ptr() as *const c_void,
body.len() as exdb_sys::size_t,
)
})
}
}
impl<'a> TryFrom<Value<'a>> for Array<'a> {
type Error = Error;
fn try_from(value: Value<'a>) -> std::result::Result<Self, Self::Error> {
if let Type::Array = value.value_type()? {
Ok(Array { val: value })
} else {
Err(Error::new_sql(mcosql_error_code::INVALID_TYPE_CAST))
}
}
}
pub trait ToValue {
#[doc(hidden)]
fn to_value<'a>(&self, alloc: AllocatorRef<'a>) -> Result<Value<'a>>;
}
#[repr(transparent)]
pub struct Sequence<'a> {
val: Value<'a>,
}
impl<'a> Sequence<'a> {
pub fn elem_type(&self) -> Result<Type> {
let mut ty = MaybeUninit::uninit();
result_from_code(unsafe { exdb_sys::mcosql_rs_seq_elem_type(self.val.h, ty.as_mut_ptr()) })
.and(
Type::from_mco(unsafe { ty.assume_init() })
.ok_or(Error::new_sql(mcosql_error_code::RUNTIME_ERROR)),
)
}
pub fn count(&self) -> Result<usize> {
let mut ret = MaybeUninit::uninit();
result_from_code(unsafe { exdb_sys::mcosql_rs_seq_count(self.val.h, ret.as_mut_ptr()) })
.and(Ok(unsafe { ret.assume_init() } as usize))
}
pub fn iterator(&'a self) -> Result<SequenceIterator<'a>> {
self.get_iterator()
.and(self.reset())
.and(Ok(SequenceIterator::new(self)))
}
fn get_iterator(&self) -> Result<()> {
result_from_code(unsafe { exdb_sys::mcosql_rs_seq_get_iterator(self.val.h) })
}
fn reset(&self) -> Result<()> {
result_from_code(unsafe { exdb_sys::mcosql_rs_seq_reset(self.val.h) })
}
unsafe fn next(&self) -> Result<exdb_sys::mcosql_rs_value> {
let mut ret = MaybeUninit::uninit();
result_from_code(exdb_sys::mcosql_rs_seq_next(self.val.h, ret.as_mut_ptr()))
.and(Ok(ret.assume_init()))
}
fn allocator(&'a self) -> Result<AllocatorRef<'a>> {
let mut alloc = MaybeUninit::uninit();
result_from_code(unsafe {
exdb_sys::mcosql_rs_seq_allocator(self.val.h, alloc.as_mut_ptr())
})
.and(Ok(AllocatorRef::from_handle(
unsafe { alloc.assume_init() },
self,
)))
}
}
pub struct SequenceIterator<'a> {
seq: &'a Sequence<'a>,
val_ref: Ref<'a>,
}
impl<'a> SequenceIterator<'a> {
fn new(seq: &'a Sequence<'a>) -> Self {
let alloc = seq.allocator().unwrap();
let r = exdb_sys::mcosql_rs_value_ref {
allocator: alloc.h,
ref_: ptr::null_mut(),
};
SequenceIterator {
seq,
val_ref: Ref::from_handle(r, seq),
}
}
pub fn advance(&mut self) -> Result<bool> {
unsafe { self.val_ref.replace_value(self.seq.next()?) };
if self.val_ref.is_null_ref() {
Ok(false)
} else {
Ok(true)
}
}
pub fn current_value(&'a self) -> Option<Ref<'a>> {
if self.val_ref.is_null_ref() {
None
} else {
Some(self.val_ref.defused_clone())
}
}
}
pub struct Numeric {
val_scaled: i64,
prec: usize,
}
impl Numeric {
pub fn new(val_scaled: i64, prec: usize) -> Option<Self> {
if prec <= 19 {
Some(Numeric { val_scaled, prec })
} else {
None
}
}
pub fn value_scaled(&self) -> i64 {
self.val_scaled
}
pub fn precision(&self) -> usize {
self.prec
}
pub fn int_part(&self) -> i64 {
self.val_scaled / self.scale() as i64
}
pub fn fract_part(&self) -> u64 {
(self.val_scaled.abs() as u64).wrapping_rem(self.scale() as u64)
}
pub fn destruct(self) -> (i64, usize) {
(self.val_scaled, self.prec)
}
fn scale(&self) -> usize {
10usize.pow(self.prec as u32)
}
}
impl Into<f64> for Numeric {
fn into(self) -> f64 {
self.val_scaled as f64 / self.scale() as f64
}
}
impl Display for Numeric {
fn fmt(&self, f: &mut Formatter<'_>) -> std::result::Result<(), FmtError> {
write!(f, "{}.{}", self.int_part(), self.fract_part())
}
}
impl ToValue for Numeric {
fn to_value<'a>(&self, alloc: AllocatorRef<'a>) -> Result<Value<'a>> {
Value::new_numeric(self.val_scaled, self.prec, alloc)
}
}
#[repr(transparent)]
pub struct Blob<'a> {
val: Value<'a>,
}
impl<'a> Blob<'a> {
pub fn available(&self) -> Result<usize> {
let mut avail: exdb_sys::size_t = 0;
result_from_code(unsafe { exdb_sys::mcosql_rs_blob_available(self.val.h, &mut avail) })
.and(Ok(avail as usize))
}
pub fn get_into(&self, buf: &mut Vec<u8>) -> Result<()> {
unsafe {
let new_len = self.get_raw(buf.as_mut_ptr() as *mut c_void, buf.capacity())?;
buf.set_len(new_len)
};
Ok(())
}
pub fn get(&self, size: usize) -> Result<Vec<u8>> {
let mut ret = Vec::with_capacity(size);
self.get_into(&mut ret).and(Ok(ret))
}
pub fn reset(&self) -> Result<()> {
result_from_code(unsafe { exdb_sys::mcosql_rs_blob_reset(self.val.h, 0) })
}
unsafe fn get_raw(&self, p: *mut c_void, l: usize) -> Result<usize> {
let mut total: exdb_sys::size_t = 0;
let lsz = l as exdb_sys::size_t;
while total < lsz {
let mut nread: exdb_sys::size_t = 0;
result_from_code(exdb_sys::mcosql_rs_blob_get(
self.val.h,
p.add(total as usize),
lsz - total,
&mut nread,
))?;
if nread == 0 {
break;
} else {
total += nread;
}
}
Ok(total as usize)
}
}
pub struct Binary<'a>(&'a [u8]);
impl<'a> Binary<'a> {
pub fn new(bytes: &'a [u8]) -> Self {
Binary(bytes)
}
}
impl ToValue for bool {
fn to_value<'a>(&self, _alloc: AllocatorRef<'a>) -> Result<Value<'a>> {
Value::new_bool(*self)
}
}
impl ToValue for u8 {
fn to_value<'a>(&self, alloc: AllocatorRef<'a>) -> Result<Value<'a>> {
Value::new_int(*self as i64, alloc)
}
}
impl ToValue for u16 {
fn to_value<'a>(&self, alloc: AllocatorRef<'a>) -> Result<Value<'a>> {
Value::new_int(*self as i64, alloc)
}
}
impl ToValue for u32 {
fn to_value<'a>(&self, alloc: AllocatorRef<'a>) -> Result<Value<'a>> {
Value::new_int(*self as i64, alloc)
}
}
impl ToValue for u64 {
fn to_value<'a>(&self, alloc: AllocatorRef<'a>) -> Result<Value<'a>> {
Value::new_int(*self as i64, alloc)
}
}
impl ToValue for i8 {
fn to_value<'a>(&self, alloc: AllocatorRef<'a>) -> Result<Value<'a>> {
Value::new_int(*self as i64, alloc)
}
}
impl ToValue for i16 {
fn to_value<'a>(&self, alloc: AllocatorRef<'a>) -> Result<Value<'a>> {
Value::new_int(*self as i64, alloc)
}
}
impl ToValue for i32 {
fn to_value<'a>(&self, alloc: AllocatorRef<'a>) -> Result<Value<'a>> {
Value::new_int(*self as i64, alloc)
}
}
impl ToValue for i64 {
fn to_value<'a>(&self, alloc: AllocatorRef<'a>) -> Result<Value<'a>> {
Value::new_int(*self as i64, alloc)
}
}
impl ToValue for f32 {
fn to_value<'a>(&self, alloc: AllocatorRef<'a>) -> Result<Value<'a>> {
Value::new_real(*self as f64, alloc)
}
}
impl ToValue for f64 {
fn to_value<'a>(&self, alloc: AllocatorRef<'a>) -> Result<Value<'a>> {
Value::new_real(*self as f64, alloc)
}
}
impl ToValue for &str {
fn to_value<'a>(&self, alloc: AllocatorRef<'a>) -> Result<Value<'a>> {
Value::new_string(self, alloc)
}
}
impl ToValue for Binary<'_> {
fn to_value<'a>(&self, alloc: AllocatorRef<'a>) -> Result<Value<'a>> {
Value::new_binary(self.0, alloc)
}
}
impl<T: ArrayElem> ToValue for &[T] {
fn to_value<'a>(&self, alloc: AllocatorRef<'a>) -> Result<Value<'a>> {
let array = Array::new(self, alloc)?;
Ok(array.into())
}
}
impl<T: ToValue> ToValue for Option<T> {
fn to_value<'a>(&self, alloc: AllocatorRef<'a>) -> Result<Value<'a>> {
match self {
Some(val) => val.to_value(alloc),
None => Value::new_null(),
}
}
}
impl ToValue for SystemTime {
fn to_value<'a>(&self, alloc: AllocatorRef<'a>) -> Result<Value<'a>> {
Value::new_date_time(self, alloc)
}
}
pub trait StaticTypeInfo {
fn static_type() -> Type;
}
macro_rules! impl_static_type_info {
($ty:ty, $col_ty:path) => {
impl StaticTypeInfo for $ty {
fn static_type() -> Type {
$col_ty
}
}
};
}
impl_static_type_info!(u8, Type::UInt1);
impl_static_type_info!(u16, Type::UInt2);
impl_static_type_info!(u32, Type::UInt4);
impl_static_type_info!(u64, Type::UInt8);
impl_static_type_info!(i8, Type::Int1);
impl_static_type_info!(i16, Type::Int2);
impl_static_type_info!(i32, Type::Int4);
impl_static_type_info!(i64, Type::Int8);
impl_static_type_info!(f32, Type::Real4);
impl_static_type_info!(f64, Type::Real8);
impl_static_type_info!(&str, Type::String);
impl_static_type_info!(SystemTime, Type::Time);
pub trait ArrayElem: ToValue + StaticTypeInfo {}
impl<T: ToValue + StaticTypeInfo> ArrayElem for T {}