1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
use std::mem::MaybeUninit;
use std::ptr::NonNull;
use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
use crate::{common::DatabaseRef, error::AsResult, ffi, Result};
foreign_type! {
pub unsafe type Scratch: Send {
type CType = ffi::hs_scratch_t;
fn drop = free_scratch;
fn clone = clone_scratch;
}
}
unsafe fn free_scratch(s: *mut ffi::hs_scratch_t) {
ffi::hs_free_scratch(s).expect("free scratch");
}
unsafe fn clone_scratch(s: *mut ffi::hs_scratch_t) -> *mut ffi::hs_scratch_t {
let mut p = MaybeUninit::uninit();
ffi::hs_clone_scratch(s, p.as_mut_ptr()).expect("clone scratch");
p.assume_init()
}
impl Scratch {
unsafe fn alloc<T>(db: &DatabaseRef<T>) -> Result<Scratch> {
let mut s = MaybeUninit::zeroed();
ffi::hs_alloc_scratch(db.as_ptr(), s.as_mut_ptr()).map(|_| Scratch::from_ptr(s.assume_init()))
}
unsafe fn realloc<T>(&mut self, db: &DatabaseRef<T>) -> Result<()> {
let mut p = self.as_ptr();
ffi::hs_alloc_scratch(db.as_ptr(), &mut p).map(|_| {
self.0 = NonNull::new_unchecked(p);
})
}
}
impl ScratchRef {
pub fn size(&self) -> Result<usize> {
let mut size = MaybeUninit::uninit();
unsafe { ffi::hs_scratch_size(self.as_ptr(), size.as_mut_ptr()).map(|_| size.assume_init()) }
}
}
impl<T> DatabaseRef<T> {
pub fn alloc_scratch(&self) -> Result<Scratch> {
unsafe { Scratch::alloc(self) }
}
pub fn realloc_scratch<'a>(&'a self, s: &'a mut Scratch) -> Result<&'a mut Scratch> {
unsafe { s.realloc(self) }.map(|_| s)
}
#[deprecated = "use `alloc_scratch` instead"]
pub fn alloc(&self) -> Result<Scratch> {
unsafe { Scratch::alloc(self) }
}
#[deprecated = "use `realloc_scratch` instead"]
pub fn realloc(&self, s: &mut Scratch) -> Result<()> {
unsafe { s.realloc(self) }
}
}
#[cfg(test)]
pub mod tests {
use crate::prelude::*;
const SCRATCH_SIZE: usize = 2000;
#[test]
fn test_scratch() {
let db: BlockDatabase = "test".parse().unwrap();
let s = db.alloc_scratch().unwrap();
assert!(s.size().unwrap() > SCRATCH_SIZE);
let mut s2 = s.clone();
assert!(s2.size().unwrap() > SCRATCH_SIZE);
let db2: VectoredDatabase = "foobar".parse().unwrap();
db2.realloc_scratch(&mut s2).unwrap();
assert!(s2.size().unwrap() > s.size().unwrap());
}
}