1 /* ide-code-index-entries.c
2 *
3 * Copyright 2017-2019 Christian Hergert <chergert@redhat.com>
4 * Copyright 2017 Anoop Chandu <anoopchandu96@gmail.com>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * SPDX-License-Identifier: GPL-3.0-or-later
20 */
21
22 #define G_LOG_DOMAIN "ide-code-index-entries"
23
24 #include "config.h"
25
26 #include <libide-threading.h>
27
28 #include "ide-code-index-entry.h"
29 #include "ide-code-index-entries.h"
30
G_DEFINE_INTERFACE(IdeCodeIndexEntries,ide_code_index_entries,G_TYPE_OBJECT)31 G_DEFINE_INTERFACE (IdeCodeIndexEntries, ide_code_index_entries, G_TYPE_OBJECT)
32
33 static void
34 ide_code_index_entries_real_next_entries_async (IdeCodeIndexEntries *self,
35 GCancellable *cancellable,
36 GAsyncReadyCallback callback,
37 gpointer user_data)
38 {
39 g_autoptr(IdeTask) task = NULL;
40 g_autoptr(GPtrArray) ret = NULL;
41 IdeCodeIndexEntry *entry;
42
43 g_assert (IDE_IS_MAIN_THREAD ());
44 g_assert (IDE_IS_CODE_INDEX_ENTRIES (self));
45 g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
46
47 task = ide_task_new (self, cancellable, callback, user_data);
48 ide_task_set_source_tag (task, ide_code_index_entries_real_next_entries_async);
49 ide_task_set_priority (task, G_PRIORITY_LOW);
50 ide_task_set_kind (task, IDE_TASK_KIND_INDEXER);
51
52 ret = g_ptr_array_new_with_free_func ((GDestroyNotify)ide_code_index_entry_free);
53
54 while ((entry = ide_code_index_entries_get_next_entry (self)))
55 g_ptr_array_add (ret, g_steal_pointer (&entry));
56
57 ide_task_return_pointer (task, g_steal_pointer (&ret), g_ptr_array_unref);
58 }
59
60 static GPtrArray *
ide_code_index_entries_real_next_entries_finish(IdeCodeIndexEntries * self,GAsyncResult * result,GError ** error)61 ide_code_index_entries_real_next_entries_finish (IdeCodeIndexEntries *self,
62 GAsyncResult *result,
63 GError **error)
64 {
65 GPtrArray *ret;
66
67 g_assert (IDE_IS_CODE_INDEX_ENTRIES (self));
68 g_assert (IDE_IS_TASK (result));
69
70 ret = ide_task_propagate_pointer (IDE_TASK (result), error);
71
72 return IDE_PTR_ARRAY_STEAL_FULL (&ret);
73 }
74
75 static IdeCodeIndexEntry *
ide_code_index_entries_real_get_next_entry(IdeCodeIndexEntries * self)76 ide_code_index_entries_real_get_next_entry (IdeCodeIndexEntries *self)
77 {
78 return NULL;
79 }
80
81 static void
ide_code_index_entries_default_init(IdeCodeIndexEntriesInterface * iface)82 ide_code_index_entries_default_init (IdeCodeIndexEntriesInterface *iface)
83 {
84 iface->get_next_entry = ide_code_index_entries_real_get_next_entry;
85 iface->next_entries_async = ide_code_index_entries_real_next_entries_async;
86 iface->next_entries_finish = ide_code_index_entries_real_next_entries_finish;
87 }
88
89 /**
90 * ide_code_index_entries_get_next_entry:
91 * @self: An #IdeCodeIndexEntries instance.
92 *
93 * This will fetch next entry in index.
94 *
95 * When all of the entries have been exhausted, %NULL should be returned.
96 *
97 * Returns: (nullable) (transfer full): An #IdeCodeIndexEntry.
98 *
99 * Since: 3.32
100 */
101 IdeCodeIndexEntry *
ide_code_index_entries_get_next_entry(IdeCodeIndexEntries * self)102 ide_code_index_entries_get_next_entry (IdeCodeIndexEntries *self)
103 {
104 g_return_val_if_fail (IDE_IS_MAIN_THREAD (), NULL);
105 g_return_val_if_fail (IDE_IS_CODE_INDEX_ENTRIES (self), NULL);
106
107 return IDE_CODE_INDEX_ENTRIES_GET_IFACE (self)->get_next_entry (self);
108 }
109
110 /**
111 * ide_code_index_entries_get_file:
112 * @self: a #IdeCodeIndexEntries
113 *
114 * The file that was indexed.
115 *
116 * Returns: (transfer full): a #GFile
117 *
118 * Since: 3.32
119 */
120 GFile *
ide_code_index_entries_get_file(IdeCodeIndexEntries * self)121 ide_code_index_entries_get_file (IdeCodeIndexEntries *self)
122 {
123 g_return_val_if_fail (IDE_IS_MAIN_THREAD (), NULL);
124 g_return_val_if_fail (IDE_IS_CODE_INDEX_ENTRIES (self), NULL);
125
126 return IDE_CODE_INDEX_ENTRIES_GET_IFACE (self)->get_file (self);
127 }
128
129 /**
130 * ide_code_index_entries_next_entries_async:
131 * @self: a #IdeCodeIndexEntries
132 * @cancellable: (nullable): a #GCancellable or %NULL
133 * @callback: a callback to execute upon completion
134 * @user_data: user data for @callback, or %NULL
135 *
136 * Requests the next set of results from the code index asynchronously.
137 * This allows implementations to possibly process data off the main thread
138 * without blocking the main loop.
139 *
140 * Since: 3.32
141 */
142 void
ide_code_index_entries_next_entries_async(IdeCodeIndexEntries * self,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)143 ide_code_index_entries_next_entries_async (IdeCodeIndexEntries *self,
144 GCancellable *cancellable,
145 GAsyncReadyCallback callback,
146 gpointer user_data)
147 {
148 g_return_if_fail (IDE_IS_MAIN_THREAD ());
149 g_return_if_fail (IDE_IS_CODE_INDEX_ENTRIES (self));
150 g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
151
152 IDE_CODE_INDEX_ENTRIES_GET_IFACE (self)->next_entries_async (self, cancellable, callback, user_data);
153 }
154
155 /**
156 * ide_code_index_entries_next_entries_finish:
157 * @self: a #IdeCodeIndexEntries
158 * @result: a #GAsyncResult provided to callback
159 * @error: a location for a #GError, or %NULL
160 *
161 * Completes an asynchronous request for the next set of entries from the index.
162 *
163 * Returns: (transfer full) (element-type IdeCodeIndexEntry): a #GPtrArray
164 * of #IdeCodeIndexEntry.
165 *
166 * Since: 3.32
167 */
168 GPtrArray *
ide_code_index_entries_next_entries_finish(IdeCodeIndexEntries * self,GAsyncResult * result,GError ** error)169 ide_code_index_entries_next_entries_finish (IdeCodeIndexEntries *self,
170 GAsyncResult *result,
171 GError **error)
172 {
173 g_return_val_if_fail (IDE_IS_MAIN_THREAD (), NULL);
174 g_return_val_if_fail (IDE_IS_CODE_INDEX_ENTRIES (self), NULL);
175 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
176
177 return IDE_CODE_INDEX_ENTRIES_GET_IFACE (self)->next_entries_finish (self, result, error);
178 }
179
180 static void
ide_code_index_entries_collect_cb(GObject * object,GAsyncResult * result,gpointer user_data)181 ide_code_index_entries_collect_cb (GObject *object,
182 GAsyncResult *result,
183 gpointer user_data)
184 {
185 IdeCodeIndexEntries *self = (IdeCodeIndexEntries *)object;
186 g_autoptr(IdeTask) task = user_data;
187 g_autoptr(GPtrArray) ret = NULL;
188 g_autoptr(GError) error = NULL;
189 GPtrArray *task_data;
190
191 g_assert (IDE_IS_MAIN_THREAD ());
192 g_assert (IDE_IS_CODE_INDEX_ENTRIES (self));
193 g_assert (G_IS_ASYNC_RESULT (result));
194 g_assert (IDE_IS_TASK (task));
195
196 if (!(task_data = ide_task_get_task_data (task)))
197 {
198 task_data = g_ptr_array_new_with_free_func ((GDestroyNotify)ide_code_index_entry_free);
199 ide_task_set_task_data (task, task_data, g_ptr_array_unref);
200 }
201
202 if ((ret = ide_code_index_entries_next_entries_finish (self, result, &error)) && ret->len > 0)
203 {
204 IDE_PTR_ARRAY_SET_FREE_FUNC (ret, NULL);
205
206 for (guint i = 0; i < ret->len; i++)
207 g_ptr_array_add (task_data, g_ptr_array_index (ret, i));
208
209 g_ptr_array_remove_range (ret, 0, ret->len);
210
211 ide_code_index_entries_next_entries_async (self,
212 ide_task_get_cancellable (task),
213 ide_code_index_entries_collect_cb,
214 g_object_ref (task));
215 return;
216 }
217
218 ide_task_return_pointer (task,
219 g_ptr_array_ref (task_data),
220 g_ptr_array_unref);
221 }
222
223 /**
224 * ide_code_index_entries_collect_async:
225 *
226 * Calls ide_code_index_entries_next_entries_async() repeatedly until all
227 * entries have been retrieved. After that, the async operation will complete.
228 *
229 * Since: 3.32
230 */
231 void
ide_code_index_entries_collect_async(IdeCodeIndexEntries * self,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)232 ide_code_index_entries_collect_async (IdeCodeIndexEntries *self,
233 GCancellable *cancellable,
234 GAsyncReadyCallback callback,
235 gpointer user_data)
236 {
237 g_autoptr(IdeTask) task = NULL;
238
239 g_return_if_fail (IDE_IS_CODE_INDEX_ENTRIES (self));
240 g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
241
242 task = ide_task_new (self, cancellable, callback, user_data);
243 ide_task_set_source_tag (task, ide_code_index_entries_collect_async);
244 ide_code_index_entries_next_entries_async (self,
245 cancellable,
246 ide_code_index_entries_collect_cb,
247 g_steal_pointer (&task));
248 }
249
250 /**
251 * ide_code_index_entries_collect_finish:
252 *
253 * Returns: (transfer full) (element-type IdeCodeIndexEntry): an array of #IdeCodeIndexEntry
254 * or %NULL and @error is set
255 *
256 * Since: 3.32
257 */
258 GPtrArray *
ide_code_index_entries_collect_finish(IdeCodeIndexEntries * self,GAsyncResult * result,GError ** error)259 ide_code_index_entries_collect_finish (IdeCodeIndexEntries *self,
260 GAsyncResult *result,
261 GError **error)
262 {
263 g_return_val_if_fail (IDE_IS_MAIN_THREAD (), NULL);
264 g_return_val_if_fail (IDE_IS_CODE_INDEX_ENTRIES (self), NULL);
265 g_return_val_if_fail (IDE_IS_TASK (result), NULL);
266
267 return ide_task_propagate_pointer (IDE_TASK (result), error);
268 }
269