1#![allow(non_upper_case_globals)]
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4
5use std::ffi::{CStr, CString};
6use std::ptr;
7use libc::{c_char, c_void};
8
9mod bindings;
10pub use bindings::*;
11
12pub const QM_MISS: u32 = u32::MAX;
13
14pub struct Qmap {
16 hd: u32,
17}
18
19impl Qmap {
20 pub fn open(
21 filename: Option<&str>,
22 database: Option<&str>,
23 ktype: u32,
24 vtype: u32,
25 mask: u32,
26 flags: u32,
27 ) -> Option<Self> {
28 let c_filename = filename.map(|s| CString::new(s).unwrap());
29 let c_database = database.map(|s| CString::new(s).unwrap());
30
31 let hd = unsafe {
32 qmap_open(
33 c_filename.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
34 c_database.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
35 ktype,
36 vtype,
37 mask,
38 flags,
39 )
40 };
41
42 if hd == QM_MISS {
43 None
44 } else {
45 Some(Qmap { hd })
46 }
47 }
48
49 pub fn handle(&self) -> u32 {
50 self.hd
51 }
52
53 pub unsafe fn from_handle(hd: u32) -> Self {
56 Qmap { hd }
57 }
58
59 pub fn get(&self, key: *const c_void) -> *const c_void {
60 unsafe { qmap_get(self.hd, key) }
61 }
62
63 pub fn get_str(&self, key: &str) -> Option<&str> {
64 let c_key = CString::new(key).unwrap();
65 let val_ptr = unsafe { qmap_get(self.hd, c_key.as_ptr() as *const c_void) };
66 if val_ptr.is_null() {
67 None
68 } else {
69 unsafe {
70 CStr::from_ptr(val_ptr as *const c_char).to_str().ok()
71 }
72 }
73 }
74
75 pub fn put(&self, key: *const c_void, value: *const c_void) -> u32 {
76 unsafe { qmap_put(self.hd, key, value) }
77 }
78
79 pub fn put_str(&self, key: &str, value: &str) -> u32 {
80 let c_key = CString::new(key).unwrap();
81 let c_value = CString::new(value).unwrap();
82 unsafe {
83 qmap_put(
84 self.hd,
85 c_key.as_ptr() as *const c_void,
86 c_value.as_ptr() as *const c_void,
87 )
88 }
89 }
90
91 pub fn del(&self, key: *const c_void) {
92 unsafe { qmap_del(self.hd, key) }
93 }
94
95 pub fn drop(&self) {
96 unsafe { qmap_drop(self.hd) }
97 }
98
99 pub fn iter(&self, key: *const c_void, flags: u32) -> Cursor {
100 let cur_id = unsafe { qmap_iter(self.hd, key, flags) };
101 Cursor { cur_id }
102 }
103}
104
105impl Drop for Qmap {
106 fn drop(&mut self) {
107 unsafe { qmap_close(self.hd) }
108 }
109}
110
111pub struct Cursor {
112 cur_id: u32,
113}
114
115impl Cursor {
116 pub fn next(&mut self) -> Option<(*const c_void, *const c_void)> {
117 let mut key: *const c_void = ptr::null();
118 let mut value: *const c_void = ptr::null();
119 let res = unsafe { qmap_next(&mut key, &mut value, self.cur_id) };
120 if res == 1 {
121 Some((key, value))
122 } else {
123 None
124 }
125 }
126}
127
128impl Drop for Cursor {
129 fn drop(&mut self) {
130 unsafe { qmap_fin(self.cur_id) }
131 }
132}
133
134pub fn save() {
135 unsafe { qmap_save() }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141
142 #[test]
143 fn test_qmap_open_in_memory() {
144 let q = Qmap::open(None, None, qmap_tbi_QM_STR, qmap_tbi_QM_STR, 0xFF, 0);
145 assert!(q.is_some());
146 let q = q.unwrap();
147 q.put_str("key1", "value1");
148 assert_eq!(q.get_str("key1"), Some("value1"));
149 assert_eq!(q.get_str("key2"), None);
150 }
151}