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")]
83fn to_io_error(error: core::num::TryFromIntError) -> std::io::Error {
84 std::io::Error::new(std::io::ErrorKind::InvalidInput, Box::new(error))
85}
86
87#[cfg(feature = "std")]
89impl std::io::Read for SqliteReadOnlyBlob<'_> {
90 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
91 let buflen: i32 = buf.len().try_into().map_err(to_io_error)?;
92 let offset: i32 = self.read_index.try_into().map_err(to_io_error)?;
93
94 let read_length: i32 = (i32::try_from(self.blob_size)
101 .map_err(to_io_error)?
102 .saturating_sub(offset))
103 .min(buflen);
104
105 let ret = unsafe {
106 ffi::sqlite3_blob_read(
107 self.blob.as_ptr(),
108 buf.as_mut_ptr() as *mut core::ffi::c_void,
109 read_length,
110 offset,
111 )
112 };
113
114 if ret != ffi::SQLITE_OK {
115 let error_message = crate::sqlite::connection::error_message(ret);
116 return Err(std::io::Error::other(error_message.to_string()));
117 }
118
119 self.read_index += usize::try_from(read_length).map_err(to_io_error)?;
120 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);
121
122 usize::try_from(read_length).map_err(to_io_error)
123 }
124}
125
126#[cfg(feature = "std")]
127impl std::io::Seek for SqliteReadOnlyBlob<'_> {
128 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
129 match pos {
130 std::io::SeekFrom::Start(n) => {
131 self.read_index = usize::try_from(n).map_err(to_io_error)?.min(self.blob_size);
132 }
133 std::io::SeekFrom::End(n) => {
134 self.read_index = if n.is_positive() {
135 self.blob_size
136 } else {
137 self.blob_size - usize::try_from(n.unsigned_abs()).map_err(to_io_error)?
138 };
139 }
140 std::io::SeekFrom::Current(n) => {
141 let n = isize::try_from(n).map_err(to_io_error)?;
142
143 if n.is_negative() {
144 self.read_index = if self.read_index < n.unsigned_abs() {
145 0
146 } else {
147 self.read_index - n.unsigned_abs()
148 };
149 } else {
150 self.read_index = (self.read_index + n.unsigned_abs()).min(self.blob_size);
151 }
152 }
153 }
154
155 u64::try_from(self.read_index).map_err(to_io_error)
156 }
157}