1use std::{array::TryFromSliceError, ops::Range, str};
18
19use arrow_schema::ArrowError;
20
21use std::cmp::Ordering;
22use std::fmt::Debug;
23use std::slice::SliceIndex;
24
25pub(crate) fn overflow_error(msg: &str) -> ArrowError {
27 ArrowError::InvalidArgumentError(format!("Integer overflow computing {msg}"))
28}
29
30#[inline]
31pub(crate) fn slice_from_slice<I: SliceIndex<[u8]> + Clone + Debug>(
32 bytes: &[u8],
33 index: I,
34) -> Result<&I::Output, ArrowError> {
35 bytes.get(index.clone()).ok_or_else(|| {
36 ArrowError::InvalidArgumentError(format!(
37 "Tried to extract byte(s) {index:?} from {}-byte buffer",
38 bytes.len(),
39 ))
40 })
41}
42
43#[inline]
48pub(crate) fn slice_from_slice_at_offset(
49 bytes: &[u8],
50 base_offset: usize,
51 range: Range<usize>,
52) -> Result<&[u8], ArrowError> {
53 let start_byte = base_offset
54 .checked_add(range.start)
55 .ok_or_else(|| overflow_error("slice start"))?;
56 let end_byte = base_offset
57 .checked_add(range.end)
58 .ok_or_else(|| overflow_error("slice end"))?;
59 slice_from_slice(bytes, start_byte..end_byte)
60}
61
62pub(crate) fn array_from_slice<const N: usize>(
63 bytes: &[u8],
64 offset: usize,
65) -> Result<[u8; N], ArrowError> {
66 slice_from_slice_at_offset(bytes, offset, 0..N)?
67 .try_into()
68 .map_err(|e: TryFromSliceError| ArrowError::InvalidArgumentError(e.to_string()))
69}
70
71pub(crate) fn first_byte_from_slice(slice: &[u8]) -> Result<u8, ArrowError> {
72 slice
73 .first()
74 .copied()
75 .ok_or_else(|| ArrowError::InvalidArgumentError("Received empty bytes".to_string()))
76}
77
78#[inline]
80pub(crate) fn string_from_slice(
81 slice: &[u8],
82 offset: usize,
83 range: Range<usize>,
84) -> Result<&str, ArrowError> {
85 let offset_buffer = slice_from_slice_at_offset(slice, offset, range)?;
86
87 #[cfg(feature = "simdutf8")]
89 {
90 simdutf8::basic::from_utf8(offset_buffer).map_err(|_| {
91 let e = simdutf8::compat::from_utf8(offset_buffer).unwrap_err();
93 ArrowError::InvalidArgumentError(format!("encountered non UTF-8 data: {e}"))
94 })
95 }
96
97 #[cfg(not(feature = "simdutf8"))]
99 str::from_utf8(offset_buffer)
100 .map_err(|_| ArrowError::InvalidArgumentError("invalid UTF-8 string".to_string()))
101}
102
103pub(crate) fn try_binary_search_range_by<F>(
120 range: Range<usize>,
121 cmp: F,
122) -> Option<Result<usize, usize>>
123where
124 F: Fn(usize) -> Option<Ordering>,
125{
126 let Range { mut start, mut end } = range;
127 while start < end {
128 let mid = start + (end - start) / 2;
129 match cmp(mid)? {
130 Ordering::Equal => return Some(Ok(mid)),
131 Ordering::Greater => end = mid,
132 Ordering::Less => start = mid + 1,
133 }
134 }
135
136 Some(Err(start))
137}
138
139#[allow(unused)]
141pub(crate) const fn expect_size_of<T>(expected: usize) {
142 let size = std::mem::size_of::<T>();
143 if size != expected {
144 let _ = [""; 0][size];
145 }
146}