couchbase_lite/
doc_enumerator.rs1use crate::{
2 document::{C4DocumentOwner, Document},
3 error::{c4error_init, Error, Result},
4 ffi::{
5 c4db_enumerateAllDocs, c4enum_free, c4enum_getDocument, c4enum_getDocumentInfo,
6 c4enum_next, C4DocEnumerator, C4DocumentInfo, C4EnumeratorFlags, C4EnumeratorOptions,
7 },
8 Database,
9};
10use bitflags::bitflags;
11use fallible_streaming_iterator::FallibleStreamingIterator;
12use std::{marker::PhantomData, mem::MaybeUninit, ptr::NonNull, str};
13
14pub struct DocEnumerator<'a> {
15 _db: &'a Database,
16 reach_end: bool,
17 inner: NonNull<C4DocEnumerator>,
18}
19
20impl Drop for DocEnumerator<'_> {
21 #[inline]
22 fn drop(&mut self) {
23 unsafe { c4enum_free(self.inner.as_ptr()) };
24 }
25}
26
27pub struct DocumentInfo<'a, 'b> {
28 inner: C4DocumentInfo,
29 phantom: PhantomData<&'a DocEnumerator<'b>>,
30}
31
32impl DocumentInfo<'_, '_> {
33 pub(crate) fn new(inner: C4DocumentInfo) -> Self {
34 Self {
35 inner,
36 phantom: PhantomData,
37 }
38 }
39 #[inline]
40 pub fn doc_id(&self) -> &str {
41 unsafe { str::from_utf8_unchecked(self.inner.docID.into()) }
42 }
43}
44
45impl<'a> DocEnumerator<'a> {
46 pub(crate) fn enumerate_all_docs(
47 db: &'a Database,
48 flags: DocEnumeratorFlags,
49 ) -> Result<DocEnumerator<'a>> {
50 let mut c4err = c4error_init();
51 let opts = C4EnumeratorOptions {
52 flags: C4EnumeratorFlags(flags.bits()),
53 };
54 let enum_ptr = unsafe { c4db_enumerateAllDocs(db.inner.0.as_ptr(), &opts, &mut c4err) };
55 NonNull::new(enum_ptr)
56 .map(|inner| DocEnumerator {
57 _db: db,
58 inner,
59 reach_end: false,
60 })
61 .ok_or_else(|| c4err.into())
62 }
63
64 #[inline]
65 pub fn get_doc_info<'b>(&'b self) -> Result<Option<DocumentInfo<'a, 'b>>> {
66 let mut di = MaybeUninit::<C4DocumentInfo>::uninit();
67 if !unsafe { c4enum_getDocumentInfo(self.inner.as_ptr(), di.as_mut_ptr()) } {
68 return Ok(None);
69 }
70 let di = unsafe { di.assume_init() };
71
72 Ok(Some(DocumentInfo::new(di)))
73 }
74
75 pub fn get_doc(&self) -> Result<Document> {
76 let mut c4err = c4error_init();
77 let doc_ptr = unsafe { c4enum_getDocument(self.inner.as_ptr(), &mut c4err) };
78 let c4doc: C4DocumentOwner =
79 NonNull::new(doc_ptr).map(C4DocumentOwner).ok_or_else(|| {
80 let err: Error = c4err.into();
81 err
82 })?;
83 let id: String = c4doc.id()?.into();
84 Ok(Document::new_internal(c4doc, id))
85 }
86}
87
88impl<'en> FallibleStreamingIterator for DocEnumerator<'en> {
89 type Error = crate::error::Error;
90 type Item = DocEnumerator<'en>;
91
92 fn advance(&mut self) -> Result<()> {
93 if self.reach_end {
94 return Ok(());
95 }
96 let mut c4err = c4error_init();
97 if unsafe { c4enum_next(self.inner.as_ptr(), &mut c4err) } {
98 Ok(())
99 } else if c4err.code == 0 {
100 self.reach_end = true;
101 Ok(())
102 } else {
103 Err(c4err.into())
104 }
105 }
106
107 #[inline]
108 fn get(&self) -> Option<&DocEnumerator<'en>> {
109 if !self.reach_end {
110 Some(self)
111 } else {
112 None
113 }
114 }
115}
116
117bitflags! {
118 #[derive(Debug)]
119 pub struct DocEnumeratorFlags: u16 {
120 const DESCENDING = 0x01;
122 const INCLUDE_DELETED = 0x08;
124 const INCLUDE_NON_CONFLICTED = 0x10;
126 const INCLUDE_BODIES = 0x20;
132
133 }
134}
135impl Default for DocEnumeratorFlags {
136 #[inline]
137 fn default() -> Self {
138 DocEnumeratorFlags::INCLUDE_BODIES | DocEnumeratorFlags::INCLUDE_NON_CONFLICTED
139 }
140}