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//