Skip to main content

recutils_rs/
rset.rs

1use std::ffi::c_void;
2use std::marker::PhantomData;
3use std::ptr;
4
5use crate::db::Db;
6use crate::ffi::*;
7use crate::record::{Record, RecordRef};
8use crate::{Error, ensure_init};
9
10pub struct Rset<'a> {
11    ptr: rec_rset_t,
12    _marker: PhantomData<&'a mut Db>,
13}
14
15impl<'a> Rset<'a> {
16    pub(crate) fn from_raw(ptr: rec_rset_t) -> Self {
17        Rset { ptr, _marker: PhantomData }
18    }
19
20    pub fn num_records(&self) -> usize {
21        unsafe { rec_rset_num_records(self.ptr) }
22    }
23
24    /// The record-descriptor record (everything declared in the `%rec:` /
25    /// `%type:` / `%key:` / `%mandatory:` block). `None` for record sets that
26    /// have no descriptor.
27    pub fn descriptor(&self) -> Option<RecordRef<'_>> {
28        let p = unsafe { rec_rset_descriptor(self.ptr) };
29        (!p.is_null()).then(|| RecordRef::from_raw(p))
30    }
31
32    pub fn records(&self) -> Records<'_> {
33        let iter = unsafe { rec_mset_iterator(rec_rset_mset(self.ptr)) };
34        Records { iter, done: false, _marker: PhantomData }
35    }
36
37    /// Remove every record for which `pred` returns true. Returns the count
38    /// of records removed.
39    pub fn remove_matching<F>(&mut self, mut pred: F) -> usize
40    where
41        F: FnMut(&RecordRef<'_>) -> bool,
42    {
43        let mset = unsafe { rec_rset_mset(self.ptr) };
44        let mut to_remove: Vec<usize> = Vec::new();
45        let mut iter = unsafe { rec_mset_iterator(mset) };
46        let mut idx: usize = 0;
47        loop {
48            let mut data: *const c_void = ptr::null();
49            let advanced = unsafe {
50                rec_mset_iterator_next(
51                    &mut iter,
52                    MSET_RECORD as rec_mset_type_t,
53                    &mut data,
54                    ptr::null_mut(),
55                )
56            };
57            if !advanced {
58                break;
59            }
60            let r = RecordRef::from_raw(data as rec_record_t);
61            if pred(&r) {
62                to_remove.push(idx);
63            }
64            idx += 1;
65        }
66        unsafe { rec_mset_iterator_free(&mut iter) };
67
68        let n = to_remove.len();
69        for pos in to_remove.into_iter().rev() {
70            unsafe { rec_mset_remove_at(mset, MSET_RECORD as rec_mset_type_t, pos) };
71        }
72        n
73    }
74
75    pub fn append_record(&mut self, record: Record) -> Result<(), Error> {
76        let raw = record.into_raw();
77        let elem = unsafe {
78            rec_mset_append(
79                rec_rset_mset(self.ptr),
80                MSET_RECORD as rec_mset_type_t,
81                raw as *mut c_void,
82                MSET_RECORD as rec_mset_type_t,
83            )
84        };
85        if elem.is_null() {
86            unsafe { rec_record_destroy(raw) };
87            return Err(Error::new("rec_mset_append (record) failed"));
88        }
89        Ok(())
90    }
91}
92
93pub struct Records<'a> {
94    iter: rec_mset_iterator_t,
95    done: bool,
96    _marker: PhantomData<&'a Rset<'a>>,
97}
98
99impl<'a> Iterator for Records<'a> {
100    type Item = RecordRef<'a>;
101
102    fn next(&mut self) -> Option<Self::Item> {
103        if self.done {
104            return None;
105        }
106        let mut data: *const c_void = ptr::null();
107        let advanced = unsafe {
108            rec_mset_iterator_next(
109                &mut self.iter,
110                MSET_RECORD as rec_mset_type_t,
111                &mut data,
112                ptr::null_mut(),
113            )
114        };
115        if !advanced {
116            self.done = true;
117            return None;
118        }
119        Some(RecordRef::from_raw(data as rec_record_t))
120    }
121}
122
123impl<'a> Drop for Records<'a> {
124    fn drop(&mut self) {
125        unsafe { rec_mset_iterator_free(&mut self.iter) }
126    }
127}
128
129/// A freshly-built record set not yet inserted into a [`Db`]. Owns its
130/// `rec_rset_t` until handed to [`Db::append_rset`], at which point ownership
131/// is transferred to the containing database.
132pub struct OwnedRset {
133    ptr: rec_rset_t,
134}
135
136impl OwnedRset {
137    pub fn new() -> Self {
138        ensure_init();
139        let ptr = unsafe { rec_rset_new() };
140        assert!(!ptr.is_null(), "rec_rset_new returned NULL");
141        OwnedRset { ptr }
142    }
143
144    /// Install `record` as this rset's descriptor (the `%rec:` / `%type:` /
145    /// `%mandatory:` block). Ownership of the record transfers to the rset.
146    /// Replaces and destroys any prior descriptor.
147    pub fn set_descriptor(&mut self, record: Record) {
148        let raw = record.into_raw();
149        unsafe { rec_rset_set_descriptor(self.ptr, raw) };
150    }
151
152    pub fn append_record(&mut self, record: Record) -> Result<(), Error> {
153        let raw = record.into_raw();
154        let elem = unsafe {
155            rec_mset_append(
156                rec_rset_mset(self.ptr),
157                MSET_RECORD as rec_mset_type_t,
158                raw as *mut c_void,
159                MSET_RECORD as rec_mset_type_t,
160            )
161        };
162        if elem.is_null() {
163            unsafe { rec_record_destroy(raw) };
164            return Err(Error::new("rec_mset_append (record) failed"));
165        }
166        Ok(())
167    }
168
169    pub(crate) fn into_raw(self) -> rec_rset_t {
170        let ptr = self.ptr;
171        std::mem::forget(self);
172        ptr
173    }
174}
175
176impl Default for OwnedRset {
177    fn default() -> Self {
178        OwnedRset::new()
179    }
180}
181
182impl Drop for OwnedRset {
183    fn drop(&mut self) {
184        unsafe { rec_rset_destroy(self.ptr) }
185    }
186}