odbc_api/parameter/varcell.rs
1use std::{
2 borrow::{Borrow, BorrowMut},
3 ffi::c_void,
4 marker::PhantomData,
5 mem::{size_of, size_of_val},
6 num::NonZeroUsize,
7 str::Utf8Error,
8};
9
10use odbc_sys::{CDataType, NULL_DATA};
11use widestring::{U16Str, U16String};
12
13use crate::{
14 buffers::{FetchRowMember, Indicator}, handles::{CData, CDataMut, HasDataType, ASSUMED_MAX_LENGTH_OF_W_VARCHAR}, DataType, OutputParameter
15};
16
17use super::CElement;
18
19/// A tag used to differentiate between different types of variadic buffers.
20///
21/// # Safety
22///
23/// * [`Self::TERMINATING_ZEROES`] is used to calculate buffer offsets. The number of terminating
24/// zeroes is expressed in `BufferElement`s.
25/// * [`Self::C_DATA_TYPE`] is used to bind parameters. Providing wrong values like e.g. a fixed length
26/// types, would cause even a correctly implemented odbc driver to access invalid memory.
27pub unsafe trait VarKind {
28 /// Either `u8` for binary and narrow text or `u16` for wide text. Wide text could also be
29 /// represented as `u8`, after all everything is bytes. This makes it difficult though to create
30 /// owned VarCell types from `u16` buffers.
31 type Element: Copy + Eq;
32 /// Zero for buffer element.
33 const ZERO: Self::Element;
34 /// Number of terminating zeroes required for this kind of variadic buffer.
35 const TERMINATING_ZEROES: usize;
36 const C_DATA_TYPE: CDataType;
37 /// Relational type used to bind the parameter. `buffer_length` is specified in elements rather
38 /// than bytes, if the two differ.
39 fn relational_type(buffer_length: usize) -> DataType;
40}
41
42/// Intended to be used as a generic argument for [`VarCell`] to declare that this buffer is used to
43/// hold narrow (as opposed to wide UTF-16) text.
44#[derive(Clone, Copy)]
45pub struct Text;
46
47unsafe impl VarKind for Text {
48 type Element = u8;
49 const ZERO: u8 = 0;
50 const TERMINATING_ZEROES: usize = 1;
51 const C_DATA_TYPE: CDataType = CDataType::Char;
52
53 fn relational_type(length: usize) -> DataType {
54 // Since we might use as an input buffer, we report the full buffer length in the type and
55 // do not deduct 1 for the terminating zero.
56
57 // For some reason (unknown to me) there has been no need to switch the LongVarchar type in
58 // order to support larger strings (so far).
59
60 DataType::Varchar {
61 length: NonZeroUsize::new(length),
62 }
63 }
64}
65
66/// Intended to be used as a generic argument for [`VarCell`] to declare that this buffer is used to
67/// hold wide UTF-16 (as opposed to narrow ASCII or UTF-8) text. Use this to annotate `[u16]`
68/// buffers.
69#[derive(Clone, Copy)]
70pub struct WideText;
71
72unsafe impl VarKind for WideText {
73 type Element = u16;
74 const ZERO: u16 = 0;
75 const TERMINATING_ZEROES: usize = 1;
76 const C_DATA_TYPE: CDataType = CDataType::WChar;
77
78 fn relational_type(length: usize) -> DataType {
79 // Since we might use as an input buffer, we report the full buffer length in the type and
80 // do not deduct 1 for the terminating zero.
81 // Also some depending on the datasource Varchar may have a length limit. We decide here to
82 // use LongVarchar above the cutoff of 4000.
83 if length <= ASSUMED_MAX_LENGTH_OF_W_VARCHAR {
84 DataType::WVarchar {
85 length: NonZeroUsize::new(length),
86 }
87 } else {
88 DataType::WLongVarchar {
89 length: NonZeroUsize::new(length),
90 }
91 }
92 }
93}
94
95/// Intended to be used as a generic argument for [`VarCell`] to declare that this buffer is used to
96/// hold raw binary input.
97#[derive(Clone, Copy)]
98pub struct Binary;
99
100unsafe impl VarKind for Binary {
101 type Element = u8;
102 const ZERO: u8 = 0;
103 const TERMINATING_ZEROES: usize = 0;
104 const C_DATA_TYPE: CDataType = CDataType::Binary;
105
106 fn relational_type(length: usize) -> DataType {
107 DataType::Varbinary {
108 length: NonZeroUsize::new(length),
109 }
110 }
111}
112
113/// Binds a byte array as Variadic sized character data. It can not be used for columnar bulk
114/// fetches, but if the buffer type is stack allocated it can be utilized in row wise bulk fetches.
115///
116/// Meaningful instantiations of this type are:
117///
118/// * [`self::VarCharSlice`] - immutable borrowed narrow character strings
119/// * [`self::VarCharSliceMut`] - mutable borrowed input / output narrow character strings
120/// * [`self::VarCharArray`] - stack allocated owned input / output narrow character strings
121/// * [`self::VarCharBox`] - heap allocated owned input /output narrow character strings
122/// * [`self::VarWCharSlice`] - immutable borrowed wide character string
123/// * [`self::VarWCharSliceMut`] - mutable borrowed input / output wide character string
124/// * [`self::VarWCharArray`] - stack allocated owned input / output wide character string
125/// * [`self::VarWCharBox`] - heap allocated owned input /output wide character string
126/// * [`self::VarBinarySlice`] - immutable borrowed parameter.
127/// * [`self::VarBinarySliceMut`] - mutable borrowed input / output parameter
128/// * [`self::VarBinaryArray`] - stack allocated owned input / output parameter
129/// * [`self::VarBinaryBox`] - heap allocated owned input /output parameter
130#[derive(Debug, Clone, Copy)]
131pub struct VarCell<B, K> {
132 /// Contains the value. Characters must be valid up to the index indicated by `indicator`. If
133 /// `indicator` is longer than buffer, the last element in buffer must be a terminating zero,
134 /// which is not regarded as being part of the payload itself.
135 buffer: B,
136 /// Indicates the length of the value stored in `buffer`. Should indicator exceed the buffer
137 /// length the value stored in buffer is truncated, and holds actually `buffer.len() - 1` valid
138 /// characters. The last element of the buffer being the terminating zero. If indicator is
139 /// exactly the buffer length, the value should be considered valid up to the last element,
140 /// unless the value is `\0`. In that case we assume `\0` to be a terminating zero left over
141 /// from truncation, rather than the last character of the string.
142 indicator: isize,
143 /// Variadic Kind, declaring wether the buffer holds text or binary data.
144 kind: PhantomData<K>,
145}
146
147pub type VarBinary<B> = VarCell<B, Binary>;
148pub type VarChar<B> = VarCell<B, Text>;
149pub type VarWChar<B> = VarCell<B, WideText>;
150
151/// Parameter type for owned, variable sized narrow character data.
152///
153/// We use `Box<[u8]>` rather than `Vec<u8>` as a buffer type since the indicator pointer already
154/// has the role of telling us how many bytes in the buffer are part of the payload.
155pub type VarCharBox = VarChar<Box<[u8]>>;
156
157/// Parameter type for owned, variable sized wide character data.
158///
159/// We use `Box<[u16]>` rather than `Vec<u16>` as a buffer type since the indicator pointer already
160/// has the role of telling us how many characters in the buffer are part of the payload.
161pub type VarWCharBox = VarWChar<Box<[u16]>>;
162
163/// Parameter type for owned, variable sized binary data.
164///
165/// We use `Box<[u8]>` rather than `Vec<u8>` as a buffer type since the indicator pointer already
166/// has the role of telling us how many bytes in the buffer are part of the payload.
167pub type VarBinaryBox = VarBinary<Box<[u8]>>;
168
169impl<K> VarCell<Box<[K::Element]>, K>
170where
171 K: VarKind,
172{
173 /// Constructs a 'missing' value.
174 pub fn null() -> Self {
175 // We do not want to use the empty buffer (`&[]`) here. It would be bound as `VARCHAR(0)`
176 // which caused errors with Microsoft Access and older versions of the Microsoft SQL Server
177 // ODBC driver.
178 Self::from_buffer(Box::new([K::ZERO]), Indicator::Null)
179 }
180
181 /// Create a VarChar box from a `Vec`.
182 pub fn from_vec(val: Vec<K::Element>) -> Self {
183 let indicator = Indicator::Length(val.len() * size_of::<K::Element>());
184 let buffer = val.into_boxed_slice();
185 Self::from_buffer(buffer, indicator)
186 }
187}
188
189impl<K> VarCell<Box<[u8]>, K>
190where
191 K: VarKind<Element = u8>,
192{
193 /// Create an owned parameter containing the character data from the passed string.
194 pub fn from_string(val: String) -> Self {
195 Self::from_vec(val.into_bytes())
196 }
197}
198
199impl<K> VarCell<Box<[u16]>, K>
200where
201 K: VarKind<Element = u16>,
202{
203 /// Create an owned parameter containing the character data from the passed string.
204 pub fn from_u16_string(val: U16String) -> Self {
205 Self::from_vec(val.into_vec())
206 }
207
208 /// Create an owned parameter containing the character data from the passed string. Converts it
209 /// to UTF-16 and allocates it.
210 pub fn from_str_slice(val: &str) -> Self {
211 let utf16 = U16String::from_str(val);
212 Self::from_u16_string(utf16)
213 }
214}
215
216impl<B, K> VarCell<B, K>
217where
218 K: VarKind,
219 B: Borrow<[K::Element]>,
220{
221 /// Creates a new instance from an existing buffer. For text should the indicator be `NoTotal`
222 /// or indicate a length longer than buffer, the last element in the buffer must be nul (`\0`).
223 pub fn from_buffer(buffer: B, indicator: Indicator) -> Self {
224 let buf = buffer.borrow();
225 if indicator.is_truncated(size_of_val(buf)) {
226 // Value is truncated. Let's check that all required terminating zeroes are at the end
227 // of the buffer.
228 if !ends_in_zeroes(buf, K::TERMINATING_ZEROES, K::ZERO) {
229 panic!("Truncated value must be terminated with zero.")
230 }
231 }
232
233 Self {
234 buffer,
235 indicator: indicator.to_isize(),
236 kind: PhantomData,
237 }
238 }
239
240 /// Call this method to ensure that the entire field content did fit into the buffer. If you
241 /// retrieve a field using [`crate::CursorRow::get_data`], you can repeat the call until this
242 /// method is false to read all the data.
243 ///
244 /// ```
245 /// use odbc_api::{CursorRow, parameter::VarCharArray, Error, handles::Statement};
246 ///
247 /// fn process_large_text(
248 /// col_index: u16,
249 /// row: &mut CursorRow<'_>
250 /// ) -> Result<(), Error>{
251 /// let mut buf = VarCharArray::<512>::NULL;
252 /// row.get_data(col_index, &mut buf)?;
253 /// while !buf.is_complete() {
254 /// // Process bytes in stream without allocation. We can assume repeated calls to
255 /// // get_data do not return `None` since it would have done so on the first call.
256 /// process_text_slice(buf.as_bytes().unwrap());
257 /// }
258 /// Ok(())
259 /// }
260 ///
261 /// fn process_text_slice(text: &[u8]) { /*...*/}
262 ///
263 /// ```
264 ///
265 /// ```
266 /// use odbc_api::{CursorRow, parameter::VarBinaryArray, Error, handles::Statement};
267 ///
268 /// fn process_large_binary(
269 /// col_index: u16,
270 /// row: &mut CursorRow<'_>
271 /// ) -> Result<(), Error>{
272 /// let mut buf = VarBinaryArray::<512>::NULL;
273 /// row.get_data(col_index, &mut buf)?;
274 /// while !buf.is_complete() {
275 /// // Process bytes in stream without allocation. We can assume repeated calls to
276 /// // get_data do not return `None` since it would have done so on the first call.
277 /// process_slice(buf.as_bytes().unwrap());
278 /// }
279 /// Ok(())
280 /// }
281 ///
282 /// fn process_slice(text: &[u8]) { /*...*/}
283 ///
284 /// ```
285 pub fn is_complete(&self) -> bool {
286 let slice = self.buffer.borrow();
287 let max_value_length = if ends_in_zeroes(slice, K::TERMINATING_ZEROES, K::ZERO) {
288 slice.len() - K::TERMINATING_ZEROES
289 } else {
290 slice.len()
291 };
292 !self
293 .indicator()
294 .is_truncated(max_value_length * size_of::<K::Element>())
295 }
296
297 /// Read access to the underlying ODBC indicator. After data has been fetched the indicator
298 /// value is set to the length the buffer should have had to hold the entire value. It may also
299 /// be [`Indicator::Null`] to indicate `NULL` or [`Indicator::NoTotal`] which tells us the data
300 /// source does not know how big the buffer must be to hold the complete value.
301 /// [`Indicator::NoTotal`] implies that the content of the current buffer is valid up to its
302 /// maximum capacity.
303 pub fn indicator(&self) -> Indicator {
304 Indicator::from_isize(self.indicator)
305 }
306
307 /// Call this method to reset the indicator to a value which matches the length returned by the
308 /// [`Self::as_bytes`] method. This is useful if you want to insert values into the database
309 /// despite the fact, that they might have been truncated. Otherwise the behaviour of databases
310 /// in this situation is driver specific. Some drivers insert up to the terminating zero, others
311 /// detect the truncation and throw an error.
312 pub fn hide_truncation(&mut self) {
313 if !self.is_complete() {
314 let binary_length = size_of_val(self.buffer.borrow());
315 self.indicator = (binary_length - K::TERMINATING_ZEROES).try_into().unwrap();
316 }
317 }
318
319 /// Length of the (potentially truncated) value within the cell in bytes. Excluding
320 /// terminating zero.
321 pub fn len_in_bytes(&self) -> Option<usize> {
322 // The maximum length is one larger for untruncated values without terminating zero. E.g.
323 // if instantiated from string literal.
324 let max_trunc_len_in_bytes =
325 (self.buffer.borrow().len() - K::TERMINATING_ZEROES) * size_of::<K::Element>();
326 match self.indicator() {
327 Indicator::Null => None,
328 Indicator::NoTotal => Some(max_trunc_len_in_bytes),
329 Indicator::Length(len) => {
330 if self.is_complete() {
331 Some(len)
332 } else {
333 Some(max_trunc_len_in_bytes)
334 }
335 }
336 }
337 }
338
339 /// The payload in bytes the buffer can hold including terminating zeroes
340 pub fn capacity_in_bytes(&self) -> usize {
341 size_of_val(self.buffer.borrow())
342 }
343
344 /// Method backing the implementation of the CElement trait
345 fn impl_assert_completness(&self) {
346 // There is one edge case in that this is different from `is_complete``, and this is with
347 // regards to values of which the payload ends with a terminating zero. All we care about
348 // is that the buffer we bind as input is valid. Not necessarily if the value in it is
349 // complete.
350 let slice = self.buffer.borrow();
351 // Terminating zero intenionally not accounted for. Since `VarCell` may hold values without
352 // it, if constructed from string literals.
353 let max_len_bytes = size_of_val(slice);
354 if self.indicator().is_truncated(max_len_bytes) {
355 panic!("Truncated values must not be used be bound as input parameters.")
356 }
357 }
358}
359
360impl<B, K> VarCell<B, K>
361where
362 B: Borrow<[K::Element]>,
363 K: VarKind,
364{
365 /// Valid payload of the buffer (excluding terminating zeroes) returned as slice or `None` in
366 /// case the indicator is `NULL_DATA`.
367 pub fn as_slice(&self) -> Option<&[K::Element]> {
368 let slice = self.buffer.borrow();
369 self.len_in_bytes()
370 .map(|len| &slice[..(len / size_of::<K::Element>())])
371 }
372}
373
374impl<B, K> VarCell<B, K>
375where
376 B: Borrow<[u8]>,
377 K: VarKind<Element = u8>,
378{
379 /// Valid payload of the buffer (excluding terminating zeroes) returned as slice or `None` in
380 /// case the indicator is `NULL_DATA`.
381 pub fn as_bytes(&self) -> Option<&[u8]> {
382 self.as_slice()
383 }
384}
385
386impl<B> VarCell<B, Text>
387where
388 B: Borrow<[u8]>,
389{
390 pub fn as_str(&self) -> Result<Option<&str>, Utf8Error> {
391 if let Some(bytes) = self.as_bytes() {
392 let text = std::str::from_utf8(bytes)?;
393 Ok(Some(text))
394 } else {
395 Ok(None)
396 }
397 }
398}
399
400impl<B> VarCell<B, WideText>
401where
402 B: Borrow<[u16]>,
403{
404 pub fn as_utf16(&self) -> Option<&U16Str> {
405 if let Some(chars) = self.as_slice() {
406 let text = U16Str::from_slice(chars);
407 Some(text)
408 } else {
409 None
410 }
411 }
412}
413
414unsafe impl<B, K> CData for VarCell<B, K>
415where
416 B: Borrow<[K::Element]>,
417 K: VarKind,
418{
419 fn cdata_type(&self) -> CDataType {
420 K::C_DATA_TYPE
421 }
422
423 fn indicator_ptr(&self) -> *const isize {
424 &self.indicator as *const isize
425 }
426
427 fn value_ptr(&self) -> *const c_void {
428 self.buffer.borrow().as_ptr() as *const c_void
429 }
430
431 fn buffer_length(&self) -> isize {
432 // This is the maximum buffer length, but it is NOT the length of an instance of Self due to
433 // the missing size of the indicator value. As such the buffer length can not be used to
434 // correctly index a columnar buffer of Self.
435 size_of_val(self.buffer.borrow()).try_into().unwrap()
436 }
437}
438
439impl<B, K> HasDataType for VarCell<B, K>
440where
441 B: Borrow<[K::Element]>,
442 K: VarKind,
443{
444 fn data_type(&self) -> DataType {
445 K::relational_type(self.buffer.borrow().len())
446 }
447}
448
449unsafe impl<B, K> CDataMut for VarCell<B, K>
450where
451 B: BorrowMut<[K::Element]>,
452 K: VarKind,
453{
454 fn mut_indicator_ptr(&mut self) -> *mut isize {
455 &mut self.indicator as *mut isize
456 }
457
458 fn mut_value_ptr(&mut self) -> *mut c_void {
459 self.buffer.borrow_mut().as_mut_ptr() as *mut c_void
460 }
461}
462
463/// Binds a byte array as a VarChar input parameter.
464///
465/// While a byte array can provide us with a pointer to the start of the array and the length of the
466/// array itself, it can not provide us with a pointer to the length of the buffer. So to bind
467/// strings which are not zero terminated we need to store the length in a separate value.
468///
469/// This type is created if `into_parameter` of the `IntoParameter` trait is called on a `&str`.
470///
471/// # Example
472///
473/// ```no_run
474/// use odbc_api::{Environment, ConnectionOptions, IntoParameter};
475///
476/// let env = Environment::new()?;
477///
478/// let mut conn = env.connect(
479/// "YourDatabase", "SA", "My@Test@Password1",
480/// ConnectionOptions::default()
481/// )?;
482/// if let Some(cursor) = conn.execute(
483/// "SELECT year FROM Birthdays WHERE name=?;",
484/// &"Bernd".into_parameter(),
485/// None)?
486/// {
487/// // Use cursor to process query results.
488/// };
489/// # Ok::<(), odbc_api::Error>(())
490/// ```
491pub type VarCharSlice<'a> = VarChar<&'a [u8]>;
492
493pub type VarWCharSlice<'a> = VarWChar<&'a [u16]>;
494
495/// Binds a byte array as a variadic binary input parameter.
496///
497/// While a byte array can provide us with a pointer to the start of the array and the length of the
498/// array itself, it can not provide us with a pointer to the length of the buffer. So to bind
499/// byte slices (`&[u8]`) we need to store the length in a separate value.
500///
501/// This type is created if `into_parameter` of the `IntoParameter` trait is called on a `&[u8]`.
502pub type VarBinarySlice<'a> = VarBinary<&'a [u8]>;
503
504impl<K> VarCell<&'_ [u8], K> {
505 /// Indicates missing data
506 pub const NULL: Self = Self {
507 // We do not want to use the empty buffer (`&[]`) here. It would be bound as `VARCHAR(0)`
508 // which caused errors with Microsoft Access and older versions of the Microsoft SQL Server
509 // ODBC driver.
510 buffer: &[0],
511 indicator: NULL_DATA,
512 kind: PhantomData,
513 };
514}
515
516impl<K> VarCell<&'_ [u16], K> {
517 /// Indicates missing data
518 pub const NULL: Self = Self {
519 // We do not want to use the empty buffer (`&[]`) here. It would be bound as `VARCHAR(0)`
520 // which caused errors with Microsoft Access and older versions of the Microsoft SQL Server
521 // ODBC driver.
522 buffer: &[0],
523 indicator: NULL_DATA,
524 kind: PhantomData,
525 };
526}
527
528impl<'a, K> VarCell<&'a [K::Element], K>
529where
530 K: VarKind,
531{
532 /// Constructs a new VarChar containing the text in the specified buffer.
533 ///
534 /// Caveat: This constructor is going to create a truncated value in case the input slice ends
535 /// with `nul`. Should you want to insert an actual string those payload ends with `nul` into
536 /// the database you need a buffer one byte longer than the string. You can instantiate such a
537 /// value using [`Self::from_buffer`].
538 pub fn new(value: &'a [K::Element]) -> Self {
539 Self::from_buffer(value, Indicator::Length(size_of_val(value)))
540 }
541}
542
543/// Wraps a slice so it can be used as an output parameter for narrow character data.
544pub type VarCharSliceMut<'a> = VarChar<&'a mut [u8]>;
545
546/// Wraps a slice so it can be used as an output parameter for wide character data.
547pub type VarWCharSliceMut<'a> = VarWChar<&'a mut [u8]>;
548
549/// Wraps a slice so it can be used as an output parameter for binary data.
550pub type VarBinarySliceMut<'a> = VarBinary<&'a mut [u8]>;
551
552/// A stack allocated VARCHAR type.
553///
554/// Due to its memory layout this type can be bound either as a single parameter, or as a column of
555/// a row-by-row output, but not be used in columnar parameter arrays or output buffers.
556///
557/// You can also use [`VarCharArray`] as an output type for statement execution using
558/// [`crate::parameter::Out`] or [`crate::parameter::InOut`].
559///
560/// # Example
561///
562/// ```no_run
563/// # use odbc_api::{Connection, Error, parameter::{VarCharArray, Out}};
564/// # fn output_example(connection: Connection<'_>) -> Result<(), Error> {
565/// let mut out_msg: VarCharArray<255> = VarCharArray::NULL;
566/// connection.execute("CALL PROCEDURE_NAME(?)", (Out(&mut out_msg),), None)?;
567/// # Ok(())
568/// # }
569/// ```
570pub type VarCharArray<const LENGTH: usize> = VarChar<[u8; LENGTH]>;
571
572/// A stack allocated NVARCHAR type.
573///
574/// Due to its memory layout this type can be bound either as a single parameter, or as a column of
575/// a row-by-row output, but not be used in columnar parameter arrays or output buffers.
576pub type VarWCharArray<const LENGTH: usize> = VarWChar<[u16; LENGTH]>;
577
578/// A stack allocated VARBINARY type.
579///
580/// Due to its memory layout this type can be bound either as a single parameter, or as a column of
581/// a row-by-row output, but not be used in columnar parameter arrays or output buffers.
582pub type VarBinaryArray<const LENGTH: usize> = VarBinary<[u8; LENGTH]>;
583
584impl<const LENGTH: usize, K, E> Default for VarCell<[E; LENGTH], K>
585where
586 E: Default + Copy,
587{
588 fn default() -> Self {
589 Self {
590 buffer: [E::default(); LENGTH],
591 indicator: Indicator::Null.to_isize(),
592 kind: Default::default(),
593 }
594 }
595}
596
597impl<const LENGTH: usize, K: VarKind> VarCell<[K::Element; LENGTH], K> {
598 /// Indicates a missing value.
599 pub const NULL: Self = Self {
600 buffer: [K::ZERO; LENGTH],
601 indicator: NULL_DATA,
602 kind: PhantomData,
603 };
604
605 /// Construct from a slice. If value is longer than `LENGTH` it will be truncated. In that case
606 /// the last byte will be set to `0`.
607 pub fn new(elements: &[K::Element]) -> Self {
608 let indicator = (size_of_val(elements)).try_into().unwrap();
609 let mut buffer = [K::ZERO; LENGTH];
610 if elements.len() > LENGTH {
611 buffer.copy_from_slice(&elements[..LENGTH]);
612 *buffer.last_mut().unwrap() = K::ZERO;
613 } else {
614 buffer[..elements.len()].copy_from_slice(elements);
615 };
616 Self {
617 buffer,
618 indicator,
619 kind: PhantomData,
620 }
621 }
622}
623
624/// Figures out, wether or not the buffer ends with a fixed number of zeroes.
625fn ends_in_zeroes<T>(buffer: &[T], number_of_zeroes: usize, zero: T) -> bool
626where
627 T: Copy + Eq,
628{
629 buffer.len() >= number_of_zeroes
630 && buffer
631 .iter()
632 .rev()
633 .copied()
634 .take(number_of_zeroes)
635 .all(|byte| byte == zero)
636}
637
638// We can't go all out and implement these traits for anything implementing Borrow and BorrowMut,
639// because erroneous but still safe implementation of these traits could cause invalid memory access
640// down the road. E.g. think about returning a different slice with a different length for borrow
641// and borrow_mut.
642unsafe impl<K: VarKind> CElement for VarCell<&'_ [K::Element], K> {
643 fn assert_completness(&self) {
644 self.impl_assert_completness()
645 }
646}
647
648unsafe impl<const LENGTH: usize, K: VarKind> CElement for VarCell<[K::Element; LENGTH], K> {
649 fn assert_completness(&self) {
650 self.impl_assert_completness()
651 }
652}
653unsafe impl<const LENGTH: usize, K: VarKind> OutputParameter for VarCell<[K::Element; LENGTH], K> {}
654
655unsafe impl<K: VarKind> CElement for VarCell<&'_ mut [K::Element], K> {
656 fn assert_completness(&self) {
657 self.impl_assert_completness()
658 }
659}
660unsafe impl<K: VarKind> OutputParameter for VarCell<&'_ mut [K::Element], K> {}
661
662unsafe impl<K: VarKind> CElement for VarCell<Box<[K::Element]>, K> {
663 fn assert_completness(&self) {
664 self.impl_assert_completness()
665 }
666}
667unsafe impl<K: VarKind> OutputParameter for VarCell<Box<[K::Element]>, K> {}
668
669unsafe impl<const LENGTH: usize> FetchRowMember for VarCharArray<LENGTH> {
670 fn indicator(&self) -> Option<Indicator> {
671 Some(self.indicator())
672 }
673}
674
675unsafe impl<const LENGTH: usize> FetchRowMember for VarWCharArray<LENGTH> {
676 fn indicator(&self) -> Option<Indicator> {
677 Some(self.indicator())
678 }
679}
680
681unsafe impl<const LENGTH: usize> FetchRowMember for VarBinaryArray<LENGTH> {
682 fn indicator(&self) -> Option<Indicator> {
683 Some(self.indicator())
684 }
685}
686
687#[cfg(test)]
688mod tests {
689
690 use super::{Indicator, VarCharSlice};
691
692 #[test]
693 fn must_accept_fitting_values_and_correctly_truncated_ones() {
694 // Fine: not truncated
695 VarCharSlice::from_buffer(b"12345", Indicator::Length(5));
696 // Fine: truncated, but ends in zero
697 VarCharSlice::from_buffer(b"1234\0", Indicator::Length(10));
698 }
699
700 #[test]
701 #[should_panic]
702 fn must_ensure_truncated_values_are_terminated() {
703 // Not fine, value is too long, but not terminated by zero
704 VarCharSlice::from_buffer(b"12345", Indicator::Length(10));
705 }
706}