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