diesel/sqlite/connection/
sqlite_blob.rs1#![allow(unsafe_code)] #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
3extern crate libsqlite3_sys as ffi;
4
5#[cfg(all(target_family = "wasm", target_os = "unknown"))]
6use sqlite_wasm_rs as ffi;
7
8#[expect(missing_debug_implementations)]
19#[cfg_attr(not(feature = "std"), expect(dead_code))]
20pub struct SqliteReadOnlyBlob<'conn> {
21 pub(crate) blob: core::ptr::NonNull<ffi::sqlite3_blob>,
22 pub(crate) read_index: usize,
23
24 pub(crate) blob_size: usize,
25 pub(crate) _pd: core::marker::PhantomData<&'conn mut ffi::sqlite3_blob>,
26}
27
28impl Drop for SqliteReadOnlyBlob<'_> {
29 fn drop(&mut self) {
30 use crate::util::std_compat::panicking;
31
32 if let Err(error_message) = self.close_inner() {
33 if panicking() {
34 #[cfg(feature = "std")]
35 {
::std::io::_eprint(format_args!("Error closing SQLite blob: {0}\n",
error_message));
};eprintln!("Error closing SQLite blob: {error_message}");
36 } else {
37 {
::core::panicking::panic_fmt(format_args!("Error closing SQLite blob: {0}",
error_message));
};panic!("Error closing SQLite blob: {error_message}");
38 }
39 }
40 }
41}
42
43impl SqliteReadOnlyBlob<'_> {
44 pub fn is_empty(&self) -> bool {
46 self.len() == 0
47 }
48
49 pub fn len(&self) -> usize {
51 self.blob_size
52 }
53
54 pub fn close(mut self) -> Result<(), crate::result::Error> {
61 self.close_inner()
62 }
63
64 fn close_inner(&mut self) -> Result<(), crate::result::Error> {
65 let close_result = unsafe { ffi::sqlite3_blob_close(self.blob.as_ptr()) };
72
73 if close_result != ffi::SQLITE_OK {
74 let error_message = super::error_message(close_result);
75 return Err(crate::result::Error::ClosingHandle(error_message));
76 }
77
78 Ok(())
79 }
80}
81
82#[cfg(feature = "std")]
83#[allow(clippy::std_instead_of_core)] fn to_io_error(error: core::num::TryFromIntError) -> std::io::Error {
85 std::io::Error::new(std::io::ErrorKind::InvalidInput, Box::new(error))
86}
87
88#[cfg(feature = "std")]
90impl std::io::Read for SqliteReadOnlyBlob<'_> {
91 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
92 let buflen: i32 = buf.len().try_into().map_err(to_io_error)?;
93 let offset: i32 = self.read_index.try_into().map_err(to_io_error)?;
94
95 let read_length: i32 = (i32::try_from(self.blob_size)
102 .map_err(to_io_error)?
103 .saturating_sub(offset))
104 .min(buflen);
105
106 let ret = unsafe {
107 ffi::sqlite3_blob_read(
108 self.blob.as_ptr(),
109 buf.as_mut_ptr() as *mut core::ffi::c_void,
110 read_length,
111 offset,
112 )
113 };
114
115 if ret != ffi::SQLITE_OK {
116 let error_message = crate::sqlite::connection::error_message(ret);
117 return Err(std::io::Error::other(error_message.to_string()));
118 }
119
120 self.read_index += usize::try_from(read_length).map_err(to_io_error)?;
121 if true {
if !(self.read_index <= self.blob_size) {
::core::panicking::panic("assertion failed: self.read_index <= self.blob_size")
};
};debug_assert!(self.read_index <= self.blob_size);
122
123 usize::try_from(read_length).map_err(to_io_error)
124 }
125}
126
127#[cfg(feature = "std")]
128impl std::io::Seek for SqliteReadOnlyBlob<'_> {
129 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
130 match pos {
131 std::io::SeekFrom::Start(n) => {
132 self.read_index = usize::try_from(n).map_err(to_io_error)?.min(self.blob_size);
133 }
134 std::io::SeekFrom::End(n) => {
135 self.read_index = if n.is_positive() {
136 self.blob_size
137 } else {
138 self.blob_size - usize::try_from(n.unsigned_abs()).map_err(to_io_error)?
139 };
140 }
141 std::io::SeekFrom::Current(n) => {
142 let n = isize::try_from(n).map_err(to_io_error)?;
143
144 if n.is_negative() {
145 self.read_index = if self.read_index < n.unsigned_abs() {
146 0
147 } else {
148 self.read_index - n.unsigned_abs()
149 };
150 } else {
151 self.read_index = (self.read_index + n.unsigned_abs()).min(self.blob_size);
152 }
153 }
154 }
155
156 u64::try_from(self.read_index).map_err(to_io_error)
157 }
158}