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};
9use crate::QueryResult;
10use std::ops::Deref;
11use std::ptr::NonNull;
12
13#[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)]
15pub struct SerializedDatabase {
16 state: State,
17}
18
19#[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)]
20enum State {
21 Owned { data: NonNull<u8>, len: i64 },
23 Empty,
25 AllocationFailed,
27}
28
29impl SerializedDatabase {
30 pub(crate) unsafe fn new(data: NonNull<u8>, len: i64) -> Self {
36 Self {
37 state: State::Owned { data, len },
38 }
39 }
40
41 pub(crate) fn empty() -> Self {
42 Self {
43 state: State::Empty,
44 }
45 }
46
47 pub(crate) fn allocation_failed() -> Self {
48 Self {
49 state: State::AllocationFailed,
50 }
51 }
52
53 #[deprecated(note = "Use `SerializedDatabase::try_as_slice` instead")]
59 #[cfg(all(feature = "with-deprecated", not(feature = "without-deprecated")))]
60 pub fn as_slice(&self) -> &[u8] {
61 self.expect_slice()
62 }
63
64 #[cfg(not(all(feature = "with-deprecated", not(feature = "without-deprecated"))))]
65 fn as_slice(&self) -> &[u8] {
66 self.expect_slice()
67 }
68
69 pub fn try_as_slice(&self) -> QueryResult<&[u8]> {
73 match self.state {
74 State::Owned { data, len } => {
75 let len = isize::try_from(len).map_err(Error::IntegerConversion)?;
77 let len = usize::try_from(len).map_err(Error::IntegerConversion)?;
78 Ok(unsafe { core::slice::from_raw_parts(data.as_ptr(), len) })
80 }
81 State::Empty => Ok(&[]),
82 State::AllocationFailed => Err(Error::DatabaseError(
83 DatabaseErrorKind::Unknown,
84 Box::new("out of memory".to_string()),
85 )),
86 }
87 }
88
89 fn expect_slice(&self) -> &[u8] {
90 match self.try_as_slice() {
91 Ok(slice) => slice,
92 Err(e) => {
::core::panicking::panic_fmt(format_args!("Cannot access the serialized database: {0}",
e));
}panic!("Cannot access the serialized database: {e}"),
93 }
94 }
95}
96
97impl Deref for SerializedDatabase {
98 type Target = [u8];
99
100 #[allow(deprecated)] fn deref(&self) -> &Self::Target {
102 self.as_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::{ffi, SerializedDatabase};
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}