diesel/sqlite/connection/
serialized_database.rs1#![allow(unsafe_code)]
2#[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
8use crate::result::{DatabaseErrorKind, Error, QueryResult};
9use alloc::boxed::Box;
10use alloc::string::ToString;
11use core::ops::Deref;
12use core::ptr::NonNull;
13
14#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SerializedDatabase {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field1_finish(f,
"SerializedDatabase", "state", &&self.state)
}
}Debug)]
16pub struct SerializedDatabase {
17 state: State,
18}
19
20#[derive(#[automatically_derived]
impl ::core::fmt::Debug for State {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
State::Owned { data: __self_0, len: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f, "Owned",
"data", __self_0, "len", &__self_1),
State::Empty => ::core::fmt::Formatter::write_str(f, "Empty"),
State::AllocationFailed =>
::core::fmt::Formatter::write_str(f, "AllocationFailed"),
}
}
}Debug)]
21enum State {
22 Owned { data: NonNull<u8>, len: i64 },
24 Empty,
26 AllocationFailed,
28}
29
30impl SerializedDatabase {
31 pub(crate) unsafe fn new(data: NonNull<u8>, len: i64) -> Self {
37 Self {
38 state: State::Owned { data, len },
39 }
40 }
41
42 pub(crate) fn empty() -> Self {
43 Self {
44 state: State::Empty,
45 }
46 }
47
48 pub(crate) fn allocation_failed() -> Self {
49 Self {
50 state: State::AllocationFailed,
51 }
52 }
53
54 #[deprecated(note = "Use `SerializedDatabase::try_as_slice` instead")]
60 #[cfg(all(feature = "with-deprecated", not(feature = "without-deprecated")))]
61 pub fn as_slice(&self) -> &[u8] {
62 self.expect_slice()
63 }
64
65 pub fn try_as_slice(&self) -> QueryResult<&[u8]> {
69 match self.state {
70 State::Owned { data, len } => {
71 let len = isize::try_from(len).map_err(Error::IntegerConversion)?;
73 let len = usize::try_from(len).map_err(Error::IntegerConversion)?;
74 Ok(unsafe { core::slice::from_raw_parts(data.as_ptr(), len) })
76 }
77 State::Empty => Ok(&[]),
78 State::AllocationFailed => Err(Error::DatabaseError(
79 DatabaseErrorKind::Unknown,
80 Box::new("out of memory".to_string()),
81 )),
82 }
83 }
84
85 fn expect_slice(&self) -> &[u8] {
86 match self.try_as_slice() {
87 Ok(slice) => slice,
88 Err(e) => {
::core::panicking::panic_fmt(format_args!("Cannot access the serialized database: {0}",
e));
}panic!("Cannot access the serialized database: {e}"),
89 }
90 }
91}
92
93impl Deref for SerializedDatabase {
94 type Target = [u8];
95
96 fn deref(&self) -> &Self::Target {
102 self.expect_slice()
103 }
104}
105
106impl Drop for SerializedDatabase {
107 fn drop(&mut self) {
109 if let State::Owned { data, .. } = self.state {
110 unsafe {
112 ffi::sqlite3_free(data.as_ptr() as _);
113 }
114 }
115 }
116}
117
118#[cfg(all(test, target_pointer_width = "32"))]
119mod tests {
120 use super::{SerializedDatabase, ffi};
121 use crate::result::Error;
122 use core::ptr::NonNull;
123
124 #[diesel_test_helper::test]
127 fn oversized_serialization_is_rejected() {
128 let len = i64::try_from(isize::MAX).expect("`isize::MAX` fits `i64`") + 1;
129 let data = unsafe { ffi::sqlite3_malloc(1) };
131 let data = NonNull::new(data.cast::<u8>()).expect("SQLite allocates a single byte");
132 let serialized = unsafe { SerializedDatabase::new(data, len) };
134
135 assert!(matches!(
136 serialized.try_as_slice(),
137 Err(Error::IntegerConversion(_))
138 ));
139 }
140}