birb/birb

Initial revision

6 months ago, Gary Kramlich
d9d91dc0265d
Parents
Children 4e1467dcd5d7
Initial revision

This just imports PurpleQueuedOutputStream and adds all the infrastructure for
the rest of the project.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore Sun Dec 10 05:10:13 2023 -0600
@@ -0,0 +1,9 @@
+syntax: glob
+*.orig
+*-docs.zip
+
+syntax: regexp
+^build.*\/
+^po\/.*\.pot$
+^subprojects\/.+\/
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AUTHORS Sun Dec 10 05:10:13 2023 -0600
@@ -0,0 +1,3 @@
+Elliott 'QuLogic' Sales de Andrade <quantum.analyst@gmail.com>
+Gary Kramlich <grim@reaperworld.com>
+Michael 'Maiku' Ruprecht <cmaiku@gmail.com>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/birb/birb.h.in Sun Dec 10 05:10:13 2023 -0600
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 Birb Developers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef BIRB_H
+#define BIRB_H
+
+#ifndef __GI_SCANNER__ /* hide this bit from g-ir-scanner */
+# ifdef BIRB_COMPILATION
+# error "birb source files should not be including birb.h"
+# endif /* BIRB_COMPILATION */
+#endif /* __GI_SCANNER__ */
+
+#ifndef BIRB_GLOBAL_HEADER_INSIDE
+# define BIRB_GLOBAL_HEADER_INSIDE
+#endif /* BIRB_GLOBAL_HEADER_INSIDE */
+
+@BIRB_H_INCLUDES@
+
+#undef BIRB_GLOBAL_HEADER_INSIDE
+
+#endif /* BIRB_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/birb/birbqueuedoutputstream.c Sun Dec 10 05:10:13 2023 -0600
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2023 Birb Developers
+ *
+ * Birb is the legal property of its developers, whose names are too
+ * numerous to list here. Please refer to the AUTHORS file distributed
+ * with this source distribution
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "birbqueuedoutputstream.h"
+
+struct _BirbQueuedOutputStream {
+ GFilterOutputStream parent;
+
+ GAsyncQueue *queue;
+ gboolean pending_queued;
+};
+
+G_DEFINE_TYPE(BirbQueuedOutputStream, birb_queued_output_stream,
+ G_TYPE_FILTER_OUTPUT_STREAM)
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static void birb_queued_output_stream_start_push_bytes_async(GTask *task);
+
+static void
+birb_queued_output_stream_push_bytes_async_cb(GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ BirbQueuedOutputStream *stream = NULL;
+ GBytes *bytes = NULL;
+ GError *error = NULL;
+ GTask *task = G_TASK(user_data);
+ gsize size = 0;
+ gssize written = 0;
+
+ stream = g_task_get_source_object(task);
+ written = g_output_stream_write_bytes_finish(G_OUTPUT_STREAM(source),
+ res, &error);
+
+ bytes = g_task_get_task_data(task);
+ size = g_bytes_get_size(bytes);
+
+ if(written < 0) {
+ /* Error occurred, return error */
+ g_task_return_error(task, error);
+ g_clear_object(&task);
+ } else if(size > (gsize)written) {
+ /* Partial write, prepare to send remaining data */
+ bytes = g_bytes_new_from_bytes(bytes, written, size - written);
+ g_task_set_task_data(task, bytes, (GDestroyNotify)g_bytes_unref);
+ } else {
+ /* Full write, this task is finished */
+ g_task_return_boolean(task, TRUE);
+ g_clear_object(&task);
+ }
+
+ /* If g_task_return_* was called in this function, the callback
+ * may have cleared the stream. If so, there will be no remaining
+ * tasks to process here.
+ */
+ if(task == NULL) {
+ /* Any queued data left? */
+ task = g_async_queue_try_pop(stream->queue);
+ }
+
+ if(task != NULL) {
+ /* More to process */
+ birb_queued_output_stream_start_push_bytes_async(task);
+ } else {
+ /* All done */
+ stream->pending_queued = FALSE;
+ g_output_stream_clear_pending(G_OUTPUT_STREAM(stream));
+ }
+}
+
+static void
+birb_queued_output_stream_start_push_bytes_async(GTask *task) {
+ BirbQueuedOutputStream *stream = g_task_get_source_object(task);
+ GOutputStream *base_stream = NULL;
+ GFilterOutputStream *filtered = NULL;
+
+ filtered = G_FILTER_OUTPUT_STREAM(stream);
+ base_stream = g_filter_output_stream_get_base_stream(filtered);
+
+ g_output_stream_write_bytes_async(base_stream,
+ g_task_get_task_data(task),
+ g_task_get_priority(task),
+ g_task_get_cancellable(task),
+ birb_queued_output_stream_push_bytes_async_cb,
+ task);
+}
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+static void
+birb_queued_output_stream_dispose(GObject *object) {
+ BirbQueuedOutputStream *stream = BIRB_QUEUED_OUTPUT_STREAM(object);
+
+ g_clear_pointer(&stream->queue, g_async_queue_unref);
+
+ G_OBJECT_CLASS(birb_queued_output_stream_parent_class)->dispose(object);
+}
+
+static void
+birb_queued_output_stream_class_init(BirbQueuedOutputStreamClass *klass) {
+ GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+ obj_class->dispose = birb_queued_output_stream_dispose;
+}
+
+static void
+birb_queued_output_stream_init(BirbQueuedOutputStream *stream) {
+ stream->queue = g_async_queue_new_full((GDestroyNotify)g_bytes_unref);
+ stream->pending_queued = FALSE;
+}
+
+/******************************************************************************
+ * Public API
+ *****************************************************************************/
+GOutputStream *
+birb_queued_output_stream_new(GOutputStream *base_stream) {
+ g_return_val_if_fail(G_IS_OUTPUT_STREAM(base_stream), NULL);
+
+ return g_object_new(
+ BIRB_TYPE_QUEUED_OUTPUT_STREAM,
+ "base-stream", base_stream,
+ NULL);
+}
+
+void
+birb_queued_output_stream_push_bytes_async(BirbQueuedOutputStream *stream,
+ GBytes *bytes,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GError *error = NULL;
+ GTask *task = NULL;
+ gboolean set_pending;
+
+ g_return_if_fail(BIRB_IS_QUEUED_OUTPUT_STREAM(stream));
+ g_return_if_fail(bytes != NULL);
+
+ task = g_task_new(stream, cancellable, callback, user_data);
+ g_task_set_task_data(task, g_bytes_ref(bytes),
+ (GDestroyNotify)g_bytes_unref);
+ g_task_set_source_tag(task, birb_queued_output_stream_push_bytes_async);
+ g_task_set_priority(task, io_priority);
+
+ set_pending = g_output_stream_set_pending(G_OUTPUT_STREAM(stream), &error);
+
+ /* Since we're allowing queuing requests without blocking,
+ * it's not an error to be pending while processing queued operations.
+ */
+ if(!set_pending) {
+ if(!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_PENDING) ||
+ !stream->pending_queued)
+ {
+ g_task_return_error(task, error);
+ g_object_unref(task);
+ return;
+ }
+ }
+
+ g_clear_error(&error);
+ stream->pending_queued = TRUE;
+
+ if(set_pending) {
+ /* Start processing if there were no pending operations */
+ birb_queued_output_stream_start_push_bytes_async(task);
+ } else {
+ /* Otherwise queue the data */
+ g_async_queue_push(stream->queue, task);
+ }
+}
+
+gboolean
+birb_queued_output_stream_push_bytes_finish(BirbQueuedOutputStream *stream,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail(BIRB_IS_QUEUED_OUTPUT_STREAM(stream), FALSE);
+ g_return_val_if_fail(g_task_is_valid(result, stream), FALSE);
+
+ if(!g_async_result_is_tagged(result,
+ birb_queued_output_stream_push_bytes_async))
+ {
+ g_set_error(error, BIRB_QUEUED_OUTPUT_STREAM_ERROR,
+ BIRB_QUEUED_OUTPUT_STREAM_ERROR_UNKNOWN_RESULT,
+ "unknown result");
+
+ return FALSE;
+ }
+
+ return g_task_propagate_boolean(G_TASK(result), error);
+}
+
+void
+birb_queued_output_stream_clear_queue(BirbQueuedOutputStream *stream) {
+ GTask *task = NULL;
+
+ g_return_if_fail(BIRB_IS_QUEUED_OUTPUT_STREAM(stream));
+
+ /* Run through each queued task and set the error message to tell the
+ * caller that the queue was cleared and their message was not sent.
+ */
+ while((task = g_async_queue_try_pop(stream->queue)) != NULL) {
+ g_task_return_new_error(task, BIRB_QUEUED_OUTPUT_STREAM_ERROR,
+ BIRB_QUEUED_OUTPUT_STREAM_ERROR_QUEUE_CLEARED,
+ "queue cleared");
+ g_object_unref(task);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/birb/birbqueuedoutputstream.h Sun Dec 10 05:10:13 2023 -0600
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2023 Birb Developers
+ *
+ * Birb is the legal property of its developers, whose names are too
+ * numerous to list here. Please refer to the AUTHORS file distributed
+ * with this source distribution
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined(BIRB_GLOBAL_HEADER_INSIDE) && !defined(BIRB_COMPILATION)
+# error "only <birb.h> may be included directly"
+#endif
+
+#ifndef BIRB_QUEUED_OUTPUT_STREAM_H
+#define BIRB_QUEUED_OUTPUT_STREAM_H
+
+#include <gio/gio.h>
+
+#include "birbversion.h"
+
+G_BEGIN_DECLS
+
+#define BIRB_QUEUED_OUTPUT_STREAM_ERROR (g_quark_from_static_string("birb-queued-output-stream"))
+
+/**
+ * BirbOutputStreamErrorEnum:
+ * @BIRB_QUEUED_OUTPUT_STREAM_ERROR_GENERIC: Generic error, does not yet have
+ * an assigned number.
+ * @BIRB_QUEUED_OUTPUT_STREAM_ERROR_QUEUE_CLEARED: Set on queued tasks when the
+ * queue is cleared.
+ * @BIRB_QUEUED_OUTPUT_STREAM_ERROR_UNKNOWN_RESULT: Used when
+ * [method@QueuedOutputStream.push_bytes_finish]
+ * is called with a
+ * [iface@Gio.AsyncResult]
+ * that was not created by
+ * [method@QueuedOutputStream.push_bytes_async].
+ *
+ * Error numbers for BirbOutputStream errors.
+ *
+ * Since: 0.1.0
+ */
+typedef enum {
+ BIRB_QUEUED_OUTPUT_STREAM_ERROR_GENERIC,
+ BIRB_QUEUED_OUTPUT_STREAM_ERROR_QUEUE_CLEARED,
+ BIRB_QUEUED_OUTPUT_STREAM_ERROR_UNKNOWN_RESULT,
+} BirbOutputStreamErrorEnum;
+
+#define BIRB_TYPE_QUEUED_OUTPUT_STREAM birb_queued_output_stream_get_type()
+
+/**
+ * BirbQueuedOutputStream:
+ *
+ * An implementation of #GFilterOutputStream which allows queuing data for
+ * output. This allows data to be queued while other data is being output.
+ * Therefore, data doesn't have to be manually stored while waiting for
+ * stream operations to finish.
+ *
+ * To create a queued output stream, use [ctor@QueuedOutputStream.new].
+ *
+ * To queue data, use [method@QueuedOutputStream.push_bytes_async].
+ *
+ * If there's a fatal stream error, it's suggested to clear the remaining bytes
+ * queued with [method@QueuedOutputStream.clear_queue] to avoid excessive
+ * errors returned in the callback of
+ * [method@QueuedOutputStream.push_bytes_async].
+ *
+ * Since: 0.1.0
+ */
+BIRB_AVAILABLE_IN_0_1
+G_DECLARE_FINAL_TYPE(BirbQueuedOutputStream, birb_queued_output_stream,
+ BIRB, QUEUED_OUTPUT_STREAM, GFilterOutputStream)
+
+/**
+ * birb_queued_output_stream_new:
+ * @base_stream: Base output stream to wrap with the queued stream
+ *
+ * Creates a new queued output stream for a base stream.
+ *
+ * Returns: (transfer full): The new stream.
+ *
+ * Since: 0.1.0
+ */
+BIRB_AVAILABLE_IN_0_1
+GOutputStream *birb_queued_output_stream_new(GOutputStream *base_stream);
+
+/**
+ * birb_queued_output_stream_push_bytes_async:
+ * @stream: The instance.
+ * @bytes: The bytes to queue.
+ * @priority: IO priority of the request.
+ * @cancellable: (nullable): A [class@Gio.Cancellable] or %NULL.
+ * @callback: (scope async): Callback to call when the request is finished.
+ * @data: (closure): Data to pass to @callback.
+ *
+ * Asynchronously queues and then writes data to @stream. Once the data has
+ * been written, or an error occurs, @callback will be called.
+ *
+ * Be careful such that if there's a fatal stream error, all remaining queued
+ * operations will likely return this error. Use
+ * [method@Birb.QueuedOutputStream.clear_queue] to clear the queue on such
+ * an error to only report it a single time.
+ *
+ * Since: 0.1.0
+ */
+BIRB_AVAILABLE_IN_0_1
+void birb_queued_output_stream_push_bytes_async(BirbQueuedOutputStream *stream, GBytes *bytes, int priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data);
+
+/**
+ * birb_queued_output_stream_push_bytes_finish:
+ * @stream: The instance.
+ * @result: The [iface@Gio.AsyncResult] of this operation.
+ * @error: Return address for a #GError, or %NULL.
+ *
+ * Finishes pushing bytes asynchronously.
+ *
+ * Returns: %TRUE on success, %FALSE if there was an error
+ *
+ * Since: 0.1.0
+ */
+BIRB_AVAILABLE_IN_0_1
+gboolean birb_queued_output_stream_push_bytes_finish(BirbQueuedOutputStream *stream, GAsyncResult *result, GError **error);
+
+/**
+ * birb_queued_output_stream_clear_queue:
+ * @stream: The instance.
+ *
+ * Clears the queue of any pending bytes. However, any bytes that are in the
+ * process of being sent will finish their operation.
+ *
+ * This function is useful for clearing the queue in case of an IO error. Call
+ * this in the async callback in order to clear the queue and avoid having all
+ * [method@Birb.QueuedOutputStream.push_bytes_async] calls on @stream return
+ * errors if there's a fatal stream error.
+ *
+ * Since: 0.1.0
+ */
+BIRB_AVAILABLE_IN_0_1
+void birb_queued_output_stream_clear_queue(BirbQueuedOutputStream *stream);
+
+G_END_DECLS
+
+#endif /* BIRB_QUEUED_OUTPUT_STREAM_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/birb/birbversion.c Sun Dec 10 05:10:13 2023 -0600
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 Birb Developers
+ *
+ * Birb is the legal property of its developers, whose names are too
+ * numerous to list here. Please refer to the AUTHORS file distributed
+ * with this source distribution
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "birbversion.h"
+
+/******************************************************************************
+ * Externals
+ *****************************************************************************/
+const guint birb_major_version = BIRB_MAJOR_VERSION;
+const guint birb_minor_version = BIRB_MINOR_VERSION;
+const guint birb_micro_version = BIRB_MICRO_VERSION;
+const char *birb_version = BIRB_VERSION;
+
+/******************************************************************************
+ * Public API
+ *****************************************************************************/
+const char *
+birb_check_version(guint required_major, guint required_minor,
+ guint required_micro)
+{
+ if(required_major > BIRB_MAJOR_VERSION) {
+ return "birb version too old (major mismatch)";
+ }
+
+#if BIRB_CHECK_VERSION(1, 0, 0)
+ if(required_major < BIRB_MAJOR_VERSION) {
+ return "birb version too new (major mismatch)";
+ }
+#endif
+
+ if(required_minor > BIRB_MINOR_VERSION) {
+ return "birb version too old (minor mismatch)";
+ }
+
+ if((required_minor == BIRB_MINOR_VERSION) &&
+ (required_micro > BIRB_MICRO_VERSION))
+ {
+ return "birb version too old (micro mismatch)";
+ }
+
+ return NULL;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/birb/birbversion.h Sun Dec 10 05:10:13 2023 -0600
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2023 Birb Developers
+ *
+ * Birb is the legal property of its developers, whose names are too
+ * numerous to list here. Please refer to the AUTHORS file distributed
+ * with this source distribution
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef BIRB_VERSION_H
+#define BIRB_VERSION_H
+
+#include <glib.h>
+
+#include "birbversionconsts.h"
+
+/* clang-format tries to remove the space after 'if', which confuses
+ * gobject-introspection, so turn it off temporarily. */
+/* clang-format off */
+#if (defined(_WIN32) || defined(__CYGWIN__)) && \
+ !defined(BIRB_STATIC_COMPILATION)
+/* clang-format on */
+#define _BIRB_EXPORT __declspec(dllexport)
+#define _BIRB_IMPORT __declspec(dllimport)
+#elif __GNUC__ >= 4
+#define _BIRB_EXPORT __attribute__((visibility("default")))
+#define _BIRB_IMPORT
+#else
+#define _BIRB_EXPORT
+#define _BIRB_IMPORT
+#endif
+#ifdef BIRB_COMPILATION
+#define _BIRB_API _BIRB_EXPORT
+#else
+#define _BIRB_API _BIRB_IMPORT
+#endif
+
+#define _BIRB_EXTERN _BIRB_API extern
+
+#ifdef BIRB_DISABLE_DEPRECATION_WARNINGS
+#define BIRB_DEPRECATED _BIRB_EXTERN
+#define BIRB_DEPRECATED_FOR(f) _BIRB_EXTERN
+#define BIRB_UNAVAILABLE(maj, min) _BIRB_EXTERN
+#define BIRB_UNAVAILABLE_STATIC_INLINE(maj, min)
+#define BIRB_UNAVAILABLE_TYPE(maj, min)
+#else
+#define BIRB_DEPRECATED G_DEPRECATED _BIRB_EXTERN
+#define BIRB_DEPRECATED_FOR(f) G_DEPRECATED_FOR(f) _BIRB_EXTERN
+#define BIRB_UNAVAILABLE(maj, min) G_UNAVAILABLE(maj, min) _BIRB_EXTERN
+#define BIRB_UNAVAILABLE_STATIC_INLINE(maj, min) G_UNAVAILABLE(maj, min)
+#define BIRB_UNAVAILABLE_TYPE(maj, min) G_UNAVAILABLE(maj, min)
+#endif
+
+/**
+ * BIRB_VERSION_CUR_STABLE:
+ *
+ * A macro that evaluates to the current stable version of birb, in a format
+ * that can be used by the C pre-processor.
+ *
+ * Since: 0.1.0
+ */
+#define BIRB_VERSION_CUR_STABLE \
+ (G_ENCODE_VERSION(BIRB_MAJOR_VERSION, BIRB_MINOR_VERSION))
+
+/* If the package sets BIRB_VERSION_MIN_REQUIRED to some future
+ * BIRB_VERSION_X_Y value that we don't know about, it will compare as 0 in
+ * preprocessor tests.
+ */
+#ifndef BIRB_VERSION_MIN_REQUIRED
+#define BIRB_VERSION_MIN_REQUIRED (BIRB_VERSION_CUR_STABLE)
+#elif BIRB_VERSION_MIN_REQUIRED == 0
+#undef BIRB_VERSION_MIN_REQUIRED
+#define BIRB_VERSION_MIN_REQUIRED (BIRB_VERSION_CUR_STABLE + 1)
+#endif /* BIRB_VERSION_MIN_REQUIRED */
+
+#if !defined(BIRB_VERSION_MAX_ALLOWED) || (BIRB_VERSION_MAX_ALLOWED == 0)
+#undef BIRB_VERSION_MAX_ALLOWED
+#define BIRB_VERSION_MAX_ALLOWED (BIRB_VERSION_CUR_STABLE)
+#endif /* BIRB_VERSION_MAX_ALLOWED */
+
+/* sanity checks */
+#if BIRB_VERSION_MIN_REQUIRED > BIRB_VERSION_CUR_STABLE
+#error "BIRB_VERSION_MIN_REQUIRED must be <= BIRB_VERSION_CUR_STABLE"
+#endif
+#if BIRB_VERSION_MAX_ALLOWED < BIRB_VERSION_MIN_REQUIRED
+#error "BIRB_VERSION_MAX_ALLOWED must be >= BIRB_VERSION_MIN_REQUIRED"
+#endif
+#if BIRB_VERSION_MIN_REQUIRED < G_ENCODE_VERSION(0, 1)
+#error "BIRB_VERSION_MIN_REQUIRED must be >= BIRB_VERSION_0_1"
+#endif
+
+#define BIRB_VAR _BIRB_EXTERN
+#define BIRB_AVAILABLE_IN_ALL _BIRB_EXTERN
+
+/**
+ * BIRB_VERSION_0_1:
+ *
+ * A macro that evaluates to the 0.1 version of birb, in a format that can be
+ * used by the C pre-processor.
+ *
+ * Since: 0.1.0
+ */
+#define BIRB_VERSION_0_1 (G_ENCODE_VERSION(0, 1))
+
+#if BIRB_VERSION_MAX_ALLOWED < BIRB_VERSION_0_1
+#define BIRB_AVAILABLE_IN_0_1 BIRB_UNAVAILABLE(0, 1)
+#define BIRB_AVAILABLE_STATIC_INLINE_IN_0_1 BIRB_UNAVAILABLE_STATIC_INLINE(0, 1)
+#define BIRB_AVAILABLE_MACRO_IN_0_1 BIRB_UNAVAILABLE_MACRO(0, 1)
+#define BIRB_AVAILABLE_ENUMERATOR_IN_0_1 BIRB_UNAVAILABLE_ENUMERATOR(0, 1)
+#define BIRB_AVAILABLE_TYPE_IN_0_1 BIRB_UNAVAILABLE_TYPE(0, 1)
+#else
+#define BIRB_AVAILABLE_IN_0_1 _BIRB_EXTERN
+#define BIRB_AVAILABLE_STATIC_INLINE_IN_0_1
+#define BIRB_AVAILABLE_MACRO_IN_0_1
+#define BIRB_AVAILABLE_ENUMERATOR_IN_0_1
+#define BIRB_AVAILABLE_TYPE_IN_0_1
+#endif
+
+G_BEGIN_DECLS
+
+/**
+ * BIRB_CHECK_VERSION:
+ * @major: The major version to check for.
+ * @minor: The minor version to check for.
+ * @micro: The micro version to check for.
+ *
+ * Checks the version of birb being compiled against. See [func@check_version]
+ * for a runtime check.
+ *
+ * Returns: %TRUE if the version is the same or newer than the passed-in
+ * version.
+ *
+ * Since: 0.1.0
+ */
+#define BIRB_CHECK_VERSION(major, minor, micro) ((major) == BIRB_MAJOR_VERSION && \
+ ((minor) < BIRB_MINOR_VERSION || \
+ ((minor) == BIRB_MINOR_VERSION && (micro) <= BIRB_MICRO_VERSION)))
+
+/**
+ * birb_check_version:
+ * @required_major: the required major version.
+ * @required_minor: the required minor version.
+ * @required_micro: the required micro version.
+ *
+ * Checks that the birb version is compatible with the requested version.
+ *
+ * Returns: %NULL if the versions are compatible, or a string describing
+ * the version mismatch if not compatible.
+ *
+ * Since: 0.1.0
+ */
+BIRB_AVAILABLE_IN_ALL
+const char *birb_check_version(guint required_major, guint required_minor, guint required_micro);
+
+/**
+ * birb_version:
+ *
+ * The full version string of the running birb.
+ *
+ * Since: 0.1.0
+ */
+BIRB_VAR const char *birb_version;
+
+/**
+ * birb_major_version:
+ *
+ * The major version of the running birb. Contrast with #BIRB_MAJOR_VERSION,
+ * which expands at compile time to the major version of birb being compiled
+ * against.
+ *
+ * Since: 0.1.0
+ */
+BIRB_VAR const guint birb_major_version;
+
+/**
+ * birb_minor_version:
+ *
+ * The minor version of the running birb. Contrast with #BIRB_MINOR_VERSION,
+ * which expands at compile time to the minor version of birb being compiled
+ * against.
+ *
+ * Since: 0.1.0
+ */
+BIRB_VAR const guint birb_minor_version;
+
+/**
+ * birb_micro_version:
+ *
+ * The micro version of the running birb. Contrast with #BIRB_MICRO_VERSION,
+ * which expands at compile time to the micro version of birb being compiled
+ * against.
+ *
+ * Since: 0.1.0
+ */
+BIRB_VAR const guint birb_micro_version;
+
+G_END_DECLS
+
+#endif /* BIRB_VERSION_CONSTS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/birb/birbversionconsts.h.in Sun Dec 10 05:10:13 2023 -0600
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 Birb Developers
+ *
+ * Birb is the legal property of its developers, whose names are too
+ * numerous to list here. Please refer to the AUTHORS file distributed
+ * with this source distribution
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef BIRB_VERSION_CONSTS_H
+#define BIRB_VERSION_CONSTS_H
+
+/**
+ * BIRB_MAJOR_VERSION:
+ *
+ * The major version of the version of Birb that was compiled against.
+ *
+ * Since: 0.1.0
+ */
+#define BIRB_MAJOR_VERSION (@BIRB_MAJOR_VERSION@)
+
+/**
+ * BIRB_MINOR_VERSION:
+ *
+ * The minor version of the version of Birb that was compiled against.
+ *
+ * Since: 0.1.0
+ */
+#define BIRB_MINOR_VERSION (@BIRB_MINOR_VERSION@)
+
+/**
+ * BIRB_MICRO_VERSION:
+ *
+ * The micro version of the version of Birb that was compiled against.
+ *
+ * Since: 0.1.0
+ */
+#define BIRB_MICRO_VERSION (@BIRB_MICRO_VERSION@)
+
+/**
+ * BIRB_EXTRA_VERSION:
+ *
+ * The extra version of the version of Birb that was compiled against.
+ *
+ * Since: 0.1.0
+ */
+#define BIRB_EXTRA_VERSION ("@BIRB_EXTRA_VERSION@")
+
+/**
+ * BIRB_VERSION:
+ *
+ * The full version number for the version of Birb that was compiled against.
+ *
+ * Since: 0.1.0
+ */
+#define BIRB_VERSION ("@BIRB_VERSION@")
+
+#endif /* BIRB_VERSION_CONSTS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/birb/meson.build Sun Dec 10 05:10:13 2023 -0600
@@ -0,0 +1,117 @@
+BIRB_SOURCES = [
+ 'birbqueuedoutputstream.c',
+ 'birbversion.c',
+]
+
+BIRB_HEADERS = [
+ 'birbqueuedoutputstream.h',
+ 'birbversion.h',
+]
+
+BIRB_BUILT_HEADERS = []
+BIRB_GENERATED_SOURCES = []
+
+###############################################################################
+# birbversionconsts.h
+###############################################################################
+birb_version_consts_h = configure_file(
+ input : 'birbversionconsts.h.in',
+ output : 'birbversionconsts.h',
+ configuration : version_config,
+ install : true,
+ install_dir : get_option('includedir') / 'birb-1.0' / 'birb')
+BIRB_BUILT_HEADERS += birb_version_consts_h
+
+###############################################################################
+# Single Header
+###############################################################################
+BIRB_H_INCLUDES = []
+foreach header : BIRB_HEADERS
+ BIRB_H_INCLUDES += f'#include <birb/@header@>'
+endforeach
+
+header_config = configuration_data()
+header_config.set('BIRB_H_INCLUDES', '\n'.join(BIRB_H_INCLUDES))
+birb_h = configure_file(
+ input : 'birb.h.in',
+ output : 'birb.h',
+ configuration : header_config,
+ install : true,
+ install_dir : get_option('includedir') / 'birb-1.0')
+
+BIRB_BUILT_HEADERS += birb_h
+
+###############################################################################
+# Enums
+###############################################################################
+BIRB_ENUM_HEADERS = [
+ 'birbqueuedoutputstream.h',
+]
+
+birb_enums = gnome.mkenums_simple(
+ 'birbenums',
+ sources : BIRB_ENUM_HEADERS,
+ install_header : true,
+ install_dir : get_option('includedir') / 'birb-1.0' / 'birb')
+
+BIRB_GENERATED_SOURCES += birb_enums[0]
+BIRB_BUILT_HEADERS += birb_enums[1]
+
+###############################################################################
+# Library Target
+###############################################################################
+birb_inc = include_directories('.')
+
+birb_lib = library('birb',
+ BIRB_SOURCES + BIRB_HEADERS + BIRB_GENERATED_SOURCES + BIRB_BUILT_HEADERS,
+ c_args : ['-DBIRB_COMPILATION', '-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="Xeme"'],
+ gnu_symbol_visibility : 'hidden',
+ dependencies : [gio_dep, glib_dep, gobject_dep],
+ include_directories : [toplevel_inc, birb_inc],
+ install : true)
+
+install_headers(
+ BIRB_HEADERS,
+ subdir : 'birb-1.0/birb')
+
+pkgconfig.generate(
+ birb_lib,
+ name : 'birb',
+ description : 'A library of GLib utilities',
+ filebase : 'birb',
+ subdirs : 'birb-1.0',
+ libraries : [gio_dep, glib_dep, gobject_dep])
+
+###############################################################################
+# GObject Introspection
+###############################################################################
+if get_option('introspection')
+ birb_gir = gnome.generate_gir(birb_lib,
+ sources : BIRB_SOURCES + BIRB_HEADERS,
+ includes : ['Gio-2.0', 'GObject-2.0'],
+ header : 'birb.h',
+ namespace : 'Birb',
+ symbol_prefix : 'birb',
+ nsversion : '1.0',
+ install : true,
+ export_packages : ['birb'],
+ extra_args : ['--quiet', '-DBIRB_COMPILATION'])
+ BIRB_GENERATED_SOURCES += birb_gir
+endif
+
+###############################################################################
+# Library Dependency Object
+###############################################################################
+birb_dep = declare_dependency(
+ dependencies : [gio_dep, glib_dep, gobject_dep],
+ include_directories : [toplevel_inc, birb_inc],
+ link_with : birb_lib,
+ sources : BIRB_BUILT_HEADERS)
+
+meson.override_dependency('birb', birb_dep)
+
+###############################################################################
+# Sub Directories
+###############################################################################
+subdir('reference')
+subdir('tests')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/birb/reference/birb.toml.in Sun Dec 10 05:10:13 2023 -0600
@@ -0,0 +1,41 @@
+[library]
+version = "@BIRB_VERSION@"
+browse_url = "https://keep.imfreedom.org/birb/birb/"
+repository_url = "https://keep.imfreedom.org/birb/birb/"
+website_url = "https://keep.imfreedom.org/birb/birb/"
+authors = "Birb Developers"
+logo_url = ""
+license = "LGPL-2.1-or-later"
+description = "A library of GLib utilities"
+dependencies = [ "Gio-2.0", "GLib-2.0", "GObject-2.0" ]
+devhelp = true
+search_index = true
+
+ [dependencies."Gio-2.0"]
+ name = "Gio"
+ description = "Stream based io library."
+ docs_url = "https://docs.gtk.org/gio/"
+
+ [dependencies."GLib-2.0"]
+ name = "GLib"
+ description = "General-purpose, portable utility library."
+ docs_url = "https://docs.gtk.org/glib/"
+
+ [dependencies."GObject-2.0"]
+ name = "GObject"
+ description = "The base type system library."
+ docs_url = "https://docs.gtk.org/gobject/"
+
+[theme]
+name = "basic"
+show_index_summary = true
+show_class_hierarchy = true
+
+[source-location]
+base_url = "https://keep.imfreedom.org/birb/birb/file/default/"
+
+[extra]
+# The same order will be used when generating the index
+content_files = []
+content_images = []
+urlmap_file = "urlmap.js"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/birb/reference/meson.build Sun Dec 10 05:10:13 2023 -0600
@@ -0,0 +1,34 @@
+if not get_option('doc')
+ subdir_done()
+endif
+
+birb_doc_content_files = []
+
+birb_gidocgen_toml = configure_file(
+ input : 'birb.toml.in',
+ output : 'birb.toml',
+ configuration : version_config,
+ install : true,
+ install_dir : docs_dir / 'birb')
+
+birb_doc = custom_target('birb-doc',
+ input : [ birb_gidocgen_toml, birb_gir[0] ],
+ output : 'birb',
+ command : [
+ gidocgen,
+ 'generate',
+ '--quiet',
+ '--fatal-warnings',
+ '--config=@INPUT0@',
+ '--output-dir=@OUTPUT@',
+ '--no-namespace-dir',
+ '--content-dir=@0@'.format(meson.current_source_dir()),
+ '@INPUT1@'
+ ],
+ depend_files : [ birb_doc_content_files ],
+ build_by_default : true,
+ install : true,
+ install_dir : docs_dir,
+)
+
+doc_targets += birb_doc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/birb/reference/urlmap.js Sun Dec 10 05:10:13 2023 -0600
@@ -0,0 +1,9 @@
+// SPDX-FileCopyrightText: 2021 GNOME Foundation
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+// A map between namespaces and base URLs for their online documentation
+baseURLs = [
+ [ 'Gio', 'https://docs.gtk.org/gio/' ],
+ [ 'GLib', 'https://docs.gtk.org/glib/' ],
+ [ 'GObject', 'https://docs.gtk.org/gobject/' ],
+]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/birb/tests/meson.build Sun Dec 10 05:10:13 2023 -0600
@@ -0,0 +1,10 @@
+PROGRAMS = [
+ 'queued_output_stream',
+]
+
+foreach PROGRAM : PROGRAMS
+ e = executable(f'test_@PROGRAM@', f'test_@PROGRAM@.c',
+ dependencies : [birb_dep])
+
+ test(PROGRAM, e)
+endforeach
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/birb/tests/test_queued_output_stream.c Sun Dec 10 05:10:13 2023 -0600
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2023 Birb Developers
+ *
+ * Birb is the legal property of its developers, whose names are too
+ * numerous to list here. Please refer to the AUTHORS file distributed
+ * with this source distribution
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include <glib.h>
+#include <string.h>
+
+#include <birb.h>
+
+/* These values are used in all of the push_bytes tests. */
+static const gsize test_bytes_data_len = 5;
+static const guint8 test_bytes_data[] = "12345";
+
+static const gsize test_bytes_data_len2 = 4;
+static const guint8 test_bytes_data2[] = "6789";
+
+static const gsize test_bytes_data_len3 = 12;
+static const guint8 test_bytes_data3[] = "101112131415";
+
+/******************************************************************************
+ * _new test
+ *****************************************************************************/
+static void
+test_queued_output_stream_new(void) {
+ GError *error = NULL;
+ GOutputStream *output = NULL;
+ GOutputStream *queued = NULL;
+ gboolean ret = FALSE;
+
+ output = g_memory_output_stream_new_resizable();
+ g_assert_true(G_IS_MEMORY_OUTPUT_STREAM(output));
+
+ queued = birb_queued_output_stream_new(output);
+ g_assert_true(BIRB_IS_QUEUED_OUTPUT_STREAM(queued));
+
+ ret = g_output_stream_close(G_OUTPUT_STREAM(queued), NULL, &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+
+ g_clear_object(&queued);
+ g_clear_object(&output);
+}
+
+/******************************************************************************
+ * push_bytes_async_single test
+ *****************************************************************************/
+static void
+test_queued_output_stream_push_bytes_async_single_cb(GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ BirbQueuedOutputStream *queued = BIRB_QUEUED_OUTPUT_STREAM(source);
+ GError *error = NULL;
+ gboolean ret = FALSE;
+ int *counter = user_data;
+
+ ret = birb_queued_output_stream_push_bytes_finish(queued, res, &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+
+ *counter = *counter + 1;
+}
+
+static void
+test_queued_output_stream_push_bytes_async_single(void) {
+ GBytes *bytes = NULL;
+ GError *error = NULL;
+ GOutputStream *output = NULL;
+ GOutputStream *queued = NULL;
+ gboolean ret = FALSE;
+ int counter = 0;
+
+ output = g_memory_output_stream_new_resizable();
+ g_assert_true(G_IS_MEMORY_OUTPUT_STREAM(output));
+
+ queued = birb_queued_output_stream_new(output);
+ g_assert_true(BIRB_IS_QUEUED_OUTPUT_STREAM(queued));
+
+ bytes = g_bytes_new_static(test_bytes_data, test_bytes_data_len);
+ birb_queued_output_stream_push_bytes_async(BIRB_QUEUED_OUTPUT_STREAM(queued),
+ bytes,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ test_queued_output_stream_push_bytes_async_single_cb,
+ &counter);
+ g_clear_pointer(&bytes, g_bytes_unref);
+
+ while(counter < 1) {
+ g_main_context_iteration(NULL, TRUE);
+ }
+
+ g_assert_cmpmem(g_memory_output_stream_get_data(G_MEMORY_OUTPUT_STREAM(output)),
+ g_memory_output_stream_get_data_size(G_MEMORY_OUTPUT_STREAM(output)),
+ test_bytes_data,
+ test_bytes_data_len);
+
+ ret = g_output_stream_close(queued, NULL, &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+
+ g_clear_object(&queued);
+ g_clear_object(&output);
+}
+
+/******************************************************************************
+ * push_bytes_async_multiple test
+ *****************************************************************************/
+static void
+test_queued_output_stream_push_bytes_async_multiple_cb(GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ BirbQueuedOutputStream *queued = BIRB_QUEUED_OUTPUT_STREAM(source);
+ GError *err = NULL;
+ gboolean ret = FALSE;
+ int *counter = user_data;
+
+ ret = birb_queued_output_stream_push_bytes_finish(queued, res, &err);
+ g_assert_no_error(err);
+ g_assert_true(ret);
+
+ *counter = *counter - 1;
+}
+
+static void
+test_queued_output_stream_push_bytes_async_multiple(void) {
+ GBytes *bytes;
+ GError *err = NULL;
+ GOutputStream *output;
+ GOutputStream *queued;
+ gboolean ret = FALSE;
+ char *all_test_bytes_data;
+ int counter = 0;
+
+ output = g_memory_output_stream_new_resizable();
+ g_assert_true(G_IS_MEMORY_OUTPUT_STREAM(output));
+
+ queued = birb_queued_output_stream_new(output);
+ g_assert_true(BIRB_IS_QUEUED_OUTPUT_STREAM(queued));
+
+ bytes = g_bytes_new_static(test_bytes_data, test_bytes_data_len);
+ birb_queued_output_stream_push_bytes_async(BIRB_QUEUED_OUTPUT_STREAM(queued),
+ bytes,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ test_queued_output_stream_push_bytes_async_multiple_cb,
+ &counter);
+ g_bytes_unref(bytes);
+ counter++;
+
+ bytes = g_bytes_new_static(test_bytes_data2, test_bytes_data_len2);
+ birb_queued_output_stream_push_bytes_async(BIRB_QUEUED_OUTPUT_STREAM(queued),
+ bytes,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ test_queued_output_stream_push_bytes_async_multiple_cb,
+ &counter);
+ g_bytes_unref(bytes);
+ counter++;
+
+ bytes = g_bytes_new_static(test_bytes_data3, test_bytes_data_len3);
+ birb_queued_output_stream_push_bytes_async(BIRB_QUEUED_OUTPUT_STREAM(queued),
+ bytes,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ test_queued_output_stream_push_bytes_async_multiple_cb,
+ &counter);
+ g_bytes_unref(bytes);
+ counter++;
+
+ while(counter > 0) {
+ g_main_context_iteration(NULL, TRUE);
+ }
+
+ g_assert_cmpint(counter, ==, 0);
+
+ all_test_bytes_data = g_strconcat((const char *)test_bytes_data,
+ test_bytes_data2,
+ test_bytes_data3,
+ NULL);
+
+ g_assert_cmpmem(g_memory_output_stream_get_data(G_MEMORY_OUTPUT_STREAM(output)),
+ g_memory_output_stream_get_data_size(G_MEMORY_OUTPUT_STREAM(output)),
+ all_test_bytes_data,
+ strlen(all_test_bytes_data));
+
+ g_free(all_test_bytes_data);
+
+ ret = g_output_stream_close(queued, NULL, &err);
+ g_assert_no_error(err);
+ g_assert_true(ret);
+
+ g_clear_object(&queued);
+ g_clear_object(&output);
+}
+
+/******************************************************************************
+ * push_bytes_async_error test
+ *****************************************************************************/
+static void
+test_queued_output_stream_push_bytes_async_error_cb(GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ BirbQueuedOutputStream *queued = BIRB_QUEUED_OUTPUT_STREAM(source);
+ GError *error = NULL;
+ gboolean ret = FALSE;
+ int *counter = user_data;
+
+ ret = birb_queued_output_stream_push_bytes_finish(queued, res, &error);
+ g_assert_error(error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+ g_clear_error(&error);
+
+ g_assert_false(ret);
+
+ *counter = *counter - 1;
+}
+
+static void
+test_queued_output_stream_push_bytes_async_error(void) {
+ GBytes *bytes = NULL;
+ GCancellable *cancellable = NULL;
+ GError *error = NULL;
+ GOutputStream *output = NULL;
+ GOutputStream *queued = NULL;
+ gboolean ret = FALSE;
+ int counter = 0;
+
+ output = g_memory_output_stream_new_resizable();
+ g_assert_true(G_IS_MEMORY_OUTPUT_STREAM(output));
+
+ queued = birb_queued_output_stream_new(output);
+ g_assert_true(BIRB_IS_QUEUED_OUTPUT_STREAM(queued));
+
+ cancellable = g_cancellable_new();
+ g_assert_nonnull(cancellable);
+
+ g_cancellable_cancel(cancellable);
+ g_assert_true(g_cancellable_is_cancelled(cancellable));
+
+ /* bytes get's referenced by push_bytes_async so we can use it multiple
+ * times.
+ */
+ bytes = g_bytes_new_static(test_bytes_data, test_bytes_data_len);
+
+ birb_queued_output_stream_push_bytes_async(BIRB_QUEUED_OUTPUT_STREAM(queued),
+ bytes,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ test_queued_output_stream_push_bytes_async_error_cb,
+ &counter);
+ counter++;
+
+ birb_queued_output_stream_push_bytes_async(BIRB_QUEUED_OUTPUT_STREAM(queued),
+ bytes,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ test_queued_output_stream_push_bytes_async_error_cb,
+ &counter);
+ counter++;
+
+ birb_queued_output_stream_push_bytes_async(BIRB_QUEUED_OUTPUT_STREAM(queued),
+ bytes,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ test_queued_output_stream_push_bytes_async_error_cb,
+ &counter);
+ counter++;
+
+ g_bytes_unref(bytes);
+
+ while(counter > 0) {
+ g_main_context_iteration(NULL, TRUE);
+ }
+
+ g_assert_cmpint(counter, ==, 0);
+
+ g_assert_cmpmem(g_memory_output_stream_get_data(G_MEMORY_OUTPUT_STREAM(output)),
+ g_memory_output_stream_get_data_size(G_MEMORY_OUTPUT_STREAM(output)),
+ NULL,
+ 0);
+
+ ret = g_output_stream_close(queued, NULL, &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+
+ g_clear_object(&cancellable);
+ g_clear_object(&queued);
+ g_clear_object(&output);
+}
+
+/******************************************************************************
+ * Main
+ *****************************************************************************/
+int
+main(int argc, char **argv) {
+ g_test_init(&argc, &argv, NULL);
+
+ g_test_set_nonfatal_assertions();
+
+ g_test_add_func("/queued-output-stream/new",
+ test_queued_output_stream_new);
+ g_test_add_func("/queued-output-stream/push-bytes-async-single",
+ test_queued_output_stream_push_bytes_async_single);
+ g_test_add_func("/queued-output-stream/push-bytes-async-multiple",
+ test_queued_output_stream_push_bytes_async_multiple);
+ g_test_add_func("/queued-output-stream/push-bytes-async-error",
+ test_queued_output_stream_push_bytes_async_error);
+
+ return g_test_run();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/meson.build Sun Dec 10 05:10:13 2023 -0600
@@ -0,0 +1,105 @@
+project('birb', 'c',
+ version : '0.1.0',
+ meson_version : '>=1.0.0',
+ default_options : ['c_std=c17', 'warning_level=2'])
+
+toplevel_inc = include_directories('.')
+
+gnome = import('gnome')
+pkgconfig = import('pkgconfig')
+
+###############################################################################
+# Versioning
+###############################################################################
+parts = meson.project_version().split('-')
+if parts.length() > 1
+ extra = parts[1]
+else
+ extra = ''
+endif
+
+parts = parts[0].split('.')
+BIRB_MAJOR_VERSION = parts[0]
+BIRB_MINOR_VERSION = parts[1]
+BIRB_MICRO_VERSION = parts[2]
+BIRB_LIB_VERSION = f'@BIRB_MAJOR_VERSION@.@BIRB_MINOR_VERSION@.@BIRB_MICRO_VERSION@'
+
+version_config = configuration_data()
+version_config.set('BIRB_MAJOR_VERSION', BIRB_MAJOR_VERSION)
+version_config.set('BIRB_MINOR_VERSION', BIRB_MINOR_VERSION)
+version_config.set('BIRB_MICRO_VERSION', BIRB_MICRO_VERSION)
+version_config.set('BIRB_EXTRA_VERSION', extra)
+version_config.set('BIRB_VERSION', meson.project_version())
+
+###############################################################################
+# Dependencies
+###############################################################################
+glib_dep = dependency('glib-2.0', version : '>=2.76.0')
+gio_dep = dependency('gio-2.0')
+gobject_dep = dependency('gobject-2.0')
+
+add_project_arguments(
+ '-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_76',
+ '-DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_76',
+ language : 'c',)
+
+###############################################################################
+# Internationalization
+###############################################################################
+GETTEXT_PACKAGE = 'birb'
+LOCALE_DIR = get_option('prefix') / get_option('localedir')
+
+add_project_arguments(f'-DLOCALEDIR="@LOCALE_DIR@"', language : 'c')
+add_project_arguments(f'-DGETTEXT_PACKAGE="@GETTEXT_PACKAGE@"', language : 'c')
+
+###############################################################################
+# Documentation
+###############################################################################
+if get_option('doc') and not get_option('introspection')
+ error('Documentation requires GObject Introspection.')
+endif
+
+gidocgen_dep = dependency(
+ 'gi-docgen', version: '>= 2023.1',
+ fallback: ['gi-docgen', 'dummy_dep'],
+ required: get_option('doc')
+)
+
+gidocgen = find_program('gi-docgen', required : get_option('doc'))
+docs_dir = get_option('prefix') / get_option('datadir') / 'doc'
+doc_targets = []
+
+###############################################################################
+# Sub directories
+###############################################################################
+subdir('birb')
+subdir('po')
+
+###############################################################################
+# Custom Targets
+###############################################################################
+if meson.backend() == 'ninja'
+ run_target('turtles',
+ command : ['ninja', '-C', '@BUILD_ROOT@', 'birb-pot', 'all', 'test'])
+endif
+
+# This needs to be after all of the sub-directories have been processed.
+if get_option('doc')
+ alias_target('doc', doc_targets)
+endif
+
+###############################################################################
+# Summarize all the things!
+###############################################################################
+summary({
+ 'prefix': get_option('prefix'),
+ 'bindir': get_option('bindir'),
+ 'libdir': get_option('libdir'),
+ 'datadir': get_option('datadir'),
+}, section : 'Directories')
+
+summary({
+ 'documentation': get_option('doc'),
+ 'internationalization': get_option('nls'),
+ 'introspection': get_option('introspection'),
+}, section : 'Options')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/meson_options.txt Sun Dec 10 05:10:13 2023 -0600
@@ -0,0 +1,17 @@
+option(
+ 'doc',
+ type : 'boolean', value : true, yield : true,
+ description : 'build documentation with gi-docgen'
+)
+
+option(
+ 'introspection',
+ type : 'boolean', value : true, yield : true,
+ description : 'Whether or not to build a GObject Introspection type library'
+)
+
+option(
+ 'nls',
+ type : 'boolean', value : true, yield : true,
+ description : 'Install translation files'
+)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/po/meson.build Sun Dec 10 05:10:13 2023 -0600
@@ -0,0 +1,11 @@
+if not get_option('nls')
+ summary('translations',
+ 'You have disabled installation of translations which means ' +
+ 'English will be the only available language.',
+ section : 'Warnings')
+
+ subdir_done()
+endif
+
+i18n = import('i18n')
+i18n.gettext(GETTEXT_PACKAGE, preset: 'glib')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/subprojects/gi-docgen.wrap Sun Dec 10 05:10:13 2023 -0600
@@ -0,0 +1,5 @@
+[wrap-file]
+directory = gi-docgen-2023.1
+source_url = https://download.gnome.org/sources/gi-docgen/2023/gi-docgen-2023.1.tar.xz
+source_filename = gi-docgen-2023.1.tar.xz
+source_hash = a9a687c1b7c4a4139a214bd451e01ca86131a3161f68aa3e07325b06002bbfb6