use super::buffer::{buf_ptr, mut_buf_ptr};
use std::{
borrow::Cow,
mem::{size_of, size_of_val},
};
#[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
use std::{ffi::CStr, string::FromUtf8Error};
#[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
use std::{
char::{DecodeUtf16Error, decode_utf16},
marker::PhantomData,
};
#[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
use widestring::{U16CStr, U16String};
#[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
pub type SqlChar = u8;
#[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
pub type SqlChar = u16;
#[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
pub type DecodingError = FromUtf8Error;
#[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
pub type DecodingError = DecodeUtf16Error;
#[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
pub fn slice_to_utf8(text: &[u8]) -> Result<String, FromUtf8Error> {
String::from_utf8(text.to_owned())
}
#[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
pub fn slice_to_utf8(text: &[u16]) -> Result<String, DecodeUtf16Error> {
decode_utf16(text.iter().copied()).collect()
}
#[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
pub fn slice_to_cow_utf8(text: &[u8]) -> Cow<'_, str> {
String::from_utf8_lossy(text)
}
#[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
pub fn slice_to_cow_utf8(text: &[u16]) -> Cow<'_, str> {
let text: Result<String, _> = decode_utf16(text.iter().copied()).collect();
text.unwrap().into()
}
#[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
fn sz_to_utf8(buffer: &[u16]) -> String {
let c_str = U16CStr::from_slice_truncate(buffer).unwrap();
c_str.to_string_lossy()
}
#[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
fn sz_to_utf8(buffer: &[u8]) -> String {
let end = buffer
.iter()
.enumerate()
.find(|&(_index, &character)| character == b'\0')
.expect("Buffer must contain terminating zero.")
.0;
let c_str = unsafe { CStr::from_bytes_with_nul_unchecked(&buffer[..=end]) };
c_str.to_string_lossy().into_owned()
}
pub fn binary_length(buffer: &[SqlChar]) -> usize {
size_of_val(buffer)
}
pub fn is_truncated_bin(buffer: &[SqlChar], actual_length_bin: usize) -> bool {
size_of_val(buffer) <= actual_length_bin
}
pub fn resize_to_fit_with_tz(buffer: &mut Vec<SqlChar>, required_binary_length: usize) {
buffer.resize((required_binary_length / size_of::<SqlChar>()) + 2, 0);
}
pub fn resize_to_fit_without_tz(buffer: &mut Vec<SqlChar>, required_binary_length: usize) {
buffer.resize(required_binary_length / size_of::<SqlChar>(), 0);
}
pub struct SqlText<'a> {
#[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
text: U16String,
#[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
_ref: PhantomData<&'a str>,
#[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
text: &'a str,
}
impl<'a> SqlText<'a> {
#[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
pub fn new(text: &'a str) -> Self {
Self {
text: U16String::from_str(text),
_ref: PhantomData,
}
}
#[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
pub fn new(text: &'a str) -> Self {
Self { text }
}
#[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
pub fn ptr(&self) -> *const u16 {
buf_ptr(self.text.as_slice())
}
#[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
pub fn ptr(&self) -> *const u8 {
buf_ptr(self.text.as_bytes())
}
pub fn len_char(&self) -> usize {
self.text.len()
}
}
pub struct SzBuffer {
buffer: Vec<SqlChar>,
}
impl SzBuffer {
pub fn with_capacity(capacity: usize) -> Self {
Self {
buffer: vec![0; capacity + 1],
}
}
pub fn mut_buf(&mut self) -> &mut [SqlChar] {
self.buffer.resize(self.buffer.capacity(), 0);
&mut self.buffer
}
pub fn to_utf8(&self) -> String {
sz_to_utf8(&self.buffer)
}
}
pub struct OutputStringBuffer {
buffer: Vec<SqlChar>,
actual_length: i16,
}
impl OutputStringBuffer {
pub fn empty() -> Self {
Self::with_buffer_size(0)
}
pub fn with_buffer_size(max_str_len: usize) -> Self {
Self {
buffer: vec![0; max_str_len],
actual_length: 0,
}
}
pub fn mut_buf_ptr(&mut self) -> *mut SqlChar {
mut_buf_ptr(&mut self.buffer)
}
pub fn buf_len(&self) -> i16 {
self.buffer.len().try_into().unwrap()
}
pub fn mut_actual_len_ptr(&mut self) -> *mut i16 {
&mut self.actual_length as *mut i16
}
pub fn to_utf8(&self) -> String {
if self.buffer.is_empty() {
return String::new();
}
if self.is_truncated() {
slice_to_utf8(&self.buffer[0..(self.buffer.len() - 1)]).unwrap()
} else {
let actual_length: usize = self.actual_length.try_into().unwrap();
slice_to_utf8(&self.buffer[0..actual_length]).unwrap()
}
}
pub fn is_truncated(&self) -> bool {
self.actual_length >= self.buffer.len().try_into().unwrap()
}
}