use std::{
borrow::{Borrow, BorrowMut},
ffi::c_void,
};
use odbc_sys::{CDataType, NULL_DATA};
use crate::{
buffers::Indicator,
handles::{CData, CDataMut, HasDataType},
DataType, OutputParameter,
};
use super::CElement;
#[derive(Debug, Clone, Copy)]
pub struct VarBinary<B> {
buffer: B,
indicator: isize,
}
pub type VarBinaryBox = VarBinary<Box<[u8]>>;
impl VarBinaryBox {
pub fn null() -> Self {
Self::from_buffer(Box::new([0]), Indicator::Null)
}
pub fn from_vec(val: Vec<u8>) -> Self {
let indicator = Indicator::Length(val.len());
let buffer = val.into_boxed_slice();
Self::from_buffer(buffer, indicator)
}
}
impl<B> VarBinary<B>
where
B: Borrow<[u8]>,
{
pub fn from_buffer(buffer: B, indicator: Indicator) -> Self {
Self {
buffer,
indicator: indicator.to_isize(),
}
}
pub fn as_bytes(&self) -> Option<&[u8]> {
let slice = self.buffer.borrow();
match self.indicator() {
Indicator::Null => None,
Indicator::NoTotal => Some(slice),
Indicator::Length(len) => {
if self.is_complete() {
Some(&slice[..len])
} else {
Some(slice)
}
}
}
}
pub fn is_complete(&self) -> bool {
let slice = self.buffer.borrow();
match self.indicator() {
Indicator::Null => true,
Indicator::NoTotal => false,
Indicator::Length(len) => len <= slice.len(),
}
}
pub fn indicator(&self) -> Indicator {
Indicator::from_isize(self.indicator)
}
}
impl<B> VarBinary<B>
where
B: Borrow<[u8]>,
{
pub fn hide_truncation(&mut self) {
if !self.is_complete() {
self.indicator = self.buffer.borrow().len().try_into().unwrap();
}
}
}
unsafe impl<B> CData for VarBinary<B>
where
B: Borrow<[u8]>,
{
fn cdata_type(&self) -> CDataType {
CDataType::Binary
}
fn indicator_ptr(&self) -> *const isize {
&self.indicator as *const isize
}
fn value_ptr(&self) -> *const c_void {
self.buffer.borrow().as_ptr() as *const c_void
}
fn buffer_length(&self) -> isize {
self.buffer.borrow().len().try_into().unwrap()
}
}
impl<B> HasDataType for VarBinary<B>
where
B: Borrow<[u8]>,
{
fn data_type(&self) -> DataType {
DataType::Varbinary {
length: self.buffer.borrow().len(),
}
}
}
unsafe impl<B> CDataMut for VarBinary<B>
where
B: BorrowMut<[u8]>,
{
fn mut_indicator_ptr(&mut self) -> *mut isize {
&mut self.indicator as *mut isize
}
fn mut_value_ptr(&mut self) -> *mut c_void {
self.buffer.borrow_mut().as_mut_ptr() as *mut c_void
}
}
pub type VarBinarySlice<'a> = VarBinary<&'a [u8]>;
impl<'a> VarBinarySlice<'a> {
pub const NULL: Self = Self {
buffer: &[0],
indicator: NULL_DATA,
};
pub fn new(value: &'a [u8]) -> Self {
Self::from_buffer(value, Indicator::Length(value.len()))
}
}
pub type VarBinarySliceMut<'a> = VarBinary<&'a mut [u8]>;
pub type VarBinaryArray<const LENGTH: usize> = VarBinary<[u8; LENGTH]>;
impl<const LENGTH: usize> VarBinaryArray<LENGTH> {
pub const NULL: Self = VarBinaryArray {
buffer: [0; LENGTH],
indicator: NULL_DATA,
};
pub fn new(bytes: &[u8]) -> Self {
let indicator = bytes.len().try_into().unwrap();
let mut buffer = [0u8; LENGTH];
if bytes.len() > LENGTH {
buffer.copy_from_slice(&bytes[..LENGTH]);
} else {
buffer[..bytes.len()].copy_from_slice(bytes);
};
Self { buffer, indicator }
}
}
unsafe impl CElement for VarBinarySlice<'_> {}
unsafe impl<const LENGTH: usize> CElement for VarBinaryArray<LENGTH> {}
unsafe impl<const LENGTH: usize> OutputParameter for VarBinaryArray<LENGTH> {}
unsafe impl CElement for VarBinarySliceMut<'_> {}
unsafe impl OutputParameter for VarBinarySliceMut<'_> {}
unsafe impl CElement for VarBinaryBox {}
unsafe impl OutputParameter for VarBinaryBox {}