k2hash_rust/lib.rs
1//
2// k2hash_rust
3//
4// Copyright 2025 LY Corporation.
5//
6// Rust driver for k2hash that is a NoSQL Key Value Store(KVS) library.
7// For k2hash, see https://github.com/yahoojapan/k2hash for the details.
8//
9// For the full copyright and license information, please view
10// the license file that was distributed with this source code.
11//
12// AUTHOR: Hirotaka Wakabayashi
13// CREATE: Fri, 17 Jul 2025
14// REVISION:
15//
16//
17
18/*!
19k2hash_rust is a NoSQL Key Value Store(KVS) library developed by [AntPickax](https://antpick.ax/),
20which is an open source team in [LY Corporation](https://www.lycorp.co.jp/en/company/overview/) and a product family
21of open source software developed by [AntPickax](https://antpick.ax/).
22
23# k2hash_rust
24
25## Overview
26
27**k2hash_rust** implements a [k2hash](https://k2hash.antpick.ax/) client in Rust.
28
29## Install
30
31Firstly you must install the [k2hash](https://k2hash.antpick.ax/) shared library.
32```sh
33curl -o- https://raw.github.com/yahoojapan/k2hash_rust/main/utils/libk2hash.sh | bash
34```
35You can install **k2hash** library step by step from [source code](https://github.com/yahoojapan/k2hash). See [Build](https://k2hash.antpick.ax/build.html) for details.
36
37Download the **k2hash_rust** package.
38
39```sh
40cd /path/to/your/rust/project
41cargo add k2hash_rust
42```
43
44## Usage
45
46Here is a simple example of **k2hash_rust** that saves a key and get it.
47
48```rust
49use k2hash_rust::K2hash;
50
51fn main() {
52 let db = K2hash::open_mem().expect("open_mem failed");
53 db.set("foo", "bar");
54 let v = db.get("foo");
55 println!("foo => {:?}", v);
56}
57```
58
59## Development
60
61Here is the step to start developing **k2hash_rust** on Fedora42.
62
63```sh
64sudo dnf update -y
65```
66
67```sh
68sudo dnf makecache && sudo yum install curl git -y && curl -s https://packagecloud.io/install/repositories/antpickax/stable/script.rpm.sh | sudo bash
69sudo dnf install libfullock-devel k2hash-devel -y
70git clone https://github.com/yahoojapan/k2hash_rust.git
71cd k2hash_rust
72cargo build
73cargo test
74```
75
76### Documents
77 - [About K2HASH](https://k2hash.antpick.ax/)
78 - [About AntPickax](https://antpick.ax/)
79
80### License
81
82MIT License. See the LICENSE file.
83
84## AntPickax
85
86[AntPickax](https://antpick.ax/) is
87 - an open source team in [LY Corporation](https://www.lycorp.co.jp/en/company/overview/).
88 - a product family of open source software developed by [AntPickax](https://antpick.ax/).
89*/
90
91use std::collections::HashMap; // Import HashMap for attributes
92
93// CString: create CString instance from Rust string.
94// CStr: create CStr instance from C API's pointer.
95use std::ffi::{CStr, CString};
96use std::os::raw::{c_char, c_int, c_uchar, c_ulong, c_ulonglong, c_void};
97use std::ptr;
98
99// use libc::size_t;
100
101/// DumpLevel represents the level of detail in the dump output.
102#[derive(PartialEq)]
103pub enum DumpLevel {
104 HEADER,
105 HASHTABLE,
106 SUBHASHTABLE,
107 ELEMENT,
108 PAGE,
109}
110
111/// DebugLevel represents the level of detail in the debug output.
112pub enum DebugLevel {
113 SILENT,
114 ERROR,
115 WARNING,
116 MESSAGE,
117}
118
119//
120// k2hash C API
121//
122// # typedef struct k2h_key_pack{
123// # unsigned char* pkey;
124// # size_t length;
125// # }K2HKEYPCK, *PK2HKEYPCK;
126// #
127
128/// K2hKeyPack represents C-API's K2HKEYPCK structure.
129#[repr(C)]
130pub struct K2hKeyPack {
131 pub pkey: *mut u8,
132 pub length: usize,
133}
134// typedef struct {
135// unsigned char* pkey;
136// size_t keylength;
137// unsigned char* pval;
138// size_t vallength;
139// } K2HATTRPCK;
140
141/// K2hAttrPack represents C-API's K2HATTRPCK structure.
142#[repr(C)]
143pub struct K2hAttrPack {
144 pub pkey: *mut u8,
145 pub keylength: usize,
146 pub pval: *mut u8,
147 pub vallength: usize,
148}
149
150// K2H_INVALID_HANDLE = 0;
151
152#[link(name = "k2hash")]
153extern "C" {
154
155 // k2h_open_mem(int maskbitcnt, int cmaskbitcnt, int maxelementcnt, int pagesize)
156 fn k2h_open_mem(maskbitcnt: i32, cmaskbitcnt: i32, maxelementcnt: i32, pagesize: i32) -> u64;
157
158 // bool k2h_set_str_value_wa(k2h_h handle, const char* pkey, const char* pval, const char* pass, const time_t* expire)
159 fn k2h_set_str_value_wa(
160 handle: u64,
161 pkey: *const c_char,
162 pval: *const c_char,
163 pass: *const c_char,
164 expire: *const c_ulonglong,
165 ) -> bool;
166
167 // char* k2h_get_str_direct_value_wp(k2h_h handle, const char* pkey, const char* pass)
168 fn k2h_get_str_direct_value_wp(
169 handle: u64,
170 pkey: *const c_char,
171 pass: *const c_char,
172 ) -> *mut c_char;
173
174 /// Defines prototypes for Rust code
175 ////////////////////////////////////////////////////////
176 /// 4. find API
177 ////////////////////////////////////////////////////////
178 ///
179 /// k2h_find_h k2h_find_first(k2h_h handle)
180 /// k2h_find_first: Find the first key
181 ///
182 /// # Arguments
183 /// * `handle` - k2hash handle
184 ///
185 /// # Returns
186 /// * `u64` - find handle
187 fn k2h_find_first(handle: u64) -> u64;
188
189 /// k2h_find_first_str_subkey: Find the first subkey for a key
190 ///
191 /// # Arguments
192 /// * `handle` - k2hash handle
193 /// * `pkey` - key string
194 ///
195 /// # Returns
196 /// * `u64` - find handle
197 fn k2h_find_first_str_subkey(handle: u64, pkey: *const c_char) -> u64;
198
199 /// k2h_find_next: Find the next key
200 ///
201 /// # Arguments
202 /// * `findhandle` - find handle
203 ///
204 /// # Returns
205 /// * `u64` - next find handle
206 fn k2h_find_next(findhandle: u64) -> u64;
207
208 /// k2h_find_get_key: Get key from find handle
209 ///
210 /// # Arguments
211 /// * `findhandle` - find handle
212 /// * `ppkey` - pointer to key pointer
213 /// * `pkeylength` - pointer to key length
214 ///
215 /// # Returns
216 /// * `bool` - true on success
217 fn k2h_find_get_key(findhandle: u64, ppkey: *mut *mut c_uchar, pkeylength: *mut usize) -> bool;
218
219 ////////////////////////////////////////////////////////
220 /// 3. keyqueue API
221 ////////////////////////////////////////////////////////
222 ///
223 /// k2h_keyq_handle_str_prefix: Create a key queue handle with prefix
224 ///
225 /// # Arguments
226 /// * `handle` - k2hash handle
227 /// * `is_fifo` - FIFO flag
228 /// * `pref` - prefix string
229 ///
230 /// # Returns
231 /// * `u64` - key queue handle
232 fn k2h_keyq_handle_str_prefix(handle: u64, is_fifo: bool, pref: *const c_char) -> u64;
233
234 /// k2h_keyq_str_push_keyval: Push a key-value pair into the key queue
235 ///
236 /// # Arguments
237 /// * `keyqhandle` - key queue handle
238 /// * `pkey` - key string
239 /// * `pval` - value string
240 ///
241 /// # Returns
242 /// * `bool` - true on success
243 // fn k2h_keyq_str_push_keyval(keyqhandle: u64, pkey: *const c_char, pval: *const c_char) -> bool;
244
245 /// k2h_keyq_str_push_keyval_wa: Push a key-value pair into the key queue with password and expiration
246 ///
247 /// # Arguments
248 /// * `keyqhandle` - key queue handle
249 /// * `pkey` - key string
250 /// * `pval` - value string
251 /// * `encpass` - encryption password string
252 /// * `expire` - pointer to expiration time
253 ///
254 /// # Returns
255 /// * `bool` - true on success
256 fn k2h_keyq_str_push_keyval_wa(
257 keyqhandle: u64,
258 pkey: *const c_char,
259 pval: *const c_char,
260 encpass: *const c_char,
261 expire: *const c_ulonglong,
262 ) -> bool;
263
264 /// k2h_keyq_dump: Dump key queue contents to a stream
265 ///
266 /// # Arguments
267 /// * `qhandle` - key queue handle
268 /// * `stream` - FILE pointer
269 ///
270 /// # Returns
271 /// * `bool` - true on success
272 fn k2h_keyq_dump(qhandle: u64, stream: *mut c_void) -> bool;
273
274 /// k2h_keyq_free: Free a key queue handle
275 ///
276 /// # Arguments
277 /// * `qhandle` - key queue handle
278 ///
279 /// # Returns
280 /// * `bool` - true on success
281 fn k2h_keyq_free(qhandle: u64) -> bool;
282
283 /// k2h_keyq_count: Get the number of elements in the key queue
284 ///
285 /// # Arguments
286 /// * `qhandle` - key queue handle
287 ///
288 /// # Returns
289 /// * `c_int` - number of elements
290 fn k2h_keyq_count(qhandle: u64) -> c_int;
291
292 /// k2h_keyq_str_read_keyval_wp: Read a key-value pair from the key queue at a specific position with password
293 ///
294 /// # Arguments
295 /// * `keyqhandle` - key queue handle
296 /// * `ppkey` - pointer to key pointer
297 /// * `ppval` - pointer to value pointer
298 /// * `pos` - position in queue
299 /// * `encpass` - encryption password string
300 ///
301 /// # Returns
302 /// * `bool` - true on success
303 fn k2h_keyq_str_read_keyval_wp(
304 keyqhandle: u64,
305 ppkey: *mut *mut c_char,
306 ppval: *mut *mut c_char,
307 pos: c_int,
308 encpass: *const c_char,
309 ) -> bool;
310
311 /// k2h_keyq_empty: Check if the key queue is empty
312 ///
313 /// # Arguments
314 /// * `qhandle` - key queue handle
315 ///
316 /// # Returns
317 /// * `bool` - true if empty
318 fn k2h_keyq_empty(qhandle: u64) -> bool;
319
320 /// k2h_keyq_str_pop_keyval_wp: Pop a key-value pair from the key queue with password
321 ///
322 /// # Arguments
323 /// * `keyqhandle` - key queue handle
324 /// * `ppkey` - pointer to key pointer
325 /// * `ppval` - pointer to value pointer
326 /// * `encpass` - encryption password string
327 ///
328 /// # Returns
329 /// * `bool` - true on success
330 fn k2h_keyq_str_pop_keyval_wp(
331 keyqhandle: u64,
332 ppkey: *mut *mut c_char,
333 ppval: *mut *mut c_char,
334 encpass: *const c_char,
335 ) -> bool;
336
337 /// k2h_keyq_remove: Remove elements from the key queue
338 ///
339 /// # Arguments
340 /// * `qhandle` - key queue handle
341 /// * `count` - number of elements to remove
342 ///
343 /// # Returns
344 /// * `bool` - true on success
345 fn k2h_keyq_remove(qhandle: u64, count: c_int) -> bool;
346
347 ////////////////////////////////////////////////////////
348 /// 2. queue API
349 ////////////////////////////////////////////////////////
350 /// k2h_q_h k2h_q_handle_str_prefix(k2h_h handle, bool is_fifo, const char* pref)
351 /// k2h_q_handle_str_prefix: Create a queue handle with prefix
352 ///
353 /// # Arguments
354 /// * `handle` - k2hash handle
355 /// * `is_fifo` - FIFO flag
356 /// * `pref` - prefix string
357 ///
358 /// # Returns
359 /// * `u64` - queue handle
360 fn k2h_q_handle_str_prefix(handle: u64, is_fifo: bool, pref: *const c_char) -> u64;
361
362 /// k2h_q_str_push_wa: Push a value with attributes, password, and expiration into the queue
363 ///
364 /// # Arguments
365 /// * `qhandle` - queue handle
366 /// * `pdata` - data string
367 /// * `pattrspck` - pointer to attribute pack
368 /// * `attrspckcnt` - attribute pack count
369 /// * `encpass` - encryption password string
370 /// * `expire` - pointer to expiration time
371 ///
372 /// # Returns
373 /// * `bool` - true on success
374 fn k2h_q_str_push_wa(
375 qhandle: u64,
376 pdata: *const c_char,
377 pattrspck: *const c_void,
378 attrspckcnt: c_int,
379 encpass: *const c_char,
380 expire: *const c_ulonglong,
381 ) -> bool;
382
383 /// k2h_q_str_push: Push a value into the queue
384 ///
385 /// # Arguments
386 /// * `qhandle` - queue handle
387 /// * `pval` - value string
388 ///
389 /// # Returns
390 /// * `bool` - true on success
391 /// fn k2h_q_str_push(qhandle: u64, pval: *const c_char) -> bool;
392
393 /// k2h_q_remove: Remove elements from the queue
394 ///
395 /// # Arguments
396 /// * `qhandle` - queue handle
397 /// * `count` - number of elements to remove
398 ///
399 /// # Returns
400 /// * `bool` - true on success
401 fn k2h_q_remove(qhandle: u64, count: c_int) -> bool;
402
403 /// k2h_q_free: Free a queue handle
404 ///
405 /// # Arguments
406 /// * `qhandle` - queue handle
407 ///
408 /// # Returns
409 /// * `bool` - true on success
410 fn k2h_q_free(qhandle: u64) -> bool;
411
412 /// k2h_q_count: Get the number of elements in the queue
413 ///
414 /// # Arguments
415 /// * `qhandle` - queue handle
416 ///
417 /// # Returns
418 /// * `c_int` - number of elements
419 fn k2h_q_count(qhandle: u64) -> c_int;
420
421 /// k2h_q_str_read_wp: Read a value from the queue at a specific position with password
422 ///
423 /// # Arguments
424 /// * `qhandle` - queue handle
425 /// * `ppdata` - pointer to data pointer
426 /// * `pos` - position in queue
427 /// * `encpass` - encryption password string
428 ///
429 /// # Returns
430 /// * `bool` - true on success
431 fn k2h_q_str_read_wp(
432 qhandle: u64,
433 ppdata: *mut *mut c_char,
434 pos: c_int,
435 encpass: *const c_char,
436 ) -> bool;
437
438 /// k2h_q_empty: Check if the queue is empty
439 ///
440 /// # Arguments
441 /// * `qhandle` - queue handle
442 ///
443 /// # Returns
444 /// * `bool` - true if empty
445 fn k2h_q_empty(qhandle: u64) -> bool;
446
447 /// k2h_q_str_pop: Pop a value from the queue
448 ///
449 /// # Arguments
450 /// * `qhandle` - queue handle
451 /// * `ppval` - pointer to value pointer
452 ///
453 /// # Returns
454 /// * `bool` - true on success
455 /// fn k2h_q_str_pop(qhandle: u64, ppval: *mut *mut c_char) -> bool;
456
457 /// k2h_q_str_pop_wp: Pop a value from the queue with password
458 ///
459 /// # Arguments
460 /// * `qhandle` - queue handle
461 /// * `ppdata` - pointer to data pointer
462 /// * `encpass` - encryption password string
463 ///
464 /// # Returns
465 /// * `bool` - true on success
466 fn k2h_q_str_pop_wp(qhandle: u64, ppdata: *mut *mut c_char, encpass: *const c_char) -> bool;
467
468 /// k2h_q_dump: Dump queue contents to a stream
469 ///
470 /// # Arguments
471 /// * `qhandle` - queue handle
472 /// * `stream` - FILE pointer
473 ///
474 /// # Returns
475 /// * `bool` - true on success
476 fn k2h_q_dump(qhandle: u64, stream: *mut c_void) -> bool;
477
478 ////////////////////////////////////////////////////////
479 /// 1. k2hash API
480 ////////////////////////////////////////////////////////
481 /// k2h_add_attr_crypt_pass: Add password for encryption
482 ///
483 /// # Arguments
484 /// * `handle` - k2hash handler
485 /// * `pass` - password string
486 /// * `is_default_encrypt` - whether to use default encryption
487 ///
488 /// # Returns
489 /// * `bool` - True on success
490 /// # bool k2h_add_attr_crypt_pass(k2h_h handle, const char* pass, bool is_default_encrypt)
491 fn k2h_add_attr_crypt_pass(handle: u64, pass: *const c_char, is_default_encrypt: bool) -> bool;
492
493 /// # add attr plugin API
494 /// # bool k2h_add_attr_plugin_library(k2h_h handle, const char* libpath)
495 /// k2h_add_attr_plugin_library: Add attribute plugin library
496 ///
497 /// # Arguments
498 /// * `handle` - k2hash handler
499 /// * `libpath` - library path string
500 ///
501 /// # Returns
502 /// * `bool` - True on success
503 fn k2h_add_attr_plugin_library(handle: u64, libpath: *const c_char) -> bool;
504
505 /// # add attr API
506 /// # bool k2h_add_str_attr(k2h_h handle, const char* pkey, const char* pattrkey, const char* pattrval)
507 /// k2h_add_str_attr: Add string attribute
508 ///
509 /// # Arguments
510 /// * `handle` - k2hash handle
511 /// * `pkey` - key string
512 /// * `pattrkey` - attribute key string
513 /// * `pattrval` - attribute value string
514 ///
515 /// # Returns
516 /// * `bool` - True on success
517 // fn k2h_add_str_attr(
518 // handle: u64,
519 // pkey: *const c_char,
520 // pattrkey: *const c_char,
521 // pattrval: *const c_char,
522 // ) -> bool;
523
524 /// # bool k2h_add_attr(k2h_h handle, const unsigned char* pkey, size_t keylength, const unsigned char* pattrkey, size_t attrkeylength, const unsigned char* pattrval, size_t attrvallength)
525 /// k2h_add_attr: Add attribute
526 ///
527 /// # Arguments
528 /// * `handle` - k2hash handle
529 /// * `pkey` - key
530 /// * `keylength` - key length
531 /// * `pattrkey` - attribute key
532 /// * `attrkeylength` - attribute key length
533 /// * `pattrval` - attribute value
534 /// * `attrvallength` - attribute value length
535 ///
536 /// # Returns
537 /// * `bool` - True on success
538 fn k2h_add_attr(
539 handle: u64,
540 pkey: *const u8,
541 keylength: usize,
542 pattrkey: *const u8,
543 attrkeylength: usize,
544 pattrval: *const u8,
545 attrvallength: usize,
546 ) -> bool;
547
548 /// # add subkey API
549 /// # bool k2h_add_subkey(k2h_h handle, const unsigned char* pkey, size_t keylength, const unsigned char* psubkey, size_t skeylength, const unsigned char* pval, size_t vallength)
550 /// k2h_add_subkey: Add a subkey attribute
551 ///
552 /// # Arguments
553 /// * `handle` - k2hash handle
554 /// * `pkey` - key pointer
555 /// * `keylength` - key length
556 /// * `psubkey` - subkey pointer
557 /// * `skeylength` - subkey length
558 /// * `pval` - value pointer
559 /// * `vallength` - value length
560 ///
561 /// # Returns
562 /// * `bool` - true on success
563 // fn k2h_add_subkey(
564 // handle: u64,
565 // pkey: *const u8,
566 // keylength: usize,
567 // psubkey: *const u8,
568 // skeylength: usize,
569 // pval: *const u8,
570 // vallength: usize,
571 // ) -> bool;
572
573 /// # bool k2h_add_subkey_wa(k2h_h handle, const unsigned char* pkey, size_t keylength, const unsigned char* psubkey, size_t skeylength, const unsigned char* pval, size_t vallength, const char* pass, const time_t* expire)
574 /// k2h_add_subkey_wa: Add subkey attribute(encryption, expiration in second)
575 ///
576 /// # Arguments
577 /// # Arguments
578 /// * `handle` - k2hash handle
579 /// * `pkey` - key
580 /// * `keylength` - key length
581 /// * `psubkey` - subkey
582 /// * `skeylength` - subkey length
583 /// * `pval` - valuea
584 /// * `vallength` - value length
585 /// * `pass` - password
586 /// * `expire` - expiration in second
587 ///
588 /// # Returns
589 /// * `bool` - True on success
590 fn k2h_add_subkey_wa(
591 handle: u64,
592 pkey: *const u8,
593 keylength: usize,
594 psubkey: *const u8,
595 skeylength: usize,
596 pval: *const u8,
597 vallength: usize,
598 pass: *const c_char,
599 expire: *const c_ulonglong,
600 ) -> bool;
601
602 /// # close API
603 /// # bool k2h_close(k2h_h handle)
604 /// k2h_close: close k2hash handle
605 ///
606 /// # Arguments
607 /// * `handle` - k2hash handle
608 ///
609 /// # Returns
610 /// * `bool` - True on success
611 fn k2h_close(handle: u64) -> bool;
612
613 /// # bool k2h_close_wait(k2h_h handle, long waitms)
614 /// k2h_close_wait: close k2hash handle with wait
615 ///
616 /// # Arguments
617 /// * `handle` - k2hash handle
618 /// * `waitms` - wait time in milliseconds
619 ///
620 /// # Returns
621 /// * `bool` - True on success
622 // fn k2h_close_wait(handle: u64, waitms: i64) -> bool;
623
624 /// # create API
625 /// # bool k2h_create(const char* filepath, int maskbitcnt, int cmaskbitcnt, int maxelementcnt, size_t pagesize)
626 /// k2h_create: Create a new k2hash database
627 ///
628 /// # Arguments
629 /// * `filepath` - file path for the database
630 /// * `maskbitcnt` - mask bit count
631 /// * `cmaskbitcnt` - chain mask bit count
632 /// * `maxelementcnt` - maximum element count
633 /// * `pagesize` - page size
634 ///
635 /// # Returns
636 /// * `bool` - True on success
637 fn k2h_create(
638 filepath: *const c_char,
639 maskbitcnt: i32,
640 cmaskbitcnt: i32,
641 maxelementcnt: i32,
642 pagesize: usize,
643 ) -> bool;
644
645 /// # disable tx API
646 /// # bool k2h_disable_transaction(k2h_h handle)
647 /// k2h_disable_transaction: disable transaction
648 ///
649 /// # Arguments
650 /// * `handle` - k2hash handle
651 ///
652 /// # Returns
653 /// * `bool` - True on success
654 fn k2h_disable_transaction(handle: u64) -> bool;
655
656 /// # dump API
657 /// # bool k2h_dump_head(k2h_h handle, FILE* stream)
658 /// k2h_dump_head: header information dump
659 ///
660 /// # Arguments
661 /// * `handle` - k2hash handle
662 /// * `stream` - FILE pointer
663 ///
664 /// # Returns
665 /// * `bool` - True on success
666 fn k2h_dump_head(handle: u64, stream: *mut c_void) -> bool;
667
668 /// # bool k2h_dump_keytable(k2h_h handle, FILE* stream)
669 /// k2h_dump_keytable: dump key table information
670 ///
671 /// # Arguments
672 /// * `handle` - k2hash handle
673 /// * `stream` - FILE pointer
674 ///
675 /// # Returns
676 /// * `bool` - True on success
677 fn k2h_dump_keytable(handle: u64, stream: *mut c_void) -> bool;
678
679 /// # bool k2h_dump_full_keytable(k2h_h handle, FILE* stream)
680 /// k2h_dump_full_keytable: dump full key table information
681 ///
682 /// # Arguments
683 /// * `handle` - k2hash handle
684 /// * `stream` - FILE pointer
685 ///
686 /// # Returns
687 /// * `bool` - True on success
688 fn k2h_dump_full_keytable(handle: u64, stream: *mut c_void) -> bool;
689
690 /// # bool k2h_dump_elementtable(k2h_h handle, FILE* stream)
691 /// k2h_dump_elementtable: dump element table information
692 ///
693 /// # Arguments
694 /// * `handle` - k2hash handle
695 /// * `stream` - FILE pointer
696 ///
697 /// # Returns
698 /// * `bool` - True on success
699 fn k2h_dump_elementtable(handle: u64, stream: *mut c_void) -> bool;
700
701 /// # bool k2h_dump_full(k2h_h handle, FILE* stream)
702 /// k2h_dump_full: dump full k2hash information
703 ///
704 /// # Arguments
705 /// * `handle` - k2hash handle
706 /// * `stream` - FILE pointer
707 ///
708 /// # Returns
709 /// * `bool` - True on success
710 fn k2h_dump_full(handle: u64, stream: *mut c_void) -> bool;
711
712 /// # get value API
713 /// # char* k2h_get_str_direct_value_wp(k2h_h handle, const char* pkey, const char* pass)
714 /// k2h_get_str_direct_value_wp: Get string value directly
715 ///
716 /// # Arguments
717 /// * `handle` - k2hash handle
718 /// * `pkey` - key string
719 /// * `pass` - password string
720 ///
721 /// # Returns
722 /// * `*mut c_char` - pointer to C string (must be freed if necessary)
723 /// fn k2h_get_str_direct_value_wp(
724 /// handle: u64,
725 /// pkey: *const c_char,
726 /// pass: *const c_char,
727 /// ) -> *mut c_char;
728
729 /// # get attrs API
730 /// # PK2HATTRPCK k2h_get_direct_attrs(k2h_h handle, const unsigned char* pkey, size_t keylength, int* pattrspckcnt)
731 /// k2h_get_direct_attrs: Get direct attributes
732 ///
733 /// # Arguments
734 /// * `handle` - k2hash handle
735 /// * `pkey` - key pointer
736 /// * `keylength` - key length
737 /// * `pattrspckcnt` - pointer to attribute count
738 ///
739 /// # Returns
740 /// * `*mut c_void` - pointer to attribute pack (replace with actual struct if available)
741 fn k2h_get_direct_attrs(
742 handle: u64,
743 pkey: *const u8,
744 keylength: usize,
745 pattrspckcnt: *mut c_int,
746 ) -> *mut c_void;
747
748 /// # get subkeys API
749 /// # PK2HKEYPCK k2h_get_direct_subkeys(k2h_h handle, const unsigned char* pkey, size_t keylength, int* pskeypckcnt)
750 /// k2h_get_direct_subkeys: Get direct subkeys
751 ///
752 /// # Arguments
753 /// * `handle` - k2hash handle
754 /// * `pkey` - key pointer
755 /// * `keylength` - key length
756 /// * `pskeypckcnt` - pointer to subkey count
757 ///
758 /// # Returns
759 /// * `*mut c_void` - pointer to subkey pack (replace with actual struct if available)
760 fn k2h_get_direct_subkeys(
761 handle: u64,
762 pkey: *const u8,
763 keylength: usize,
764 pskeypckcnt: *mut c_int,
765 ) -> *mut c_void;
766
767 /// # get transaction API
768 /// # int k2h_get_transaction_archive_fd(k2h_h handle)
769 /// k2h_get_transaction_archive_fd: Get transaction archive file descriptor
770 ///
771 /// # Arguments
772 /// * `handle` - k2hash handle
773 ///
774 /// # Returns
775 /// * `c_int` - file descriptor
776 fn k2h_get_transaction_archive_fd(handle: u64) -> c_int;
777
778 /// # int k2h_get_transaction_thread_pool(void)
779 /// k2h_get_transaction_thread_pool: Get transaction thread pool count
780 ///
781 /// # Arguments
782 /// (none)
783 ///
784 /// # Returns
785 /// * `c_int` - thread pool count
786 fn k2h_get_transaction_thread_pool() -> c_int;
787
788 /// # load archive API
789 /// # bool k2h_load_archive(k2h_h handle, const char* filepath, bool errskip)
790 /// k2h_load_archive: Load archive file
791 ///
792 /// # Arguments
793 /// * `handle` - k2hash handle
794 /// * `filepath` - file path
795 /// * `errskip` - skip errors flag
796 ///
797 /// # Returns
798 /// * `bool` - true on success
799 fn k2h_load_archive(handle: u64, filepath: *const c_char, errskip: bool) -> bool;
800
801 /// # open API
802 // k2h_open_mem(int maskbitcnt, int cmaskbitcnt, int maxelementcnt, int pagesize)
803 fn k2h_open(
804 pfile: *const c_char,
805 readonly: bool,
806 removefile: bool,
807 fullmap: bool,
808 maskbitcnt: i32,
809 cmaskbitcnt: i32,
810 maxelementcnt: i32,
811 pagesize: i32,
812 ) -> u64;
813
814 /// # print API
815 /// # bool k2h_print_attr_version(k2h_h handle, FILE* stream)
816 /// k2h_print_attr_version: Print attribute version information
817 ///
818 /// # Arguments
819 /// * `handle` - k2hash handle
820 /// * `stream` - FILE pointer
821 ///
822 /// # Returns
823 /// * `bool` - true on success
824 fn k2h_print_attr_version(handle: u64, stream: *mut c_void) -> bool;
825
826 /// # bool k2h_print_attr_information(k2h_h handle, FILE* stream)
827 /// k2h_print_attr_information: Print attribute information
828 ///
829 /// # Arguments
830 /// * `handle` - k2hash handle
831 /// * `stream` - FILE pointer
832 ///
833 /// # Returns
834 /// * `bool` - true on success
835 fn k2h_print_attr_information(handle: u64, stream: *mut c_void) -> bool;
836
837 /// # bool k2h_print_state(k2h_h handle, FILE* stream)
838 /// k2h_print_state: Print state information
839 ///
840 /// # Arguments
841 /// * `handle` - k2hash handle
842 /// * `stream` - FILE pointer
843 ///
844 /// # Returns
845 /// * `bool` - true on success
846 fn k2h_print_state(handle: u64, stream: *mut c_void) -> bool;
847
848 /// # void k2h_print_version(FILE* stream)
849 /// k2h_print_version: Print version information
850 ///
851 /// # Arguments
852 /// * `stream` - FILE pointer
853 ///
854 /// # Returns
855 /// * nothing (void)
856 fn k2h_print_version(stream: *mut c_void);
857
858 /// # put_archive API
859 /// # bool k2h_put_archive(k2h_h handle, const char* filepath, bool errskip)
860 /// k2h_put_archive: Put archive file
861 ///
862 /// # Arguments
863 /// * `handle` - k2hash handle
864 /// * `filepath` - file path
865 /// * `errskip` - skip errors flag
866 ///
867 /// # Returns
868 /// * `bool` - true on success
869 fn k2h_put_archive(handle: u64, filepath: *const c_char, errskip: bool) -> bool;
870
871 /// # remove API
872 /// # bool k2h_remove_str_all(k2h_h handle, const char* pkey)
873 /// k2h_remove_str_all: Remove all values for a key
874 ///
875 /// # Arguments
876 /// * `handle` - k2hash handle
877 /// * `pkey` - key string
878 ///
879 /// # Returns
880 /// * `bool` - true on success
881 fn k2h_remove_str_all(handle: u64, pkey: *const c_char) -> bool;
882
883 /// # bool k2h_remove_str(k2h_h handle, const char* pkey)
884 /// k2h_remove_str: Remove values for a key
885 ///
886 /// # Arguments
887 /// * `handle` - k2hash handle
888 /// * `pkey` - key string
889 ///
890 /// # Returns
891 /// * `bool` - true on success
892 fn k2h_remove_str(handle: u64, pkey: *const c_char) -> bool;
893
894 /// # rename API
895 /// # bool k2h_rename_str(k2h_h handle, const char* pkey, const char* pnewkey)
896 /// k2h_rename_str: Rename a key
897 ///
898 /// # Arguments
899 /// * `handle` - k2hash handle
900 /// * `pkey` - old key string
901 /// * `pnewkey` - new key string
902 ///
903 /// # Returns
904 /// * `bool` - true on success
905 fn k2h_rename_str(handle: u64, pkey: *const c_char, pnewkey: *const c_char) -> bool;
906
907 /// # remove subkey API
908 /// # bool k2h_remove_str_subkey(k2h_h handle, const char* pkey, const char* psubkey)
909 /// k2h_remove_str_subkey: Remove a subkey from a key
910 ///
911 /// # Arguments
912 /// * `handle` - k2hash handle
913 /// * `pkey` - key string
914 /// * `psubkey` - subkey string
915 ///
916 /// # Returns
917 /// * `bool` - true on success
918 fn k2h_remove_str_subkey(handle: u64, pkey: *const c_char, psubkey: *const c_char) -> bool;
919
920 /// # set_common_attr
921 /// # bool k2h_set_common_attr(k2h_h handle, const bool* is_mtime, const bool* is_defenc, const char* passfile, const bool* is_history, const c_ulong* expire)
922 /// k2h_set_common_attr: Set common attributes
923 ///
924 /// # Arguments
925 /// * `handle` - k2hash handle
926 /// * `is_mtime` - pointer to bool
927 /// * `is_defenc` - pointer to bool
928 /// * `passfile` - file path string
929 /// * `is_history` - pointer to bool
930 /// * `expire` - pointer to c_ulong
931 ///
932 /// # Returns
933 /// * `bool` - true on success
934 fn k2h_set_common_attr(
935 handle: u64,
936 is_mtime: *const bool,
937 is_defenc: *const bool,
938 passfile: *const c_char,
939 is_history: *const bool,
940 expire: *const c_ulong,
941 ) -> bool;
942
943 // # set loglevel
944 /// # bool k2h_set_debug_level_silent(void)
945 /// k2h_set_debug_level_silent: Set debug level to silent
946 ///
947 /// # Arguments
948 /// * `void` - no arguments
949 ///
950 /// # Returns
951 /// * `bool` - true on success
952 fn k2h_set_debug_level_silent() -> bool;
953
954 /// # bool k2h_set_debug_level_error(void)
955 /// k2h_set_debug_level_error: Set debug level to error
956 ///
957 /// # Arguments
958 /// * `void` - no arguments
959 ///
960 /// # Returns
961 /// * `bool` - true on success
962 fn k2h_set_debug_level_error() -> bool;
963
964 /// # bool k2h_set_debug_level_warning(void)
965 /// k2h_set_debug_level_warning: Set debug level to warning
966 ///
967 /// # Arguments
968 /// * `void` - no arguments
969 ///
970 /// # Returns
971 /// * `bool` - true on success
972 fn k2h_set_debug_level_warning() -> bool;
973
974 /// # bool k2h_set_debug_level_message(void)
975 /// k2h_set_debug_level_message: Set debug level to message
976 ///
977 /// # Arguments
978 /// * `void` - no arguments
979 ///
980 /// # Returns
981 /// * `bool` - true on success
982 fn k2h_set_debug_level_message() -> bool;
983
984 /// # set value
985 /// # bool k2h_set_str_value_wa(k2h_h handle, const char* pkey, const char* pval, const char* pass, const time_t* expire)
986 /// k2h_set_str_value_wa: Set string value with optional password and expiration
987 ///
988 /// # Arguments
989 /// * `handle` - k2hash handle
990 /// * `pkey` - key string
991 /// * `pval` - value string
992 /// * `pass` - password string (nullable)
993 /// * `expire` - pointer to expiration time (nullable)
994 ///
995 /// # Returns
996 /// * `bool` - true on success
997 /// fn k2h_set_str_value_wa(
998 /// handle: u64,
999 /// pkey: *const c_char,
1000 /// pval: *const c_char,
1001 /// pass: *const c_char,
1002 /// expire: *const c_ulonglong,
1003 /// ) -> bool;
1004
1005 /// # bool k2h_transaction_param(k2h_h handle, bool enable, const char* transfile, const unsigned char* pprefix, size_t prefixlen, const unsigned char* pparam, size_t paramlen)
1006 /// k2h_transaction_param: Set transaction parameters
1007 ///
1008 /// # Arguments
1009 /// * `handle` - k2hash handle
1010 /// * `enable` - enable flag
1011 /// * `transfile` - transaction file path
1012 /// * `pprefix` - prefix pointer
1013 /// * `prefixlen` - prefix length
1014 /// * `pparam` - parameter pointer
1015 /// * `paramlen` - parameter length
1016 ///
1017 /// # Returns
1018 /// * `bool` - true on success
1019 // fn k2h_transaction_param(
1020 // handle: u64,
1021 // enable: bool,
1022 // transfile: *const c_char,
1023 // pprefix: *const u8,
1024 // prefixlen: usize,
1025 // pparam: *const u8,
1026 // paramlen: usize,
1027 // ) -> bool;
1028
1029 /// # bool k2h_transaction_param_we(k2h_h handle, bool enable, const char* transfile, const unsigned char* pprefix, size_t prefixlen, const unsigned char* pparam, size_t paramlen, const time_t* expire)
1030 /// k2h_transaction_param_we: Set transaction parameters with expiration
1031 ///
1032 /// # Arguments
1033 /// * `handle` - k2hash handle
1034 /// * `enable` - enable flag
1035 /// * `transfile` - transaction file path
1036 /// * `pprefix` - prefix pointer
1037 /// * `prefixlen` - prefix length
1038 /// * `pparam` - parameter pointer
1039 /// * `paramlen` - parameter length
1040 /// * `expire` - pointer to expiration time
1041 ///
1042 /// # Returns
1043 /// * `bool` - true on success
1044 fn k2h_transaction_param_we(
1045 handle: u64,
1046 enable: bool,
1047 transfile: *const c_char,
1048 pprefix: *const u8,
1049 prefixlen: usize,
1050 pparam: *const u8,
1051 paramlen: usize,
1052 expire: *const c_ulonglong,
1053 ) -> bool;
1054
1055 /// # bool k2h_set_transaction_thread_pool(int count)
1056 /// k2h_set_transaction_thread_pool: Set transaction thread pool count
1057 ///
1058 /// # Arguments
1059 /// * `count` - thread pool count
1060 ///
1061 /// # Returns
1062 /// * `bool` - true on success
1063 fn k2h_set_transaction_thread_pool(count: c_int) -> bool;
1064
1065}
1066
1067/// K2hashKey provides an iterator over the keys in the K2hash database.
1068///
1069/// # Examples
1070/// https://doc.rust-lang.org/std/iter/index.html#implementing-iterator
1071/// ```
1072/// use k2hash_rust::{K2hash, K2hashKey};
1073/// let db = K2hash::open_mem().expect("open_mem failed");
1074/// assert!(db.handle() != 0, "Database handle should not be zero");
1075/// let key = "hello";
1076/// let val = "world";
1077/// assert!(db.set(key, val).is_ok(), "Set operation failed");
1078/// assert_eq!(
1079/// db.get(key).expect("Get operation failed"),
1080/// Some("world".to_string()),
1081/// "Get operation returned unexpected value"
1082/// );
1083/// let mut k2hkey = K2hashKey::new(db.handle(), None).expect("K2hashKey creation failed"); // internally calls k2h_find_first.
1084/// assert_eq!(k2hkey.next(), Some("hello".to_string())); // internally calls k2h_find_next.
1085/// assert_eq!(k2hkey.next(), None); // internally calls k2h_find_next, but no more keys are available, so returns None.
1086/// ```
1087pub struct K2hashKey {
1088 k2h_handle: u64,
1089 key: Option<String>,
1090 handle: u64,
1091}
1092
1093impl K2hashKey {
1094 pub fn new(k2h_handle: u64, key: Option<String>) -> Result<Self, &'static str> {
1095 if k2h_handle == 0 {
1096 return Err("handle should not be 0");
1097 }
1098 let mut k2hkey = K2hashKey {
1099 k2h_handle,
1100 key,
1101 handle: 0,
1102 };
1103 if let Some(ref k) = k2hkey.key {
1104 // if key is provided, call k2h_find_first_str_subkey.
1105 let c_key = CString::new(k.as_str()).unwrap();
1106 k2hkey.handle = unsafe { k2h_find_first_str_subkey(k2hkey.k2h_handle, c_key.as_ptr()) };
1107 } else {
1108 k2hkey.handle = unsafe { k2h_find_first(k2hkey.k2h_handle) };
1109 }
1110 if k2hkey.handle == 0 {
1111 return Err("handle should not be K2H_INVALID_HANDLE");
1112 }
1113 Ok(k2hkey)
1114 }
1115}
1116
1117// fn k2h_find_get_key(findhandle: u64, ppkey: *mut *mut c_uchar, pkeylength: *mut usize) -> bool;
1118
1119// fn k2h_keyq_str_read_keyval_wp(
1120// keyqhandle: u64,
1121// ppkey: *mut *mut c_char,
1122// ppval: *mut *mut c_char,
1123// pos: c_int,
1124// encpass: *const c_char,
1125// ) -> bool;
1126
1127impl Iterator for K2hashKey {
1128 type Item = String;
1129
1130 fn next(&mut self) -> Option<Self::Item> {
1131 let mut ppkey: *mut c_char = ptr::null_mut();
1132 let mut pkeylength: usize = 0;
1133 let result = unsafe {
1134 k2h_find_get_key(
1135 self.handle,
1136 &mut ppkey as *mut *mut c_char as *mut *mut c_uchar,
1137 &mut pkeylength as *mut usize,
1138 )
1139 };
1140 if result && !ppkey.is_null() && pkeylength > 0 {
1141 let key = unsafe { CStr::from_ptr(ppkey).to_string_lossy().into_owned() };
1142 self.handle = unsafe { k2h_find_next(self.handle) };
1143 Some(key)
1144 } else {
1145 None
1146 }
1147 }
1148}
1149
1150/// K2hash struct provides a high-level interface for interacting with the K2hash database.
1151///
1152/// # Examples
1153///
1154/// ```
1155/// use k2hash_rust::K2hash;
1156/// let db = K2hash::open_mem().expect("open_mem failed");
1157/// assert!(db.handle() != 0, "Database handle should not be zero");
1158/// assert!(
1159/// db.set("test_key", "test_value").is_ok(),
1160/// "Set operation failed"
1161/// );
1162/// let value = db.get("test_key").expect("Get operation failed");
1163/// assert_eq!(
1164/// value,
1165/// Some("test_value".to_string()),
1166/// "Get operation returned unexpected value"
1167/// );
1168/// ```
1169pub struct K2hash {
1170 handle: u64,
1171}
1172
1173impl K2hash {
1174 /// Get the handle of the K2hash database.
1175 pub fn handle(&self) -> u64 {
1176 self.handle
1177 }
1178
1179 /// Set the debug level for the K2hash c-library.
1180 pub fn set_debug_level(level: DebugLevel) -> Result<(), &'static str> {
1181 let result = match level {
1182 DebugLevel::SILENT => unsafe { k2h_set_debug_level_silent() },
1183 DebugLevel::ERROR => unsafe { k2h_set_debug_level_error() },
1184 DebugLevel::WARNING => unsafe { k2h_set_debug_level_warning() },
1185 DebugLevel::MESSAGE => unsafe { k2h_set_debug_level_message() },
1186 };
1187 if result {
1188 Ok(())
1189 } else {
1190 Err("Failed to set debug level")
1191 }
1192 }
1193
1194 /// Open a key-value database in a file based.
1195 pub fn open(file: &str) -> Result<Self, &'static str> {
1196 let f = CString::new(file).unwrap();
1197 let handle = unsafe { k2h_open(f.as_ptr(), false, false, false, 8, 4, 1024, 512) };
1198 if handle == 0 {
1199 Err("k2h_open_mem failed")
1200 } else {
1201 Ok(K2hash { handle })
1202 }
1203 }
1204
1205 /// Open a memory-based database.
1206 pub fn open_mem() -> Result<Self, &'static str> {
1207 let handle = unsafe { k2h_open_mem(8, 4, 1024, 512) };
1208 if handle == 0 {
1209 Err("k2h_open_mem failed")
1210 } else {
1211 Ok(K2hash { handle })
1212 }
1213 }
1214
1215 /// Set a value with a key.
1216 pub fn set(&self, key: &str, value: &str) -> Result<(), &'static str> {
1217 return self.set_with_options(key, value, None, None);
1218 }
1219
1220 /// Set a value with a key with the options.
1221 pub fn set_with_options(
1222 &self,
1223 key: &str,
1224 value: &str,
1225 password: Option<&str>,
1226 expire_duration: Option<u64>,
1227 ) -> Result<(), &'static str> {
1228 let k = CString::new(key).unwrap();
1229 let v = CString::new(value).unwrap();
1230 if k.is_empty() || v.is_empty() {
1231 return Err("Key and value cannot be empty");
1232 }
1233 // Option<String> --as_ref()--> Option<&String> --CString::new()-> Option<CString>
1234 let pass = password.map(|p| CString::new(p).unwrap());
1235 let c_pass = pass.as_ref().map_or(ptr::null(), |p| p.as_ptr());
1236 let expire = expire_duration.map(|e| e as c_ulonglong);
1237 let c_expire = expire
1238 .as_ref()
1239 .map_or(ptr::null(), |e| e as *const c_ulonglong);
1240 let result =
1241 unsafe { k2h_set_str_value_wa(self.handle, k.as_ptr(), v.as_ptr(), c_pass, c_expire) };
1242 if result {
1243 Ok(())
1244 } else {
1245 Err("Failed to set value")
1246 }
1247 }
1248
1249 /// Get a value from a key.
1250 pub fn get(&self, key: &str) -> Result<Option<String>, &'static str> {
1251 return self.get_with_options(key, None);
1252 }
1253
1254 /// Get a value from a key with options.
1255 pub fn get_with_options(
1256 &self,
1257 key: &str,
1258 password: Option<&str>,
1259 ) -> Result<Option<String>, &'static str> {
1260 let k = CString::new(key).unwrap();
1261 if k.is_empty() {
1262 return Err("Key cannot be empty");
1263 }
1264 // Option<&str> --CString::new()-> Option<CString>
1265 let pass = password.map(|p| CString::new(p).unwrap());
1266 let c_pass = pass.as_ref().map_or(ptr::null(), |p| p.as_ptr());
1267 let ptr = unsafe { k2h_get_str_direct_value_wp(self.handle, k.as_ptr(), c_pass) };
1268
1269 if ptr.is_null() {
1270 Err("Failed to get result")
1271 } else {
1272 let cstr = unsafe { CStr::from_ptr(ptr) };
1273 Ok(Some(cstr.to_string_lossy().into_owned()))
1274 }
1275 }
1276
1277 /// Add an attribute plugin library.
1278 pub fn add_attribute_plugin_lib(&self, path: &str) -> Result<(), &'static str> {
1279 let path = CString::new(path).unwrap();
1280 if path.is_empty() {
1281 return Err("Path should be a some string");
1282 }
1283 let result = unsafe { k2h_add_attr_plugin_library(self.handle, path.as_ptr()) };
1284 if result {
1285 Ok(())
1286 } else {
1287 Err("add_attribute_plugin_lib returns error")
1288 }
1289 }
1290
1291 /// Add a decryption password.
1292 pub fn add_decryption_password(&self, password: &str) -> Result<(), &'static str> {
1293 let password = CString::new(password).unwrap();
1294 if password.is_empty() {
1295 return Err("Password should be a some string");
1296 }
1297 let result = unsafe { k2h_add_attr_crypt_pass(self.handle, password.as_ptr(), false) };
1298 if result {
1299 Ok(())
1300 } else {
1301 Err("add_decryption_password returns error")
1302 }
1303 }
1304
1305 /// Add a subkey to a key.
1306 pub fn add_subkey(&self, key: &str, subkey: &str, subval: &str) -> Result<(), &'static str> {
1307 return self.add_subkey_with_options(key, subkey, subval, None, None);
1308 }
1309
1310 /// Add a subkey to a key with options.
1311 pub fn add_subkey_with_options(
1312 &self,
1313 key: &str,
1314 subkey: &str,
1315 subval: &str,
1316 password: Option<String>,
1317 expire_duration: Option<u64>,
1318 ) -> Result<(), &'static str> {
1319 let k = CString::new(key).unwrap();
1320 let sk = CString::new(subkey).unwrap();
1321 let sv = CString::new(subval).unwrap();
1322 // Option<String> --as_ref()--> Option<&String> --CString::new()-> Option<CString>
1323 let pass = password.as_ref().map(|p| CString::new(p.as_str()).unwrap());
1324 let c_pass = pass.as_ref().map_or(ptr::null(), |p| p.as_ptr());
1325 let expire = expire_duration.map(|e| e as c_ulonglong);
1326 let c_expire = expire
1327 .as_ref()
1328 .map_or(ptr::null(), |e| e as *const c_ulonglong);
1329 let result = unsafe {
1330 k2h_add_subkey_wa(
1331 self.handle,
1332 k.as_bytes_with_nul().as_ptr(),
1333 k.as_bytes_with_nul().len(),
1334 sk.as_bytes_with_nul().as_ptr(),
1335 sk.as_bytes_with_nul().len(),
1336 sv.as_bytes_with_nul().as_ptr(),
1337 sv.as_bytes_with_nul().len(),
1338 c_pass,
1339 c_expire,
1340 )
1341 };
1342 if result {
1343 Ok(())
1344 } else {
1345 Err("k2h_add_subkey_wa returns error")
1346 }
1347 }
1348
1349 /// Start a transaction.
1350 pub fn begin_tx(&self, txfile: &str) -> Result<(), &'static str> {
1351 return self.begin_tx_with_options(txfile, None, None, None);
1352 }
1353
1354 /// Start a transaction with options.
1355 pub fn begin_tx_with_options(
1356 &self,
1357 txfile: &str,
1358 prefix: Option<String>,
1359 param: Option<String>,
1360 expire_duration: Option<u64>,
1361 ) -> Result<(), &'static str> {
1362 let txf = CString::new(txfile).unwrap();
1363
1364 // Option<String> --as_ref()--> Option<&String> --CString::new()-> Option<CString>
1365 let pre = prefix.as_ref().map(|p| CString::new(p.as_str()).unwrap());
1366 // Option<CString> -> const unsigned char*
1367 let c_pre = pre
1368 .as_ref()
1369 .map_or(ptr::null(), |p| p.as_bytes_with_nul().as_ptr());
1370 // Option<usize>
1371 let pre_length = pre.as_ref().map(|c| c.as_bytes_with_nul().len());
1372
1373 // Option<String> --as_ref()--> Option<&String> --CString::new()-> Option<CString>
1374 let par = param.as_ref().map(|p| CString::new(p.as_str()).unwrap());
1375 // Option<CString> -> const unsigned char*
1376 let c_par = par
1377 .as_ref()
1378 .map_or(ptr::null(), |p| p.as_bytes_with_nul().as_ptr());
1379 // Option<usize>
1380 let par_length = par.as_ref().map(|c| c.as_bytes_with_nul().len());
1381
1382 let expire = expire_duration.map(|e| e as c_ulonglong);
1383 let c_expire = expire
1384 .as_ref()
1385 .map_or(ptr::null(), |e| e as *const c_ulonglong);
1386 let result = unsafe {
1387 k2h_transaction_param_we(
1388 self.handle,
1389 true,
1390 txf.as_ptr(),
1391 c_pre,
1392 pre_length.unwrap_or(0), // Option<usize> -> usize
1393 c_par,
1394 par_length.unwrap_or(0), // Option<usize> -> usize
1395 c_expire,
1396 )
1397 };
1398 if result {
1399 Ok(())
1400 } else {
1401 Err("begin_tx returns error")
1402 }
1403 }
1404
1405 /// Create a new K2hash database in a file.
1406 pub fn create(path: &str) -> Result<(), &'static str> {
1407 return K2hash::create_with_options(path, 8, 4, 1024, 512);
1408 }
1409
1410 /// Create a new K2hash database in a file with options.
1411 pub fn create_with_options(
1412 path: &str,
1413 maskbit: i32,
1414 cmaskbit: i32,
1415 maxelementcnt: i32,
1416 pagesize: usize,
1417 ) -> Result<(), &'static str> {
1418 let p = CString::new(path).unwrap();
1419 if p.is_empty() {
1420 return Err("path cannot be empty");
1421 }
1422 let maskbit_len: i32 = maskbit;
1423 let cmaskbit_len: i32 = cmaskbit;
1424 let maxelementcnt_len: i32 = maxelementcnt;
1425 let pagesize_len: usize = pagesize;
1426
1427 let result = unsafe {
1428 k2h_create(
1429 p.as_ptr(),
1430 maskbit_len,
1431 cmaskbit_len,
1432 maxelementcnt_len,
1433 pagesize_len,
1434 )
1435 };
1436 if result {
1437 Ok(())
1438 } else {
1439 Err("k2h_create returns error")
1440 }
1441 }
1442
1443 /// Dump the database to a file.
1444 pub fn dump_to_file(&self, path: &str) -> Result<(), &'static str> {
1445 return self.dump_to_file_with_options(path, true);
1446 }
1447
1448 /// Dump the database to a file with options.
1449 pub fn dump_to_file_with_options(
1450 &self,
1451 path: &str,
1452 is_skip_error: bool,
1453 ) -> Result<(), &'static str> {
1454 let p = CString::new(path).unwrap();
1455 if p.is_empty() {
1456 return Err("path cannot be empty");
1457 }
1458 let i: bool = is_skip_error;
1459
1460 let result = unsafe { k2h_put_archive(self.handle, p.as_ptr(), i) };
1461 if result {
1462 Ok(())
1463 } else {
1464 Err("k2h_create returns error")
1465 }
1466 }
1467
1468 /// Enable encryption.
1469 pub fn enable_encryption(&self, enable: bool) -> Result<(), &'static str> {
1470 let is_defenc = enable;
1471 let result = unsafe {
1472 k2h_set_common_attr(
1473 self.handle,
1474 ptr::null(), // is_mtime
1475 &is_defenc as *const bool, // is_defenc
1476 ptr::null(), // passfile
1477 ptr::null(), // is_history
1478 ptr::null(), // expire
1479 )
1480 };
1481 if result {
1482 Ok(())
1483 } else {
1484 Err("k2h_create returns error")
1485 }
1486 }
1487
1488 /// Enable history.
1489 pub fn enable_history(&self, enable: bool) -> Result<(), &'static str> {
1490 let is_history = enable;
1491 let result = unsafe {
1492 k2h_set_common_attr(
1493 self.handle,
1494 ptr::null(), // is_mtime
1495 ptr::null(), // is_defenc
1496 ptr::null(), // passfile
1497 &is_history as *const bool, // is_history
1498 ptr::null(), // expire
1499 )
1500 };
1501 if result {
1502 Ok(())
1503 } else {
1504 Err("k2h_create returns error")
1505 }
1506 }
1507
1508 /// Enable mtime.
1509 pub fn enable_mtime(&self, enable: bool) -> Result<(), &'static str> {
1510 let is_mtime = enable;
1511 let result = unsafe {
1512 k2h_set_common_attr(
1513 self.handle,
1514 &is_mtime as *const bool, // is_mtime
1515 ptr::null(), // is_defenc
1516 ptr::null(), // passfile
1517 ptr::null(), // is_history
1518 ptr::null(), // expire
1519 )
1520 };
1521 if result {
1522 Ok(())
1523 } else {
1524 Err("k2h_create returns error")
1525 }
1526 }
1527
1528 /// Get attributes of a key.
1529 pub fn get_attributes(
1530 &self,
1531 key: &str,
1532 ) -> Result<Option<HashMap<String, String>>, &'static str> {
1533 let k = CString::new(key).unwrap();
1534 if k.is_empty() {
1535 return Err("key should be passed");
1536 }
1537 let k_length = k.as_bytes_with_nul().len();
1538 let mut pattrspckcnt: c_int = 0; // mutable c_int
1539 // let mut pskeypckcnt: c_int = 0;
1540 let result = unsafe {
1541 k2h_get_direct_attrs(
1542 self.handle,
1543 k.as_bytes_with_nul().as_ptr(), // byte
1544 k_length,
1545 &mut pattrspckcnt, // mutable pointer to c_int
1546 )
1547 };
1548 println!("pattrspckcnt: {}", pattrspckcnt);
1549 if !result.is_null() && pattrspckcnt > 0 {
1550 let mut attrs: HashMap<String, String> = HashMap::new();
1551 for i in 0..pattrspckcnt {
1552 // Assuming result is a pointer to an array of AttrPack structures
1553 let attr_pack: &K2hAttrPack =
1554 unsafe { &*(result as *const K2hAttrPack).add(i as usize) };
1555 let key = unsafe {
1556 CStr::from_ptr(attr_pack.pkey as *const c_char)
1557 .to_string_lossy()
1558 .into_owned()
1559 };
1560 let val = unsafe {
1561 CStr::from_ptr(attr_pack.pval as *const c_char)
1562 .to_string_lossy()
1563 .into_owned()
1564 };
1565 // println!("key: {}", key);
1566 let keylength = unsafe { attr_pack.keylength as usize };
1567 let vallength = unsafe { attr_pack.vallength as usize };
1568 println!("keylength: {}", keylength);
1569 println!("vallength: {}", vallength);
1570 attrs.insert(key, val);
1571 }
1572 // Return the attributes as a Result
1573 Ok(Some(attrs))
1574 } else {
1575 Err("k2h_get_direct_attrs returns error")
1576 }
1577 }
1578
1579 // # get subkeys API
1580 // # PK2HKEYPCK k2h_get_direct_subkeys(k2h_h handle, const unsigned char* pkey,
1581 // # size_t keylength, int* pskeypckcnt)
1582 // ret.k2h_get_direct_subkeys.argtypes = [c_uint64, c_char_p, c_size_t, POINTER(c_int)]
1583 // ret.k2h_get_direct_subkeys.restype = POINTER(KeyPack)
1584
1585 /// Get subkeys of a key.
1586 pub fn get_subkeys(&self, key: &str) -> Result<Option<Vec<String>>, &'static str> {
1587 let k = CString::new(key).unwrap();
1588 if k.is_empty() {
1589 return Err("key should be passed");
1590 }
1591 let k_length = k.as_bytes_with_nul().len();
1592 let mut pskeypckcnt: c_int = 0;
1593 let result = unsafe {
1594 k2h_get_direct_subkeys(
1595 self.handle,
1596 k.as_bytes_with_nul().as_ptr(),
1597 k_length,
1598 &mut pskeypckcnt,
1599 )
1600 };
1601 if !result.is_null() && pskeypckcnt > 0 {
1602 // println!("pskeypckcnt: {}", pskeypckcnt);
1603 let mut keys: Vec<String> = Vec::new();
1604 for i in 0..pskeypckcnt {
1605 // Assuming result is a pointer to an array of KeyPack structures
1606 let key_pack: &K2hKeyPack =
1607 unsafe { &*(result as *const K2hKeyPack).add(i as usize) };
1608 let key = unsafe {
1609 CStr::from_ptr(key_pack.pkey as *const c_char)
1610 .to_string_lossy()
1611 .into_owned()
1612 };
1613 // println!("key: {}", key);
1614 keys.push(key);
1615 }
1616 // Return the keys as a Result
1617 Ok(Some(keys))
1618 } else {
1619 Err("k2h_get_direct_subkeys returns error")
1620 }
1621 }
1622
1623 /// Get transaction file descriptor.
1624 pub fn get_tx_file_fd(&self) -> Result<i32, &'static str> {
1625 // fn k2h_get_transaction_archive_fd(handle: u64) -> c_int;
1626 let fd = unsafe { k2h_get_transaction_archive_fd(self.handle) };
1627 if fd < 0 {
1628 Err("Failed to get result")
1629 } else {
1630 Ok(fd)
1631 }
1632 }
1633
1634 /// Get transaction pool size.
1635 pub fn get_tx_pool_size() -> Result<i32, &'static str> {
1636 let pool_size = unsafe { k2h_get_transaction_thread_pool() };
1637 if pool_size < 0 {
1638 Err("Failed to get result")
1639 } else {
1640 Ok(pool_size)
1641 }
1642 }
1643
1644 /// Load a K2hash database from a file.
1645 pub fn load_from_file(
1646 &self,
1647 path: &str,
1648 is_skip_error: Option<bool>,
1649 ) -> Result<(), &'static str> {
1650 let p = CString::new(path).unwrap();
1651 let skip_error = is_skip_error.unwrap_or(true);
1652 if p.is_empty() {
1653 return Err("Failed to get path");
1654 }
1655 let result = unsafe { k2h_load_archive(self.handle, p.as_ptr(), skip_error) };
1656 if result {
1657 Ok(())
1658 } else {
1659 Err("k2h_load_archive returns error")
1660 }
1661 }
1662
1663 /// Print attribute plugins of the K2hash database.
1664 pub fn print_attribute_plugins(&self) -> Result<(), &'static str> {
1665 let result = unsafe { k2h_print_attr_version(self.handle, core::ptr::null_mut()) };
1666 if result {
1667 Ok(())
1668 } else {
1669 Err("k2h_print_attr_version returns error")
1670 }
1671 }
1672
1673 /// Print attribute information of k2hash database.
1674 pub fn print_attributes(&self) -> Result<(), &'static str> {
1675 let result = unsafe { k2h_print_attr_information(self.handle, core::ptr::null_mut()) };
1676 if result {
1677 Ok(())
1678 } else {
1679 Err("k2h_print_attr_information returns error")
1680 }
1681 }
1682
1683 /// Print attribute information of k2hash database.
1684 pub fn print_data_stats(&self) -> Result<(), &'static str> {
1685 let result = unsafe { k2h_print_state(self.handle, core::ptr::null_mut()) };
1686 if result {
1687 Ok(())
1688 } else {
1689 Err("k2h_print_state returns error")
1690 }
1691 }
1692
1693 /// Print table information of k2hash database.
1694 pub fn print_table_stats(&self, dump_level: DumpLevel) -> Result<(), &'static str> {
1695 let dl = dump_level;
1696 if dl == DumpLevel::HEADER {
1697 let result = unsafe { k2h_dump_head(self.handle, core::ptr::null_mut()) };
1698 if result {
1699 Ok(())
1700 } else {
1701 Err("k2h_dump_head returns error")
1702 }
1703 } else if dl == DumpLevel::HASHTABLE {
1704 let result = unsafe { k2h_dump_keytable(self.handle, core::ptr::null_mut()) };
1705 if result {
1706 Ok(())
1707 } else {
1708 Err("k2h_dump_head returns error")
1709 }
1710 } else if dl == DumpLevel::SUBHASHTABLE {
1711 let result = unsafe { k2h_dump_full_keytable(self.handle, core::ptr::null_mut()) };
1712 if result {
1713 Ok(())
1714 } else {
1715 Err("k2h_dump_head returns error")
1716 }
1717 } else if dl == DumpLevel::ELEMENT {
1718 let result = unsafe { k2h_dump_elementtable(self.handle, core::ptr::null_mut()) };
1719 if result {
1720 Ok(())
1721 } else {
1722 Err("k2h_dump_head returns error")
1723 }
1724 } else if dl == DumpLevel::PAGE {
1725 let result = unsafe { k2h_dump_full(self.handle, core::ptr::null_mut()) };
1726 if result {
1727 Ok(())
1728 } else {
1729 Err("k2h_dump_head returns error")
1730 }
1731 } else {
1732 return Err("k2h_dump_head returns error");
1733 }
1734 }
1735
1736 /// Remove a key from the K2hash database.
1737 pub fn remove(&self, key: &str) -> Result<(), &'static str> {
1738 return self.remove_with_options(key, false);
1739 }
1740
1741 /// Remove a key from the K2hash database with options.
1742 pub fn remove_with_options(
1743 &self,
1744 key: &str,
1745 remove_all_subkeys: bool,
1746 ) -> Result<(), &'static str> {
1747 let k = CString::new(key).unwrap();
1748 let b_remove_all_subkeys = remove_all_subkeys;
1749 if k.is_empty() {
1750 return Err("key should be passed");
1751 }
1752 if b_remove_all_subkeys {
1753 let result = unsafe { k2h_remove_str_all(self.handle, k.as_ptr()) };
1754 if result {
1755 Ok(())
1756 } else {
1757 Err("Failed to h.k2h_remove_str_all")
1758 }
1759 } else {
1760 let result = unsafe { k2h_remove_str(self.handle, k.as_ptr()) };
1761 if result {
1762 Ok(())
1763 } else {
1764 Err("Failed to set value")
1765 }
1766 }
1767 }
1768
1769 /// Remove a subkey of a key from the K2hash database.
1770 pub fn remove_subkeys(&self, key: &str, subkeys: Vec<&str>) -> Result<(), &'static str> {
1771 let k = CString::new(key).unwrap();
1772 if k.is_empty() {
1773 return Err("key should be passed");
1774 }
1775 let v_subkeys_iter = subkeys.iter();
1776 for skey in v_subkeys_iter {
1777 let sk = CString::new(*skey).unwrap();
1778 let result = unsafe { k2h_remove_str_subkey(self.handle, k.as_ptr(), sk.as_ptr()) };
1779 if result == false {
1780 return Err("Failed to h.k2h_remove_str_all");
1781 }
1782 }
1783 Ok(())
1784 }
1785
1786 /// Rename a old key with a new key.
1787 pub fn rename(&self, oldkey: &str, newkey: &str) -> Result<(), &'static str> {
1788 let okey = CString::new(oldkey).unwrap();
1789 if okey.is_empty() {
1790 return Err("oldkey should be passed");
1791 }
1792 let nkey = CString::new(newkey).unwrap();
1793 if nkey.is_empty() {
1794 return Err("newkey should be passed");
1795 }
1796 let result = unsafe { k2h_rename_str(self.handle, okey.as_ptr(), nkey.as_ptr()) };
1797 if result {
1798 Ok(())
1799 } else {
1800 Err("Failed to h.k2h_rename")
1801 }
1802 }
1803
1804 /// Set attribute of a key in the K2hash database.
1805 pub fn set_attribute(
1806 &self,
1807 key: &str,
1808 attr_name: &str,
1809 attr_val: &str,
1810 ) -> Result<(), &'static str> {
1811 let key = CString::new(key).unwrap();
1812 if key.as_bytes().is_empty() {
1813 return Err("key should be passed");
1814 }
1815 let k_length = key.as_bytes_with_nul().len();
1816
1817 let attr_name = CString::new(attr_name).unwrap();
1818 if attr_name.as_bytes().is_empty() {
1819 return Err("attr_name should be passed");
1820 }
1821 let name_length = attr_name.as_bytes_with_nul().len();
1822
1823 let attr_val = CString::new(attr_val).unwrap();
1824 if attr_val.as_bytes().is_empty() {
1825 return Err("attr_val should be passed");
1826 }
1827 let val_length = attr_val.as_bytes_with_nul().len();
1828
1829 let result = unsafe {
1830 k2h_add_attr(
1831 self.handle,
1832 key.as_bytes_with_nul().as_ptr(),
1833 k_length,
1834 attr_name.as_bytes_with_nul().as_ptr(),
1835 name_length,
1836 attr_val.as_bytes_with_nul().as_ptr(),
1837 val_length,
1838 )
1839 };
1840 if result {
1841 Ok(())
1842 } else {
1843 Err("Failed to h.k2h_set_attribute")
1844 }
1845 }
1846
1847 /// Set a default encryption password.
1848 pub fn set_default_encryption_password(&self, password: &str) -> Result<(), &'static str> {
1849 let p = CString::new(password).unwrap();
1850 if p.is_empty() {
1851 return Err("password should be passed");
1852 }
1853 let result = unsafe { k2h_add_attr_crypt_pass(self.handle, p.as_ptr(), true) };
1854 if result {
1855 Ok(())
1856 } else {
1857 Err("Failed to set value")
1858 }
1859 }
1860
1861 /// Set subkeys to a key in the K2hash database.
1862 pub fn set_subkeys(&self, key: &str, subkeys: Vec<(&str, &str)>) -> Result<(), &'static str> {
1863 return self.set_subkeys_with_options(key, subkeys, None, None);
1864 }
1865
1866 /// Set subkeys to a key in the K2hash database with options.
1867 pub fn set_subkeys_with_options(
1868 &self,
1869 key: &str,
1870 subkeys: Vec<(&str, &str)>,
1871 password: Option<String>,
1872 expire_duration: Option<u64>,
1873 ) -> Result<(), &'static str> {
1874 let k = CString::new(key).unwrap();
1875 if k.is_empty() {
1876 return Err("key should be passed");
1877 }
1878 let k_length = k.as_bytes_with_nul().len();
1879 // Option<String> --as_ref()--> Option<&String> --CString::new()-> Option<CString>
1880 let pass = password.as_ref().map(|p| CString::new(p.as_str()).unwrap());
1881 // Option<CString> -> const unsigned char*
1882 let c_pass = pass.as_ref().map_or(ptr::null(), |p| p.as_ptr());
1883 // Option<usize>
1884 let expire = expire_duration.map(|e| e as c_ulonglong);
1885 let c_expire = expire
1886 .as_ref()
1887 .map_or(ptr::null(), |e| e as *const c_ulonglong);
1888
1889 let v_subkeys_iter = subkeys.iter();
1890 for (subk, subv) in v_subkeys_iter {
1891 let sk = CString::new(*subk).unwrap();
1892 let sv = CString::new(*subv).unwrap();
1893 if sk.as_bytes().is_empty() {
1894 return Err("subkey's key should be passed");
1895 }
1896 let sk_length = sk.as_bytes_with_nul().len();
1897 if sv.as_bytes().is_empty() {
1898 return Err("subkey's val should be passed");
1899 }
1900 let sv_length = sv.as_bytes_with_nul().len();
1901 let result = unsafe {
1902 k2h_add_subkey_wa(
1903 self.handle,
1904 k.as_bytes_with_nul().as_ptr(),
1905 k_length,
1906 sk.as_bytes_with_nul().as_ptr(),
1907 sk_length,
1908 sv.as_bytes_with_nul().as_ptr(),
1909 sv_length,
1910 c_pass,
1911 c_expire,
1912 )
1913 };
1914 if result == false {
1915 return Err("Failed to h.k2h_remove_str_all");
1916 }
1917 }
1918 Ok(())
1919 }
1920
1921 /// Stop a transaction.
1922 pub fn stop_tx(&self) -> Result<(), &'static str> {
1923 let result = unsafe { k2h_disable_transaction(self.handle) };
1924 if result {
1925 Ok(())
1926 } else {
1927 Err("k2h_disable_transaction returns error")
1928 }
1929 }
1930
1931 /// Print the k2hash C-library version.
1932 pub fn version() -> Result<(), &'static str> {
1933 unsafe { k2h_print_version(core::ptr::null_mut()) };
1934 Ok(())
1935 }
1936
1937 /// Set transaction pool size.
1938 pub fn set_tx_pool_size(size: i32) -> Result<(), &'static str> {
1939 if size < 0 {
1940 return Err("size should be 0 or positive");
1941 }
1942 let result = unsafe { k2h_set_transaction_thread_pool(size) };
1943 if result {
1944 Ok(())
1945 } else {
1946 Err("Failed to set value")
1947 }
1948 }
1949}
1950
1951impl Drop for K2hash {
1952 fn drop(&mut self) {
1953 unsafe {
1954 k2h_close(self.handle);
1955 }
1956 }
1957}
1958
1959/// Base struct of Queue and KeyQueue struct.
1960pub struct BaseQueue {
1961 k2h: u64,
1962 fifo: bool,
1963 prefix: Option<String>,
1964 password: Option<String>,
1965 expire_duration: Option<u64>,
1966 handle: u64,
1967}
1968impl BaseQueue {
1969 /// Create a new BaseQueue.
1970 pub fn new(
1971 k2h: u64,
1972 fifo: bool,
1973 prefix: Option<String>,
1974 password: Option<String>,
1975 expire_duration: Option<u64>,
1976 ) -> Self {
1977 BaseQueue {
1978 k2h,
1979 fifo,
1980 prefix,
1981 password,
1982 expire_duration,
1983 handle: 0,
1984 }
1985 }
1986
1987 /// Get the handle of the BaseQueue.
1988 pub fn handle(&self) -> u64 {
1989 self.handle
1990 }
1991}
1992
1993/// Queue provides FIFO (first-in, first-out) functionality using k2hash database.
1994///
1995/// # Examples
1996///
1997/// ```
1998/// use k2hash_rust::{K2hash, Queue};
1999/// let db = K2hash::open_mem().expect("open_mem failed");
2000/// let handle = db.handle();
2001/// assert!(handle != 0, "Handle should not be zero");
2002/// let q = Queue::new(db.handle(), true, None, None, None).expect("Queue creation failed");
2003/// // check if queue is not null
2004/// assert!(q.handle() != 0, "Queue handle should not be zero");
2005/// // converts &str(string slice) to String
2006/// let value = "hello".to_string();
2007/// assert!(q.put(&value).is_ok(), "Push operation failed");
2008/// // check if get returns the correct value
2009/// if let Some(value) = q.get() {
2010/// assert_eq!(value, "hello", "Get operation returned unexpected value");
2011/// } else {
2012/// panic!("Get operation failed or returned None");
2013/// }
2014/// ```
2015pub struct Queue {
2016 base: BaseQueue,
2017}
2018/// KeyQueue provides FIFO (first-in, first-out) functionality using k2hash database.
2019///
2020/// # Examples
2021///
2022/// ```
2023/// use k2hash_rust::{K2hash, KeyQueue};
2024/// let db = K2hash::open_mem().expect("open_mem failed");
2025/// let handle = db.handle();
2026/// assert!(handle != 0, "Handle should not be zero");
2027/// let q = KeyQueue::new(db.handle(), true, None, None, None).expect("KeyQueue creation failed");
2028/// // check if KeyQueue is not null
2029/// assert!(q.handle() != 0, "KeyQueue handle should not be zero");
2030/// // converts &str(string slice) to String
2031/// let key = "hello";
2032/// let value = "world";
2033/// assert!(q.put(key, value).is_ok(), "Push operation failed");
2034/// // check if get returns the correct value
2035/// if let Some((key, value)) = q.get() {
2036/// assert_eq!(key, "hello", "Get operation returned unexpected value");
2037/// assert_eq!(value, "world", "Get operation returned unexpected value");
2038/// } else {
2039/// panic!("Get operation failed or returned None");
2040/// }
2041/// ```
2042pub struct KeyQueue {
2043 base: BaseQueue,
2044}
2045impl Queue {
2046 /// Create a new Queue.
2047 pub fn new(
2048 k2h: u64,
2049 fifo: bool,
2050 prefix: Option<String>,
2051 password: Option<String>,
2052 expire_duration: Option<u64>,
2053 ) -> Result<Self, &'static str> {
2054 let mut base = BaseQueue::new(k2h, fifo, prefix, password, expire_duration);
2055 let c_prefix = base
2056 .prefix
2057 .as_ref()
2058 .map(|p| CString::new(p.as_str()).unwrap());
2059 let ptr = c_prefix.as_ref().map_or(ptr::null(), |c| c.as_ptr());
2060 base.handle = unsafe { k2h_q_handle_str_prefix(base.k2h, base.fifo, ptr) };
2061 if base.handle == 0 {
2062 Err("Queue instance failed")
2063 } else {
2064 Ok(Queue { base })
2065 }
2066 }
2067
2068 /// Get a handle to the Queue.
2069 pub fn handle(&self) -> u64 {
2070 self.base.handle
2071 }
2072
2073 /// Put a value into the Queue.
2074 pub fn put(&self, value: &str) -> Result<(), &'static str> {
2075 let c_val = CString::new(value).unwrap();
2076 let c_pass = self
2077 .base
2078 .password
2079 .as_ref()
2080 .map(|p| CString::new(p.as_str()).unwrap());
2081 let c_pattrspck = ptr::null();
2082 let c_attrspckcnt = 0;
2083 let expire = self.base.expire_duration.map(|e| e as c_ulonglong);
2084 let result = unsafe {
2085 k2h_q_str_push_wa(
2086 self.base.handle,
2087 c_val.as_ptr(),
2088 c_pattrspck,
2089 c_attrspckcnt,
2090 c_pass.as_ref().map_or(ptr::null(), |p| p.as_ptr()),
2091 expire
2092 .as_ref()
2093 .map_or(ptr::null(), |e| e as *const c_ulonglong),
2094 )
2095 };
2096 if result {
2097 Ok(())
2098 } else {
2099 Err("Failed to set value")
2100 }
2101 }
2102
2103 /// Get a value from the Queue.
2104 pub fn get(&self) -> Option<String> {
2105 let mut val_ptr: *mut c_char = ptr::null_mut();
2106 let c_pass = self
2107 .base
2108 .password
2109 .as_ref()
2110 .map(|p| CString::new(p.as_str()).unwrap());
2111 let result = unsafe {
2112 k2h_q_str_pop_wp(
2113 self.base.handle,
2114 &mut val_ptr,
2115 c_pass.as_ref().map_or(ptr::null(), |p| p.as_ptr()),
2116 )
2117 };
2118 if result && !val_ptr.is_null() {
2119 let cstr = unsafe { CStr::from_ptr(val_ptr) };
2120 Some(cstr.to_string_lossy().into_owned())
2121 } else {
2122 None
2123 }
2124 }
2125
2126 /// Get the size of the Queue.
2127 pub fn qsize(&self) -> usize {
2128 unsafe { k2h_q_count(self.base.handle) as usize }
2129 }
2130
2131 /// Get an element from the Queue at a specific position.
2132 pub fn element(&self, position: usize) -> Option<String> {
2133 let mut ppdata: *mut c_char = ptr::null_mut();
2134 let c_pass = self
2135 .base
2136 .password
2137 .as_ref()
2138 .map(|p| CString::new(p.as_str()).unwrap());
2139 let result = unsafe {
2140 k2h_q_str_read_wp(
2141 self.base.handle,
2142 &mut ppdata,
2143 position as c_int,
2144 c_pass.as_ref().map_or(ptr::null(), |p| p.as_ptr()),
2145 )
2146 };
2147 if result && !ppdata.is_null() {
2148 let cstr = unsafe { CStr::from_ptr(ppdata) };
2149 Some(cstr.to_string_lossy().into_owned())
2150 } else {
2151 None
2152 }
2153 }
2154
2155 /// Check if the Queue is empty.
2156 pub fn empty(&self) -> bool {
2157 unsafe { k2h_q_empty(self.base.handle) }
2158 }
2159
2160 /// Print the objects in the Queue.
2161 pub fn print(&self) -> Result<(), &'static str> {
2162 let result = unsafe { k2h_q_dump(self.base.handle, ptr::null_mut()) };
2163 if result {
2164 Ok(())
2165 } else {
2166 Err("k2h_q_dump returns error")
2167 }
2168 }
2169
2170 /// Remove the objects from the Queue.
2171 pub fn remove(&self, count: usize) -> Result<Vec<String>, &'static str> {
2172 if count == 0 {
2173 return Ok(Vec::new());
2174 }
2175 let mut vals = Vec::new();
2176 for _ in 0..count {
2177 let mut val_ptr: *mut c_char = ptr::null_mut();
2178 let c_pass = self
2179 .base
2180 .password
2181 .as_ref()
2182 .map(|p| CString::new(p.as_str()).unwrap());
2183 let result = unsafe {
2184 k2h_q_str_pop_wp(
2185 self.base.handle,
2186 &mut val_ptr,
2187 c_pass.as_ref().map_or(ptr::null(), |p| p.as_ptr()),
2188 )
2189 };
2190 if result && !val_ptr.is_null() {
2191 let cstr = unsafe { CStr::from_ptr(val_ptr) };
2192 vals.push(cstr.to_string_lossy().into_owned());
2193 } else {
2194 break; // Stop if no more elements are available
2195 }
2196 }
2197 Ok(vals)
2198 }
2199
2200 /// Remove the objects from the Queue.
2201 pub fn clear(&self) -> bool {
2202 let count = self.qsize() as c_int;
2203 if count > 0 {
2204 unsafe { k2h_q_remove(self.base.handle, count) }
2205 } else {
2206 true
2207 }
2208 }
2209
2210 /// Close the Queue.
2211 pub fn close(&self) -> bool {
2212 unsafe { k2h_q_free(self.base.handle) }
2213 }
2214}
2215
2216/// QueueBuilder provides a builder pattern for creating Queue instances.
2217///
2218/// # Examples
2219///
2220/// ```
2221/// use k2hash_rust::{K2hash, QueueBuilder};
2222/// let db = K2hash::open_mem().expect("open_mem failed");
2223/// let handle = db.handle();
2224/// assert!(handle != 0, "Handle should not be zero");
2225/// let fifo = true; // or false, depending on your needs
2226/// let prefix = "test_prefix".to_string();
2227/// let password = Some("your_password".to_string());
2228/// let expire_duration = Some(60); // for 60 seconds expiration
2229/// // Create the queue using QueueBuilder
2230/// let qb1 = QueueBuilder::new(db.handle())
2231/// .fifo(fifo)
2232/// .prefix(prefix) // Optional prefix
2233/// .password(password.expect("Error")) // Optional password
2234/// .expire_duration(expire_duration.expect("Error")) // Optional expiration duration
2235/// .build()
2236/// .expect("Queue creation failed");
2237/// // check if queue is not null
2238/// assert!(qb1.handle() != 0, "Queue handle should not be zero");
2239/// ```
2240pub struct QueueBuilder {
2241 k2h: u64,
2242 fifo: bool,
2243 prefix: Option<String>,
2244 password: Option<String>,
2245 expire_duration: Option<u64>,
2246}
2247
2248impl QueueBuilder {
2249 /// Create a new QueueBuilder instance.
2250 pub fn new(k2h: u64) -> Self {
2251 QueueBuilder {
2252 k2h,
2253 fifo: true,
2254 prefix: None,
2255 password: None,
2256 expire_duration: None,
2257 }
2258 }
2259
2260 /// Set the FIFO flag for the Queue.
2261 pub fn fifo(mut self, fifo: bool) -> Self {
2262 self.fifo = fifo;
2263 self
2264 }
2265 /// Set the prefix of the Queue.
2266 pub fn prefix(mut self, prefix: String) -> Self {
2267 self.prefix = Some(prefix);
2268 self
2269 }
2270 /// Set the password of the Queue.
2271 pub fn password(mut self, password: String) -> Self {
2272 self.password = Some(password);
2273 self
2274 }
2275 /// Set the expiration duration of the Queue.
2276 pub fn expire_duration(mut self, expire_duration: u64) -> Self {
2277 self.expire_duration = Some(expire_duration);
2278 self
2279 }
2280 /// Build the Queue.
2281 pub fn build(self) -> Result<Queue, &'static str> {
2282 Queue::new(
2283 self.k2h,
2284 self.fifo,
2285 self.prefix,
2286 self.password,
2287 self.expire_duration,
2288 )
2289 }
2290}
2291
2292impl KeyQueue {
2293 /// Create a new KeyQueue instance.
2294 pub fn new(
2295 k2h: u64,
2296 fifo: bool,
2297 prefix: Option<String>,
2298 password: Option<String>,
2299 expire_duration: Option<u64>,
2300 ) -> Result<Self, &'static str> {
2301 let mut base = BaseQueue::new(k2h, fifo, prefix, password, expire_duration);
2302 let c_prefix = base
2303 .prefix
2304 .as_ref()
2305 .map(|p| CString::new(p.as_str()).unwrap());
2306 let ptr = c_prefix.as_ref().map_or(ptr::null(), |c| c.as_ptr());
2307 base.handle = unsafe { k2h_keyq_handle_str_prefix(base.k2h, base.fifo, ptr) };
2308 if base.handle == 0 {
2309 Err("Failed to create KeyQueue handle")
2310 } else {
2311 Ok(KeyQueue { base })
2312 }
2313 }
2314
2315 /// Get the handle of the KeyQueue.
2316 pub fn handle(&self) -> u64 {
2317 self.base.handle
2318 }
2319
2320 /// Put a key-value pair into the KeyQueue.
2321 pub fn put(&self, key: &str, value: &str) -> Result<(), &'static str> {
2322 let c_key = CString::new(key).unwrap();
2323 let c_val = CString::new(value).unwrap();
2324 let c_pass = self
2325 .base
2326 .password
2327 .as_ref()
2328 .map(|p| CString::new(p.as_str()).unwrap());
2329 let expire = self.base.expire_duration.map(|e| e as c_ulonglong);
2330 let result = unsafe {
2331 k2h_keyq_str_push_keyval_wa(
2332 self.base.handle,
2333 c_key.as_ptr(),
2334 c_val.as_ptr(),
2335 c_pass.as_ref().map_or(ptr::null(), |p| p.as_ptr()),
2336 expire
2337 .as_ref()
2338 .map_or(ptr::null(), |e| e as *const c_ulonglong),
2339 )
2340 };
2341 if result {
2342 Ok(())
2343 } else {
2344 Err("Failed to set value")
2345 }
2346 }
2347
2348 /// Get a key-value pair from the KeyQueue.
2349 pub fn get(&self) -> Option<(String, String)> {
2350 let mut key_ptr: *mut c_char = ptr::null_mut();
2351 let mut val_ptr: *mut c_char = ptr::null_mut();
2352 let c_pass = self
2353 .base
2354 .password
2355 .as_ref()
2356 .map(|p| CString::new(p.as_str()).unwrap());
2357 let result = unsafe {
2358 k2h_keyq_str_pop_keyval_wp(
2359 self.base.handle,
2360 &mut key_ptr,
2361 &mut val_ptr,
2362 c_pass.as_ref().map_or(ptr::null(), |p| p.as_ptr()),
2363 )
2364 };
2365 if result && !key_ptr.is_null() && !val_ptr.is_null() {
2366 let key = unsafe { CStr::from_ptr(key_ptr).to_string_lossy().into_owned() };
2367 let val = unsafe { CStr::from_ptr(val_ptr).to_string_lossy().into_owned() };
2368 Some((key, val))
2369 } else {
2370 None
2371 }
2372 }
2373
2374 /// Get the size of the KeyQueue.
2375 pub fn qsize(&self) -> usize {
2376 unsafe { k2h_keyq_count(self.base.handle) as usize }
2377 }
2378
2379 /// Get element from queue in read-only access.
2380 pub fn element(&self, position: usize) -> Option<(String, String)> {
2381 if position < 0 {
2382 return None; // Position should be non-negative
2383 }
2384 let mut ppkey: *mut c_char = ptr::null_mut();
2385 let mut ppval: *mut c_char = ptr::null_mut();
2386 let c_pass = self
2387 .base
2388 .password
2389 .as_ref()
2390 .map(|p| CString::new(p.as_str()).unwrap());
2391 let result = unsafe {
2392 k2h_keyq_str_read_keyval_wp(
2393 self.base.handle,
2394 &mut ppkey,
2395 &mut ppval,
2396 position as c_int,
2397 c_pass.as_ref().map_or(ptr::null(), |p| p.as_ptr()),
2398 )
2399 };
2400 if result && !ppkey.is_null() && !ppval.is_null() {
2401 let key = unsafe { CStr::from_ptr(ppkey).to_string_lossy().into_owned() };
2402 let val = unsafe { CStr::from_ptr(ppval).to_string_lossy().into_owned() };
2403 Some((key, val))
2404 } else {
2405 None
2406 }
2407 }
2408
2409 /// Check if the KeyQueue is empty.
2410 pub fn empty(&self) -> bool {
2411 unsafe { k2h_keyq_empty(self.base.handle) }
2412 }
2413
2414 /// Print the current KeyQueue.
2415 pub fn print(&self) -> Result<(), &'static str> {
2416 let result = unsafe { k2h_keyq_dump(self.base.handle, ptr::null_mut()) };
2417 if result {
2418 Ok(())
2419 } else {
2420 Err("k2h_keyq_dump returns error")
2421 }
2422 }
2423
2424 /// Remove elements from the KeyQueue.
2425 pub fn remove(&self, count: usize) -> Result<Vec<(String, String)>, &'static str> {
2426 if count == 0 {
2427 return Ok(Vec::new());
2428 }
2429 let mut vals = Vec::new();
2430 for _ in 0..count {
2431 let mut key_ptr: *mut c_char = ptr::null_mut();
2432 let mut val_ptr: *mut c_char = ptr::null_mut();
2433 let c_pass = self
2434 .base
2435 .password
2436 .as_ref()
2437 .map(|p| CString::new(p.as_str()).unwrap());
2438 let result = unsafe {
2439 k2h_keyq_str_pop_keyval_wp(
2440 self.base.handle,
2441 &mut key_ptr,
2442 &mut val_ptr,
2443 c_pass.as_ref().map_or(ptr::null(), |p| p.as_ptr()),
2444 )
2445 };
2446 if result && !key_ptr.is_null() && !val_ptr.is_null() {
2447 let key = unsafe { CStr::from_ptr(key_ptr).to_string_lossy().into_owned() };
2448 let val = unsafe { CStr::from_ptr(val_ptr).to_string_lossy().into_owned() };
2449 vals.push((key, val));
2450 } else {
2451 break; // Stop if no more elements are available
2452 }
2453 }
2454 Ok(vals)
2455 }
2456
2457 /// Remove all elements from the KeyQueue.
2458 pub fn clear(&self) -> bool {
2459 let count = self.qsize() as c_int;
2460 if count > 0 {
2461 unsafe { k2h_keyq_remove(self.base.handle, count) }
2462 } else {
2463 true
2464 }
2465 }
2466
2467 /// Close the KeyQueue handle.
2468 pub fn close(&self) -> bool {
2469 unsafe { k2h_keyq_free(self.base.handle) }
2470 }
2471}
2472/// KeyQueueBuilder provides a builder pattern for creating KeyQueue instances.
2473///
2474/// # Examples
2475///
2476/// ```
2477/// use k2hash_rust::{K2hash, KeyQueueBuilder};
2478/// let db = K2hash::open_mem().expect("open_mem failed");
2479/// let handle = db.handle();
2480/// assert!(handle != 0, "Handle should not be zero");
2481/// let fifo = true; // or false, depending on your needs
2482/// let prefix = "test_prefix".to_string();
2483/// let password = Some("your_password".to_string());
2484/// let expire_duration = Some(60); // for 60 seconds expiration
2485/// // Create the KeyQueue using KeyQueueBuilder
2486/// let qb1 = KeyQueueBuilder::new(db.handle())
2487/// .fifo(fifo)
2488/// .prefix(prefix) // Optional prefix
2489/// .password(password.expect("Error")) // Optional password
2490/// .expire_duration(expire_duration.expect("Error")) // Optional expiration duration
2491/// .build()
2492/// .expect("KeyQueue creation failed");
2493/// // check if KeyQueue is not null
2494/// assert!(qb1.handle() != 0, "KeyQueue handle should not be zero");
2495/// ```
2496pub struct KeyQueueBuilder {
2497 k2h: u64,
2498 fifo: bool,
2499 prefix: Option<String>,
2500 password: Option<String>,
2501 expire_duration: Option<u64>,
2502}
2503
2504impl KeyQueueBuilder {
2505 /// Create a new KeyQueueBuilder.
2506 pub fn new(k2h: u64) -> Self {
2507 KeyQueueBuilder {
2508 k2h,
2509 fifo: true,
2510 prefix: None,
2511 password: None,
2512 expire_duration: None,
2513 }
2514 }
2515
2516 /// Set the FIFO mode for the KeyQueue.
2517 pub fn fifo(mut self, fifo: bool) -> Self {
2518 self.fifo = fifo;
2519 self
2520 }
2521
2522 /// Set the prefix for the KeyQueue.
2523 pub fn prefix(mut self, prefix: String) -> Self {
2524 self.prefix = Some(prefix);
2525 self
2526 }
2527
2528 /// Set the password for the KeyQueue.
2529 pub fn password(mut self, password: String) -> Self {
2530 self.password = Some(password);
2531 self
2532 }
2533
2534 /// Set the expire duration for the KeyQueue.
2535 pub fn expire_duration(mut self, expire_duration: u64) -> Self {
2536 self.expire_duration = Some(expire_duration);
2537 self
2538 }
2539
2540 /// Create a new KeyQueue instance with options.
2541 pub fn build(self) -> Result<KeyQueue, &'static str> {
2542 KeyQueue::new(
2543 self.k2h,
2544 self.fifo,
2545 self.prefix,
2546 self.password,
2547 self.expire_duration,
2548 )
2549 }
2550}
2551
2552//
2553// Local variables:
2554// tab-width: 4
2555// c-basic-offset: 4
2556// End:
2557// vim600: expandtab sw=4 ts=4 fdm=marker
2558// vim<600: expandtab sw=4 ts=4
2559//