1use std::ffi::{CStr, c_void};
2use std::marker::PhantomData;
3use std::ptr;
4
5use crate::ffi::*;
6use crate::{Error, cstring, ensure_init};
7
8pub struct Record {
12 ptr: rec_record_t,
13}
14
15impl Record {
16 pub fn new() -> Self {
17 ensure_init();
18 let ptr = unsafe { rec_record_new() };
19 assert!(!ptr.is_null(), "rec_record_new returned NULL");
20 Record { ptr }
21 }
22
23 pub fn append_field(&mut self, name: &str, value: &str) -> Result<(), Error> {
24 let cn = cstring(name, "field name")?;
25 let cv = cstring(value, "field value")?;
26 unsafe {
27 let field = rec_field_new(cn.as_ptr(), cv.as_ptr());
28 if field.is_null() {
29 return Err(Error::new("rec_field_new returned NULL"));
30 }
31 let mset = rec_record_mset(self.ptr);
32 let elem = rec_mset_append(
33 mset,
34 MSET_FIELD as rec_mset_type_t,
35 field as *mut c_void,
36 MSET_FIELD as rec_mset_type_t,
37 );
38 if elem.is_null() {
39 rec_field_destroy(field);
40 return Err(Error::new("rec_mset_append (field) failed"));
41 }
42 }
43 Ok(())
44 }
45
46 pub(crate) fn into_raw(self) -> rec_record_t {
47 let ptr = self.ptr;
48 std::mem::forget(self);
49 ptr
50 }
51}
52
53impl Default for Record {
54 fn default() -> Self {
55 Record::new()
56 }
57}
58
59impl Drop for Record {
60 fn drop(&mut self) {
61 unsafe { rec_record_destroy(self.ptr) }
62 }
63}
64
65pub struct RecordRef<'a> {
66 ptr: rec_record_t,
67 _marker: PhantomData<&'a ()>,
68}
69
70impl<'a> RecordRef<'a> {
71 pub(crate) fn from_raw(ptr: rec_record_t) -> Self {
72 RecordRef { ptr, _marker: PhantomData }
73 }
74
75 pub fn fields(&self) -> Fields<'_> {
76 let iter = unsafe { rec_mset_iterator(rec_record_mset(self.ptr)) };
77 Fields { iter, done: false, _marker: PhantomData }
78 }
79
80 pub fn as_ptr(&self) -> rec_record_t {
81 self.ptr
82 }
83
84 pub fn set_field(&mut self, name: &str, value: &str) -> Result<bool, Error> {
87 let cn = cstring(name, "field name")?;
88 let cv = cstring(value, "field value")?;
89 unsafe {
90 let field = rec_record_get_field_by_name(self.ptr, cn.as_ptr(), 0);
91 if field.is_null() {
92 return Ok(false);
93 }
94 if !rec_field_set_value(field, cv.as_ptr()) {
95 return Err(Error::new("rec_field_set_value failed"));
96 }
97 }
98 Ok(true)
99 }
100}
101
102pub struct Fields<'a> {
103 iter: rec_mset_iterator_t,
104 done: bool,
105 _marker: PhantomData<&'a RecordRef<'a>>,
106}
107
108impl<'a> Iterator for Fields<'a> {
109 type Item = FieldRef<'a>;
110
111 fn next(&mut self) -> Option<Self::Item> {
112 if self.done {
113 return None;
114 }
115 let mut data: *const c_void = ptr::null();
116 let advanced = unsafe {
117 rec_mset_iterator_next(
118 &mut self.iter,
119 MSET_FIELD as rec_mset_type_t,
120 &mut data,
121 ptr::null_mut(),
122 )
123 };
124 if !advanced {
125 self.done = true;
126 return None;
127 }
128 Some(FieldRef { ptr: data as rec_field_t, _marker: PhantomData })
129 }
130}
131
132impl<'a> Drop for Fields<'a> {
133 fn drop(&mut self) {
134 unsafe { rec_mset_iterator_free(&mut self.iter) }
135 }
136}
137
138pub struct FieldRef<'a> {
139 ptr: rec_field_t,
140 _marker: PhantomData<&'a ()>,
141}
142
143impl<'a> FieldRef<'a> {
144 pub fn name(&self) -> String {
145 unsafe { CStr::from_ptr(rec_field_name(self.ptr)).to_string_lossy().into_owned() }
146 }
147
148 pub fn value(&self) -> String {
149 unsafe { CStr::from_ptr(rec_field_value(self.ptr)).to_string_lossy().into_owned() }
150 }
151}