1use std::ffi::{CStr, c_char, c_void};
2use std::ptr;
3
4use crate::ffi::*;
5use crate::rset::{OwnedRset, Rset};
6use crate::{Error, cstring, ensure_init};
7
8unsafe extern "C" {
9 fn free(ptr: *mut c_void);
10}
11
12pub struct Db {
13 ptr: rec_db_t,
14}
15
16impl Db {
17 pub fn new() -> Self {
20 ensure_init();
21 let ptr = unsafe { rec_db_new() };
22 assert!(!ptr.is_null(), "rec_db_new returned NULL");
23 Db { ptr }
24 }
25
26 pub fn parse_str(text: &str) -> Result<Self, Error> {
27 ensure_init();
28 let c_text = cstring(text, "rec source")?;
29 unsafe {
30 let parser = rec_parser_new_str(c_text.as_ptr(), c"input".as_ptr());
31 if parser.is_null() {
32 return Err(Error::new("rec_parser_new_str returned NULL"));
33 }
34 let mut db: rec_db_t = ptr::null_mut();
35 let ok = rec_parse_db(parser, &mut db);
36 rec_parser_destroy(parser);
37 if !ok || db.is_null() {
38 if !db.is_null() {
39 rec_db_destroy(db);
40 }
41 return Err(Error::new("rec_parse_db failed"));
42 }
43 Ok(Db { ptr: db })
44 }
45 }
46
47 pub fn num_rsets(&self) -> usize {
48 unsafe { rec_db_size(self.ptr) }
49 }
50
51 pub fn rset_at(&mut self, idx: usize) -> Option<Rset<'_>> {
52 let p = unsafe { rec_db_get_rset(self.ptr, idx) };
53 (!p.is_null()).then(|| Rset::from_raw(p))
54 }
55
56 pub fn rset_by_type(&mut self, name: &str) -> Option<Rset<'_>> {
57 let c_name = cstring(name, "rset type").ok()?;
58 let p = unsafe { rec_db_get_rset_by_type(self.ptr, c_name.as_ptr()) };
59 (!p.is_null()).then(|| Rset::from_raw(p))
60 }
61
62 pub fn append_rset(&mut self, rset: OwnedRset) -> Result<(), Error> {
66 let raw = rset.into_raw();
67 let position = unsafe { rec_db_size(self.ptr) };
68 let ok = unsafe { rec_db_insert_rset(self.ptr, raw, position) };
69 if !ok {
70 unsafe { rec_rset_destroy(raw) };
71 return Err(Error::new("rec_db_insert_rset failed"));
72 }
73 Ok(())
74 }
75
76 pub fn to_rec_string(&self) -> Result<String, Error> {
77 unsafe {
78 let mut buf: *mut c_char = ptr::null_mut();
79 let mut size: usize = 0;
80 let writer = rec_writer_new_str(&mut buf, &mut size);
81 if writer.is_null() {
82 return Err(Error::new("rec_writer_new_str returned NULL"));
83 }
84 let ok = rec_write_db(writer, self.ptr);
85 rec_writer_destroy(writer);
86 if !ok || buf.is_null() {
87 if !buf.is_null() {
88 free(buf as *mut c_void);
89 }
90 return Err(Error::new("rec_write_db failed"));
91 }
92 let s = CStr::from_ptr(buf).to_string_lossy().into_owned();
93 free(buf as *mut c_void);
94 Ok(s)
95 }
96 }
97}
98
99impl Default for Db {
100 fn default() -> Self {
101 Db::new()
102 }
103}
104
105impl Drop for Db {
106 fn drop(&mut self) {
107 unsafe { rec_db_destroy(self.ptr) }
108 }
109}