sqlite3_ext/value/
blob.rs1use std::{
2 alloc::{alloc, dealloc, realloc, Layout},
3 ffi::c_void,
4 mem::{align_of, forget, size_of},
5 ptr::{copy_nonoverlapping, read_unaligned, write_unaligned, NonNull},
6 slice,
7};
8
9const SIZEI: isize = size_of::<usize>() as _;
10const SIZEU: usize = size_of::<usize>();
11
12const _: () = {
13 assert!(align_of::<u8>() == 1);
14};
15
16fn blob_layout(len: usize) -> Layout {
17 unsafe { Layout::from_size_align_unchecked(len + SIZEU, 1) }
19}
20
21#[repr(transparent)]
25pub struct Blob {
26 data: NonNull<u8>,
27}
28
29impl Blob {
30 fn alloc(len: usize) -> Blob {
31 let data = unsafe { NonNull::new_unchecked(alloc(blob_layout(len))) };
32 let mut ret = Blob { data };
33 ret.set_len(len);
34 ret
35 }
36
37 fn realloc(&mut self, new_len: usize) {
38 let layout = blob_layout(self.len());
39 self.set_len(new_len);
40 self.data = unsafe { NonNull::new_unchecked(realloc(self.data.as_ptr(), layout, new_len)) };
41 }
42
43 pub fn truncate(&mut self, len: usize) {
47 if len < self.len() {
48 self.realloc(len);
49 }
50 }
51
52 pub fn into_raw(self) -> *mut c_void {
58 let ret = unsafe { self.data.as_ptr().offset(SIZEI).cast() };
59 forget(self);
60 ret
61 }
62
63 pub unsafe fn from_raw(ptr: *mut c_void) -> Blob {
72 Blob {
73 data: NonNull::new_unchecked(ptr.cast::<u8>().offset(-SIZEI)),
74 }
75 }
76
77 fn set_len(&mut self, len: usize) {
78 unsafe { write_unaligned(self.data.cast().as_ptr(), len) };
79 }
80
81 pub fn len(&self) -> usize {
83 unsafe { read_unaligned(self.data.cast::<usize>().as_ptr()) }
84 }
85
86 pub fn as_slice(&self) -> &[u8] {
88 unsafe { slice::from_raw_parts(self.data.as_ptr().offset(SIZEI), self.len()) }
89 }
90
91 pub fn as_mut_slice(&mut self) -> &mut [u8] {
93 unsafe { slice::from_raw_parts_mut(self.data.as_ptr().offset(SIZEI), self.len()) }
94 }
95}
96
97impl Clone for Blob {
98 fn clone(&self) -> Self {
99 let mut ret = Blob::alloc(self.len());
100 ret.as_mut_slice().copy_from_slice(self.as_slice());
101 ret
102 }
103}
104
105impl PartialEq for Blob {
106 fn eq(&self, other: &Blob) -> bool {
107 self.as_slice() == other.as_slice()
108 }
109}
110
111impl Drop for Blob {
112 fn drop(&mut self) {
113 unsafe { dealloc(self.data.as_ptr(), blob_layout(self.len())) }
114 }
115}
116
117impl From<&[u8]> for Blob {
118 fn from(val: &[u8]) -> Self {
119 let mut ret = Self::alloc(val.len());
120 ret.as_mut_slice()[..val.len()].copy_from_slice(val);
121 ret
122 }
123}
124
125impl<const N: usize> From<[u8; N]> for Blob {
126 fn from(val: [u8; N]) -> Self {
127 Self::from(&val[..])
128 }
129}
130
131impl<const N: usize> From<&[u8; N]> for Blob {
132 fn from(val: &[u8; N]) -> Self {
133 let ret = Self::alloc(N);
134 unsafe { copy_nonoverlapping(val.as_ptr(), ret.data.as_ptr().offset(SIZEI), N) };
135 ret
136 }
137}
138
139impl std::fmt::Debug for Blob {
140 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
141 f.debug_tuple("Blob").field(&self.as_slice()).finish()
142 }
143}
144
145#[cfg(test)]
146mod test {
147 use super::Blob;
148
149 #[test]
150 fn debug() {
151 let blob = Blob::from([1, 2, 3, 4]);
152 assert_eq!(format!("{blob:?}"), "Blob([1, 2, 3, 4])");
153 }
154
155 #[test]
156 fn truncate() {
157 let mut blob = Blob::from([1, 2, 3, 4]);
158 assert_eq!(blob.as_slice(), [1, 2, 3, 4]);
159 blob.truncate(2);
160 assert_eq!(blob.as_slice(), [1, 2]);
161 }
162
163 #[test]
164 fn into_raw() {
165 let ptr;
166 {
167 let blob = Blob::from([1, 2, 3, 4]);
168 assert_eq!(blob.as_slice(), [1, 2, 3, 4]);
169 ptr = blob.into_raw();
170 }
171 let blob = unsafe { Blob::from_raw(ptr) };
172 assert_eq!(blob.as_slice(), [1, 2, 3, 4]);
173 }
174}