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