diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 95273946..c1b98e17 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,7 +1,7 @@ image: registry.freedesktop.org/pipewire/pipewire/fedora:31 variables: - DEPENDENCIES: gtk-doc gobject-introspection-devel + DEPENDENCIES: gtk-doc gobject-introspection-devel cmake gcc-c++ build: before_script: diff --git a/lib/meson.build b/lib/meson.build index 8f7c8329..0e49d4bf 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -1 +1,2 @@ +subdir('wptoml') subdir('wp') diff --git a/lib/wptoml/array.cpp b/lib/wptoml/array.cpp new file mode 100644 index 00000000..a907d262 --- /dev/null +++ b/lib/wptoml/array.cpp @@ -0,0 +1,178 @@ +/* WirePlumber + * + * Copyright © 2019 Collabora Ltd. + * @author Julian Bouzas + * + * SPDX-License-Identifier: MIT + */ + +/* C++ STL */ +#include + +/* CPPTOML */ +#include + +/* TOML */ +#include "private.h" +#include "array.h" + +namespace wp { +namespace toml { + +/* The Array class */ +class Array { + public: + /* The data of the array */ + using Data = std::shared_ptr; + + /* The for each function for values */ + template + using ForEachValueFunction = std::function; + + /* The for each function for arrays of values */ + using ForEachArrayFunction = std::function; + + /* Constructor */ + Array(Data data) : + data_(std::move(data)) { + } + + /* Destructor */ + virtual ~Array() { + } + + /* Calls the given callback for values */ + template + void ForEachValue(ForEachValueFunction func, gpointer user_data) const { + for (const std::shared_ptr>& v : data_->array_of()) { + if (v) { + const T val = v->get(); + func(&val, user_data); + } else { + func(nullptr, user_data); + } + } + } + + /* Calls the given callback for arrays of values */ + void ForEachArray(ForEachArrayFunction func, gpointer user_data) const { + for (const Data& val : data_->nested_array()) { + gconstpointer d = static_cast(&val); + g_autoptr (WpTomlArray) a = wp_toml_array_new(d); + func(a, user_data); + } + } + + private: + /* Copy Constructor */ + Array(const Array&) = delete; + + /* Move Constructor */ + Array(Array &&) = delete; + + /* Copy-Assign Constructor */ + Array& operator=(const Array&) = delete; + + /* Move-Assign Constructr */ + Array& operator=(Array &&) = delete; + + private: + /* The data array */ + const Data data_; +}; + +} /* namespace toml */ +} /* namespace wp */ + +struct _WpTomlArray +{ + const wp::toml::Array *data; +}; + +G_DEFINE_BOXED_TYPE(WpTomlArray, wp_toml_array, wp_toml_array_ref, + wp_toml_array_unref) + +WpTomlArray * +wp_toml_array_new (gconstpointer data) +{ + g_return_val_if_fail (data, nullptr); + + try { + g_autoptr(WpTomlArray) self = g_rc_box_new (WpTomlArray); + + /* Set the data */ + const wp::toml::Array::Data *d = + static_cast(data); + self->data = new wp::toml::Array {*d}; + + return static_cast(g_steal_pointer (&self)); + } catch (std::bad_alloc& ba) { + g_critical ("Could not create WpTomlArray: %s", ba.what()); + return nullptr; + } catch (...) { + g_critical ("Could not create WpTomlArray"); + return nullptr; + } +} + +WpTomlArray * +wp_toml_array_ref (WpTomlArray * self) +{ + return static_cast( + g_rc_box_acquire (static_cast(self))); +} + +void +wp_toml_array_unref (WpTomlArray * self) +{ + static void (*free_func)(gpointer) = [](gpointer p){ + WpTomlArray *a = static_cast(p); + delete a->data; + }; + g_rc_box_release_full (self, free_func); +} + +void +wp_toml_array_for_each_boolean (const WpTomlArray *self, + WpTomlArrayForEachBoolFunc func, gpointer user_data) +{ + self->data->ForEachValue([&](const bool *v, gpointer d){ + if (v) { + const gboolean b = *v ? TRUE : FALSE; + func(&b, d); + } else { + func(nullptr, d); + } + }, user_data); +} + +void +wp_toml_array_for_each_int64 (const WpTomlArray *self, + WpTomlArrayForEachInt64Func func, gpointer user_data) +{ + self->data->ForEachValue(func, user_data); +} + +void +wp_toml_array_for_each_double (const WpTomlArray *self, + WpTomlArrayForEachDoubleFunc func, gpointer user_data) +{ + self->data->ForEachValue(func, user_data); +} + +void +wp_toml_array_for_each_string (const WpTomlArray *self, + WpTomlArrayForEachStringFunc func, gpointer user_data) +{ + self->data->ForEachValue([&](const std::string *v, gpointer d){ + func(v ? v->c_str() : nullptr, d); + }, user_data); +} + +void +wp_toml_array_for_each_array (const WpTomlArray *self, + WpTomlArrayForEachArrayFunc func, gpointer user_data) +{ + self->data->ForEachArray(func, user_data); +} + diff --git a/lib/wptoml/array.h b/lib/wptoml/array.h new file mode 100644 index 00000000..a75ac6e5 --- /dev/null +++ b/lib/wptoml/array.h @@ -0,0 +1,44 @@ +/* WirePlumber + * + * Copyright © 2019 Collabora Ltd. + * @author Julian Bouzas + * + * SPDX-License-Identifier: MIT + */ + +#ifndef __WP_TOML_ARRAY_H__ +#define __WP_TOML_ARRAY_H__ + +#include + +#include + +G_BEGIN_DECLS + +/* WpTomlArray */ +GType wp_toml_array_get_type (void); +typedef struct _WpTomlArray WpTomlArray; +WpTomlArray * wp_toml_array_ref (WpTomlArray * self); +void wp_toml_array_unref (WpTomlArray * self); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (WpTomlArray, wp_toml_array_unref) + +/* API */ +typedef void (*WpTomlArrayForEachBoolFunc)(const gboolean *, gpointer); +void wp_toml_array_for_each_boolean (const WpTomlArray *self, + WpTomlArrayForEachBoolFunc func, gpointer user_data); +typedef void (*WpTomlArrayForEachInt64Func)(const int64_t *, gpointer); +void wp_toml_array_for_each_int64 (const WpTomlArray *self, + WpTomlArrayForEachInt64Func func, gpointer user_data); +typedef void (*WpTomlArrayForEachDoubleFunc)(const double *, gpointer); +void wp_toml_array_for_each_double (const WpTomlArray *self, + WpTomlArrayForEachDoubleFunc func, gpointer user_data); +typedef void (*WpTomlArrayForEachStringFunc)(const char *, gpointer); +void wp_toml_array_for_each_string (const WpTomlArray *self, + WpTomlArrayForEachStringFunc func, gpointer user_data); +typedef void (*WpTomlArrayForEachArrayFunc)(WpTomlArray *, gpointer); +void wp_toml_array_for_each_array (const WpTomlArray *self, + WpTomlArrayForEachArrayFunc func, gpointer user_data); + +G_END_DECLS + +#endif diff --git a/lib/wptoml/file.cpp b/lib/wptoml/file.cpp new file mode 100644 index 00000000..d39e468b --- /dev/null +++ b/lib/wptoml/file.cpp @@ -0,0 +1,80 @@ +/* WirePlumber + * + * Copyright © 2019 Collabora Ltd. + * @author Julian Bouzas + * + * SPDX-License-Identifier: MIT + */ + +/* CPPTOML */ +#include + +/* TOML */ +#include "private.h" +#include "file.h" + +struct _WpTomlFile +{ + char *name; + WpTomlTable *table; +}; + +G_DEFINE_BOXED_TYPE(WpTomlFile, wp_toml_file, wp_toml_file_ref, + wp_toml_file_unref) + +WpTomlFile * +wp_toml_file_new (const char *name) +{ + g_return_val_if_fail (name, nullptr); + + try { + g_autoptr (WpTomlFile) self = g_rc_box_new (WpTomlFile); + + /* Set the name */ + self->name = g_strdup (name); + + /* Set the table by parsing the file */ + std::shared_ptr data = cpptoml::parse_file(name); + self->table = wp_toml_table_new (static_cast(&data)); + + return static_cast(g_steal_pointer (&self)); + } catch (std::bad_alloc& ba) { + g_critical ("Could not create WpTomlFile from '%s': %s", name, ba.what()); + return nullptr; + } catch (...) { + g_critical ("Could not create WpTomlFile from '%s'", name); + return nullptr; + } +} + +WpTomlFile * +wp_toml_file_ref (WpTomlFile * self) +{ + return static_cast( + g_rc_box_acquire (static_cast(self))); +} + +void +wp_toml_file_unref (WpTomlFile * self) +{ + static void (*free_func)(gpointer) = [](gpointer p){ + WpTomlFile *f = static_cast(p); + g_free (f->name); + f->name = nullptr; + wp_toml_table_unref (f->table); + f->table = nullptr; + }; + g_rc_box_release_full (self, free_func); +} + +const char * +wp_toml_file_get_name (const WpTomlFile *self) +{ + return self->name; +} + +WpTomlTable * +wp_toml_file_get_table (const WpTomlFile *self) +{ + return wp_toml_table_ref (self->table); +} diff --git a/lib/wptoml/file.h b/lib/wptoml/file.h new file mode 100644 index 00000000..753d94b8 --- /dev/null +++ b/lib/wptoml/file.h @@ -0,0 +1,32 @@ +/* WirePlumber + * + * Copyright © 2019 Collabora Ltd. + * @author Julian Bouzas + * + * SPDX-License-Identifier: MIT + */ + +#ifndef __WP_TOML_FILE_H__ +#define __WP_TOML_FILE_H__ + +#include + +#include "table.h" + +G_BEGIN_DECLS + +/* WpTomlFile */ +GType wp_toml_file_get_type (void); +typedef struct _WpTomlFile WpTomlFile; +WpTomlFile *wp_toml_file_new (const char *name); +WpTomlFile * wp_toml_file_ref (WpTomlFile * self); +void wp_toml_file_unref (WpTomlFile * self); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (WpTomlFile, wp_toml_file_unref) + +/* API */ +const char *wp_toml_file_get_name (const WpTomlFile *self); +WpTomlTable *wp_toml_file_get_table (const WpTomlFile *self); + +G_END_DECLS + +#endif diff --git a/lib/wptoml/meson.build b/lib/wptoml/meson.build new file mode 100644 index 00000000..7d04e901 --- /dev/null +++ b/lib/wptoml/meson.build @@ -0,0 +1,30 @@ +wptoml_lib_sources = [ + 'array.cpp', + 'table.cpp', + 'file.cpp', +] + +wptoml_lib_headers = [ + 'wptoml.h', + 'array.h', + 'table.h', + 'file.h', +] + +wptoml_lib = static_library('wptoml-' + wireplumber_api_version, + wptoml_lib_sources, + cpp_args : [ + '-D_GNU_SOURCE', + '-DG_LOG_USE_STRUCTURED', + '-DG_LOG_DOMAIN="libwptoml"', + ], + install: false, + include_directories: wp_lib_include_dir, + dependencies : [gobject_dep, cpptoml_dep], +) + +wptoml_dep = declare_dependency( + link_with: wptoml_lib, + include_directories: wp_lib_include_dir, + dependencies: [gobject_dep] +) diff --git a/lib/wptoml/private.h b/lib/wptoml/private.h new file mode 100644 index 00000000..2272015a --- /dev/null +++ b/lib/wptoml/private.h @@ -0,0 +1,27 @@ +/* WirePlumber + * + * Copyright © 2019 Collabora Ltd. + * @author Julian Bouzas + * + * SPDX-License-Identifier: MIT + */ + +#ifndef __WP_TOML_PRIVATE_H__ +#define __WP_TOML_PRIVATE_H__ + +#include + +G_BEGIN_DECLS + +/* Forward declaration */ +struct _WpTomlArray; +typedef struct _WpTomlArray WpTomlArray; +struct _WpTomlTable; +typedef struct _WpTomlTable WpTomlTable; + +WpTomlArray * wp_toml_array_new (gconstpointer data); +WpTomlTable * wp_toml_table_new (gconstpointer data); + +G_END_DECLS + +#endif diff --git a/lib/wptoml/table.cpp b/lib/wptoml/table.cpp new file mode 100644 index 00000000..3224826b --- /dev/null +++ b/lib/wptoml/table.cpp @@ -0,0 +1,461 @@ +/* WirePlumber + * + * Copyright © 2019 Collabora Ltd. + * @author Julian Bouzas + * + * SPDX-License-Identifier: MIT + */ + +/* C++ STL */ +#include + +/* CPPTOML */ +#include + +/* TOML */ +#include "private.h" +#include "table.h" + +namespace wp { +namespace toml { + +/* The Table class */ +class Table { + public: + /* The data of the array */ + using Data = std::shared_ptr; + + /* Constructor */ + Table(Data data) : + data_(std::move(data)) { + } + + /* Destructor */ + virtual ~Table() { + } + + /* Determines if this table contains the given key */ + bool Contains(const std::string& key) const { + return data_->contains(key); + } + + /* Gets a value */ + template + bool GetValue(const std::string& key, T *val, bool qualified) const { + g_return_val_if_fail (val, false); + const cpptoml::option opt = + qualified ? data_->get_qualified_as(key) : data_->get_as(key); + if (!opt) + return false; + *val = *opt; + return true; + } + + /* Gets an array of values */ + std::shared_ptr GetArray(const std::string& key, + bool qualified) const { + return qualified ? data_->get_array_qualified(key) : data_->get_array(key); + } + + /* Gets an array of tables */ + std::shared_ptr GetTableArray( + const std::string& key, bool qualified) const { + return qualified ? data_->get_table_array_qualified(key) : + data_->get_table_array(key); + } + + /* Gets a nested table */ + Data GetTable(const std::string& key, bool qualified) const { + return qualified ? data_->get_table_qualified(key) : data_->get_table(key); + } + + private: + /* Copy Constructor */ + Table(const Table&) = delete; + + /* Move Constructor */ + Table(Table &&) = delete; + + /* Copy-Assign Constructor */ + Table& operator=(const Table&) = delete; + + /* Move-Assign Constructr */ + Table& operator=(Table &&) = delete; + + private: + /* The data table */ + const Data data_; +}; + +/* The Array Table class */ +class TableArray { + public: + /* The data of the array */ + using Data = std::shared_ptr; + + /* The for each function for arrays of tables */ + using ForEachFunction = std::function; + + /* Constructor */ + TableArray(Data data) : + data_(std::move(data)) { + } + + /* Destructor */ + virtual ~TableArray() { + } + + /* Calls the given callback for arrays of values */ + void ForEach(ForEachFunction func, gpointer user_data) const { + for (const auto& table : *data_) { + gconstpointer p = static_cast(&table); + g_autoptr (WpTomlTable) t = wp_toml_table_new(p); + func(t, user_data); + } + } + + private: + /* Copy Constructor */ + TableArray(const TableArray&) = delete; + + /* Move Constructor */ + TableArray(TableArray &&) = delete; + + /* Copy-Assign Constructor */ + TableArray& operator=(const TableArray&) = delete; + + /* Move-Assign Constructr */ + TableArray& operator=(TableArray &&) = delete; + + private: + /* The data array */ + const Data data_; +}; + +} /* namespace toml */ +} /* namespace wp */ + +struct _WpTomlTable +{ + wp::toml::Table *data; +}; + +G_DEFINE_BOXED_TYPE(WpTomlTable, wp_toml_table, wp_toml_table_ref, + wp_toml_table_unref) + +struct _WpTomlTableArray +{ + const wp::toml::TableArray *data; +}; + +G_DEFINE_BOXED_TYPE(WpTomlTableArray, wp_toml_table_array, + wp_toml_table_array_ref, wp_toml_table_array_unref) + +WpTomlTable * +wp_toml_table_new (gconstpointer data) +{ + g_return_val_if_fail (data, nullptr); + + try { + g_autoptr (WpTomlTable) self = g_rc_box_new (WpTomlTable); + + /* Set the data */ + const wp::toml::Table::Data *d = + static_cast(data); + self->data = new wp::toml::Table {*d}; + + return static_cast(g_steal_pointer (&self)); + } catch (std::bad_alloc& ba) { + g_critical ("Could not create WpTomlTable: %s", ba.what()); + return nullptr; + } catch (...) { + g_critical ("Could not create WpTomlTable"); + return nullptr; + } +} + +WpTomlTable * +wp_toml_table_ref (WpTomlTable * self) +{ + return static_cast( + g_rc_box_acquire (static_cast(self))); +} + +void +wp_toml_table_unref (WpTomlTable * self) +{ + static void (*free_func)(gpointer) = [](gpointer p){ + WpTomlTable *t = static_cast(p); + delete t->data; + }; + g_rc_box_release_full (self, free_func); +} + +static WpTomlTableArray * +wp_toml_table_array_new (gconstpointer data) +{ + g_return_val_if_fail (data, nullptr); + + try { + g_autoptr (WpTomlTableArray) self = g_rc_box_new (WpTomlTableArray); + + /* Set the data */ + const wp::toml::TableArray::Data *d = + static_cast(data); + self->data = new wp::toml::TableArray {*d}; + + return static_cast(g_steal_pointer (&self)); + } catch (std::bad_alloc& ba) { + g_critical ("Could not create WpTomlTableArray: %s", ba.what()); + return nullptr; + } catch (...) { + g_critical ("Could not create WpTomlTableArray"); + return nullptr; + } +} + +WpTomlTableArray * +wp_toml_table_array_ref (WpTomlTableArray * self) +{ + return static_cast( + g_rc_box_acquire (static_cast(self))); +} + +void +wp_toml_table_array_unref (WpTomlTableArray * self) +{ + static void (*free_func)(gpointer) = [](gpointer p){ + WpTomlTableArray *at = static_cast(p); + delete at->data; + }; + g_rc_box_release_full (self, free_func); +} + +gboolean +wp_toml_table_contains (const WpTomlTable *self, const char *key) { + return self->data->Contains(key); +} + +gboolean +wp_toml_table_get_boolean (const WpTomlTable *self, const char *key, + gboolean *val) +{ + bool v; + if (!self->data->GetValue(key, &v, false)) + return false; + *val = v ? TRUE : FALSE; + return true; +} + +gboolean +wp_toml_table_get_qualified_boolean (const WpTomlTable *self, const char *key, + gboolean *val) +{ + bool v; + if (!self->data->GetValue(key, &v, true)) + return false; + *val = v ? TRUE : FALSE; + return true; +} + +gboolean +wp_toml_table_get_int8 (const WpTomlTable *self, const char *key, int8_t *val) +{ + return self->data->GetValue(key, val, false); +} + +gboolean +wp_toml_table_get_qualified_int8 (const WpTomlTable *self, const char *key, + int8_t *val) +{ + return self->data->GetValue(key, val, true); +} + +gboolean +wp_toml_table_get_uint8 (const WpTomlTable *self, const char *key, uint8_t *val) +{ + return self->data->GetValue(key, val, false); +} + +gboolean +wp_toml_table_get_qualified_uint8 (const WpTomlTable *self, const char *key, + uint8_t *val) +{ + return self->data->GetValue(key, val, true); +} + +gboolean +wp_toml_table_get_int16 (const WpTomlTable *self, const char *key, int16_t *val) +{ + return self->data->GetValue(key, val, false); +} + +gboolean +wp_toml_table_get_qualified_int16 (const WpTomlTable *self, const char *key, + int16_t *val) +{ + return self->data->GetValue(key, val, true); +} + +gboolean +wp_toml_table_get_uint16 (const WpTomlTable *self, const char *key, + uint16_t *val) +{ + return self->data->GetValue(key, val, false); +} + +gboolean +wp_toml_table_get_qualified_uint16 (const WpTomlTable *self, const char *key, + uint16_t *val) +{ + return self->data->GetValue(key, val, true); +} + +gboolean +wp_toml_table_get_int32 (const WpTomlTable *self, const char *key, int32_t *val) +{ + return self->data->GetValue(key, val, false); +} + +gboolean +wp_toml_table_get_qualified_int32 (const WpTomlTable *self, const char *key, + int32_t *val) +{ + return self->data->GetValue(key, val, true); +} + +gboolean +wp_toml_table_get_uint32 (const WpTomlTable *self, const char *key, + uint32_t *val) +{ + return self->data->GetValue(key, val, false); +} + +gboolean +wp_toml_table_get_qualified_uint32 (const WpTomlTable *self, const char *key, + uint32_t *val) +{ + return self->data->GetValue(key, val, true); +} + +gboolean +wp_toml_table_get_int64 (const WpTomlTable *self, const char *key, int64_t *val) +{ + return self->data->GetValue(key, val, false); +} + +gboolean +wp_toml_table_get_qualified_int64 (const WpTomlTable *self, const char *key, + int64_t *val) +{ + return self->data->GetValue(key, val, true); +} + +gboolean +wp_toml_table_get_uint64 (const WpTomlTable *self, const char *key, + uint64_t *val) +{ + return self->data->GetValue(key, val, false); +} + +gboolean +wp_toml_table_get_qualified_uint64 (const WpTomlTable *self, const char *key, + uint64_t *val) +{ + return self->data->GetValue(key, val, true); +} + +gboolean +wp_toml_table_get_double (const WpTomlTable *self, const char *key, double *val) +{ + return self->data->GetValue(key, val, false); +} + +gboolean +wp_toml_table_get_qualified_double (const WpTomlTable *self, const char *key, + double *val) +{ + return self->data->GetValue(key, val, true); +} + +char * +wp_toml_table_get_string (const WpTomlTable *self, const char *key) +{ + std::string str; + return self->data->GetValue(key, &str, false) ? + g_strdup (str.c_str()) : nullptr; +} + +char * +wp_toml_table_get_qualified_string (const WpTomlTable *self, const char *key) +{ + std::string str; + return self->data->GetValue(key, &str, true) ? + g_strdup (str.c_str()) : nullptr; +} + +WpTomlArray * +wp_toml_table_get_array (const WpTomlTable *self, const char *key) +{ + std::shared_ptr array = + self->data->GetArray(key, false); + return array ? + wp_toml_array_new (static_cast(&array)) : + nullptr; +} + +WpTomlArray * +wp_toml_table_get_qualified_array (const WpTomlTable *self, const char *key) +{ + std::shared_ptr array = + self->data->GetArray(key, true); + return array ? + wp_toml_array_new (static_cast(&array)) : + nullptr; +} + +WpTomlTable * +wp_toml_table_get_table (const WpTomlTable *self, const char *key) +{ + wp::toml::Table::Data table = self->data->GetTable(key, false); + return table ? + wp_toml_table_new (static_cast(&table)) : + nullptr; +} + +WpTomlTable * +wp_toml_table_get_qualified_table (const WpTomlTable *self, const char *key) +{ + wp::toml::Table::Data table = self->data->GetTable(key, true); + return table ? + wp_toml_table_new (static_cast(&table)) : + nullptr; +} + +WpTomlTableArray * +wp_toml_table_get_array_table (const WpTomlTable *self, const char *key) +{ + std::shared_ptr array_table = + self->data->GetTableArray(key, false); + return array_table ? + wp_toml_table_array_new (static_cast(&array_table)) : + nullptr; +} + +WpTomlTableArray * +wp_toml_table_get_qualified_array_table (const WpTomlTable *self, + const char *key) +{ + std::shared_ptr array_table = + self->data->GetTableArray(key, true); + return array_table ? + wp_toml_table_array_new (static_cast(&array_table)) : + nullptr; +} + +void +wp_toml_table_array_for_each (const WpTomlTableArray *self, + WpTomlTableArrayForEachFunc func, gpointer user_data) +{ + self->data->ForEach(func, user_data); +} diff --git a/lib/wptoml/table.h b/lib/wptoml/table.h new file mode 100644 index 00000000..a62367fc --- /dev/null +++ b/lib/wptoml/table.h @@ -0,0 +1,95 @@ +/* WirePlumber + * + * Copyright © 2019 Collabora Ltd. + * @author Julian Bouzas + * + * SPDX-License-Identifier: MIT + */ + +#ifndef __WP_TOML_TABLE_H__ +#define __WP_TOML_TABLE_H__ + +#include + +#include + +#include "array.h" + +G_BEGIN_DECLS + +/* WpTomlTable */ +GType wp_toml_table_get_type (void); +typedef struct _WpTomlTable WpTomlTable; +WpTomlTable * wp_toml_table_ref (WpTomlTable * self); +void wp_toml_table_unref (WpTomlTable * self); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (WpTomlTable, wp_toml_table_unref) + +/* WpTomlTableArray */ +GType wp_toml_table_array_get_type (void); +typedef struct _WpTomlTableArray WpTomlTableArray; +WpTomlTableArray * wp_toml_table_array_ref (WpTomlTableArray * self); +void wp_toml_table_array_unref (WpTomlTableArray * self); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (WpTomlTableArray, wp_toml_table_array_unref) + +/* API */ +gboolean wp_toml_table_contains (const WpTomlTable *self, const char *key); +gboolean wp_toml_table_get_boolean (const WpTomlTable *self, const char *key, + gboolean *val); +gboolean wp_toml_table_get_qualified_boolean (const WpTomlTable *self, + const char *key, gboolean *val); +gboolean wp_toml_table_get_int8 (const WpTomlTable *self, const char *key, + int8_t *val); +gboolean wp_toml_table_get_qualified_int8 (const WpTomlTable *self, + const char *key, int8_t *val); +gboolean wp_toml_table_get_uint8 (const WpTomlTable *self, const char *key, + uint8_t *val); +gboolean wp_toml_table_get_qualified_uint8 (const WpTomlTable *self, + const char *key, uint8_t *val); +gboolean wp_toml_table_get_int16 (const WpTomlTable *self, const char *key, + int16_t *val); +gboolean wp_toml_table_get_qualified_int16 (const WpTomlTable *self, + const char *key, int16_t *val); +gboolean wp_toml_table_get_uint16 (const WpTomlTable *self, const char *key, + uint16_t *val); +gboolean wp_toml_table_get_qualified_uint16 (const WpTomlTable *self, + const char *key, uint16_t *val); +gboolean wp_toml_table_get_int32 (const WpTomlTable *self, const char *key, + int32_t *val); +gboolean wp_toml_table_get_qualified_int32 (const WpTomlTable *self, + const char *key, int32_t *val); +gboolean wp_toml_table_get_uint32 (const WpTomlTable *self, const char *key, + uint32_t *val); +gboolean wp_toml_table_get_qualified_uint32 (const WpTomlTable *self, + const char *key, uint32_t *val); +gboolean wp_toml_table_get_int64 (const WpTomlTable *self, const char *key, + int64_t *val); +gboolean wp_toml_table_get_qualified_int64 (const WpTomlTable *self, + const char *key, int64_t *val); +gboolean wp_toml_table_get_uint64 (const WpTomlTable *self, const char *key, + uint64_t *val); +gboolean wp_toml_table_get_qualified_uint64 (const WpTomlTable *self, + const char *key, uint64_t *val); +gboolean wp_toml_table_get_double (const WpTomlTable *self, const char *key, + double *val); +gboolean wp_toml_table_get_qualified_double (const WpTomlTable *self, + const char *key, double *val); +char *wp_toml_table_get_string (const WpTomlTable *self, const char *key); +char *wp_toml_table_get_qualified_string (const WpTomlTable *self, + const char *key); +WpTomlArray *wp_toml_table_get_array (const WpTomlTable *self, const char *key); +WpTomlArray *wp_toml_table_get_qualified_array (const WpTomlTable *self, + const char *key); +WpTomlTable *wp_toml_table_get_table (const WpTomlTable *self, const char *key); +WpTomlTable *wp_toml_table_get_qualified_table (const WpTomlTable *self, + const char *key); +WpTomlTableArray *wp_toml_table_get_array_table (const WpTomlTable *self, + const char *key); +WpTomlTableArray *wp_toml_table_get_qualified_array_table ( + const WpTomlTable *self, const char *key); +typedef void (*WpTomlTableArrayForEachFunc)(const WpTomlTable *, gpointer); +void wp_toml_table_array_for_each (const WpTomlTableArray *self, + WpTomlTableArrayForEachFunc func, gpointer uder_data); + +G_END_DECLS + +#endif diff --git a/lib/wptoml/wptoml.h b/lib/wptoml/wptoml.h new file mode 100644 index 00000000..f21b7dae --- /dev/null +++ b/lib/wptoml/wptoml.h @@ -0,0 +1,11 @@ +/* WirePlumber + * + * Copyright © 2019 Collabora Ltd. + * @author Julian Bouzas + * + * SPDX-License-Identifier: MIT + */ + +#include "array.h" +#include "table.h" +#include "file.h" diff --git a/meson.build b/meson.build index 1a879da9..1b549cc8 100644 --- a/meson.build +++ b/meson.build @@ -1,10 +1,11 @@ -project('wireplumber', ['c'], +project('wireplumber', ['c', 'cpp'], version : '0.1.90', license : 'MIT', meson_version : '>= 0.47.0', default_options : [ 'warning_level=1', - 'buildtype=debugoptimized' + 'buildtype=debugoptimized', + 'cpp_std=c++11', ] ) @@ -23,6 +24,10 @@ else wireplumber_config_dir = join_paths(get_option('prefix'), get_option('sysconfdir'), 'wireplumber') endif +cmake = import('cmake') +cpptoml = cmake.subproject('cpptoml') +cpptoml_dep = cpptoml.dependency('cpptoml') + gobject_dep = dependency('gobject-2.0') gmodule_dep = dependency('gmodule-2.0') gio_dep = dependency('gio-2.0') diff --git a/subprojects/cpptoml.wrap b/subprojects/cpptoml.wrap new file mode 100644 index 00000000..7fa60bd9 --- /dev/null +++ b/subprojects/cpptoml.wrap @@ -0,0 +1,4 @@ +[wrap-git] +directory=cpptoml +url=https://github.com/skystrife/cpptoml.git +revision=master diff --git a/tests/meson.build b/tests/meson.build index fb5ca059..bfec91f9 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -1,2 +1,3 @@ subdir('modules') subdir('wp') +subdir('wptoml') diff --git a/tests/wptoml/files/basic-array.toml b/tests/wptoml/files/basic-array.toml new file mode 100644 index 00000000..7e804fd6 --- /dev/null +++ b/tests/wptoml/files/basic-array.toml @@ -0,0 +1,4 @@ +bool-array = [true, false, false, false, false, true, false] +int64-array = [1, 2, 3, 4, 5] +double-array = [0.1, 1.1, 2.1] +str-array = ["a ", "string ", "array"] diff --git a/tests/wptoml/files/basic-table.toml b/tests/wptoml/files/basic-table.toml new file mode 100644 index 00000000..f903b271 --- /dev/null +++ b/tests/wptoml/files/basic-table.toml @@ -0,0 +1,12 @@ +bool = true +int8 = -8 +uint8 = 8 +int16 = -16 +uint16 = 16 +int32 = -32 +uint32 = 32 +int64 = -64 +uint64 = 64 +double = 3.141592 +str = "str" +big_str = "this is a big string with special characters (!@#$%^&&*'') to make sure the wptoml library parses it correctly" diff --git a/tests/wptoml/files/nested-array.toml b/tests/wptoml/files/nested-array.toml new file mode 100644 index 00000000..03999fb3 --- /dev/null +++ b/tests/wptoml/files/nested-array.toml @@ -0,0 +1 @@ +nested-array = [[1, 2, 3, 4, 5], ["hello", "world"], [0.1, 1.1, 2.1]] diff --git a/tests/wptoml/files/nested-table.toml b/tests/wptoml/files/nested-table.toml new file mode 100644 index 00000000..ea8f5391 --- /dev/null +++ b/tests/wptoml/files/nested-table.toml @@ -0,0 +1,6 @@ +[table] +key1 = 0.1 +key2 = 1284 + +[table.subtable] +key3 = "hello world" diff --git a/tests/wptoml/files/table-array.toml b/tests/wptoml/files/table-array.toml new file mode 100644 index 00000000..d4f4a84b --- /dev/null +++ b/tests/wptoml/files/table-array.toml @@ -0,0 +1,5 @@ +[[table-array]] +key1 = "hello" + +[[table-array]] +key1 = ", can you hear me?" diff --git a/tests/wptoml/meson.build b/tests/wptoml/meson.build new file mode 100644 index 00000000..c34e732e --- /dev/null +++ b/tests/wptoml/meson.build @@ -0,0 +1,12 @@ +common_deps = [gobject_dep, wptoml_dep] +common_env = [ + 'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()), + 'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()), +] + +test( + 'test-wptoml', + executable('test-toml', 'wptoml.c', dependencies: common_deps), + env: common_env, + workdir : meson.current_source_dir(), +) diff --git a/tests/wptoml/wptoml.c b/tests/wptoml/wptoml.c new file mode 100644 index 00000000..af82e2ee --- /dev/null +++ b/tests/wptoml/wptoml.c @@ -0,0 +1,394 @@ +/* WirePlumber + * + * Copyright © 2019 Collabora Ltd. + * @author Julian Bouzas + * + * SPDX-License-Identifier: MIT + */ + +#include + +#define TOML_FILE_BASIC_TABLE "files/basic-table.toml" +#define TOML_FILE_BASIC_ARRAY "files/basic-array.toml" +#define TOML_FILE_NESTED_ARRAY "files/nested-array.toml" +#define TOML_FILE_NESTED_TABLE "files/nested-table.toml" +#define TOML_FILE_TABLE_ARRAY "files/table-array.toml" + +static void +test_basic_table (void) +{ + /* Parse the file */ + const char *file_name = TOML_FILE_BASIC_TABLE; + g_autoptr (WpTomlFile) file = wp_toml_file_new (file_name); + g_assert_nonnull (file); + + /* Get the name */ + const char *name = wp_toml_file_get_name (file); + g_assert_cmpstr (name, ==, TOML_FILE_BASIC_TABLE); + + /* Get the table */ + g_autoptr (WpTomlTable) table = wp_toml_file_get_table (file); + g_assert_nonnull (table); + + /* Test contains */ + g_assert_false (wp_toml_table_contains (table, "invalid-key")); + g_assert_true (wp_toml_table_contains (table, "bool")); + + /* Test boolean */ + { + gboolean val = FALSE; + g_assert_false (wp_toml_table_get_boolean (table, "invalid-key", &val)); + g_assert_false (val); + g_assert_true (wp_toml_table_get_boolean (table, "bool", &val)); + g_assert_true (val); + } + + /* Test int8 */ + { + int8_t val = 0; + g_assert_false (wp_toml_table_get_int8 (table, "invalid-key", &val)); + g_assert_cmpint (val, ==, 0); + g_assert_true (wp_toml_table_get_int8 (table, "int8", &val)); + g_assert_cmpint (val, ==, -8); + } + + /* Test uint8 */ + { + uint8_t val = 0; + g_assert_false (wp_toml_table_get_uint8 (table, "invalid-key", &val)); + g_assert_cmpuint (val, ==, 0); + g_assert_true (wp_toml_table_get_uint8 (table, "uint8", &val)); + g_assert_cmpuint (val, ==, 8); + } + + /* Test int16 */ + { + int16_t val = 0; + g_assert_false (wp_toml_table_get_int16 (table, "invalid-key", &val)); + g_assert_cmpint (val, ==, 0); + g_assert_true (wp_toml_table_get_int16 (table, "int16", &val)); + g_assert_cmpint (val, ==, -16); + } + + /* Test uint16 */ + { + uint16_t val = 0; + g_assert_false (wp_toml_table_get_uint16 (table, "invalid-key", &val)); + g_assert_cmpuint (val, ==, 0); + g_assert_true (wp_toml_table_get_uint16 (table, "uint16", &val)); + g_assert_cmpuint (val, ==, 16); + } + + /* Test int32 */ + { + int32_t val = 0; + g_assert_false (wp_toml_table_get_int32 (table, "invalid-key", &val)); + g_assert_cmpint (val, ==, 0); + g_assert_true (wp_toml_table_get_int32 (table, "int32", &val)); + g_assert_cmpint (val, ==, -32); + } + + /* Test uint32 */ + { + uint32_t val = 0; + g_assert_false (wp_toml_table_get_uint32 (table, "invalid-key", &val)); + g_assert_cmpuint (val, ==, 0); + g_assert_true (wp_toml_table_get_uint32 (table, "uint32", &val)); + g_assert_cmpuint (val, ==, 32); + } + + /* Test int64 */ + { + int64_t val = 0; + g_assert_false (wp_toml_table_get_int64 (table, "invalid-key", &val)); + g_assert_cmpint (val, ==, 0); + g_assert_true (wp_toml_table_get_int64 (table, "int64", &val)); + g_assert_cmpint (val, ==, -64); + } + + /* Test uint64 */ + { + uint64_t val = 0; + g_assert_false (wp_toml_table_get_uint64 (table, "invalid-key", &val)); + g_assert_true (val == 0); + g_assert_true (wp_toml_table_get_uint64 (table, "uint64", &val)); + g_assert_true (val == 64); + } + + /* Test double */ + { + double val = 0.0; + g_assert_false (wp_toml_table_get_double (table, "invalid-key", &val)); + g_assert_cmpfloat_with_epsilon (val, 0.0, 0.01); + g_assert_true (wp_toml_table_get_double (table, "double", &val)); + g_assert_cmpfloat_with_epsilon (val, 3.14, 0.01); + } + + /* Test string */ + { + g_autofree char *val = wp_toml_table_get_string (table, "invalid-key"); + g_assert_null (val); + val = wp_toml_table_get_string (table, "str"); + g_assert_nonnull (val); + g_assert_cmpstr (val, ==, "str"); + } + + /* Test big string */ + { + g_autofree char *val = wp_toml_table_get_string (table, "invalid-key"); + g_assert_null (val); + val = wp_toml_table_get_string (table, "big_str"); + g_assert_nonnull (val); + g_assert_cmpstr(val, ==, "this is a big string with special " + "characters (!@#$%^&&*'') to make sure the wptoml library parses " + "it correctly"); + } +} + +static void +boolean_array_for_each (const gboolean *v, gpointer user_data) +{ + int64_t *total_trues = user_data; + g_assert_nonnull (total_trues); + + /* Test all the array values could be parsed into boolean correctly */ + g_assert_nonnull (v); + + /* Count the trues */ + if (*v) + (*total_trues)++; +} + +static void +int64_array_for_each (const int64_t *v, gpointer user_data) +{ + int64_t *total = user_data; + g_assert_nonnull (total); + + /* Test all the array values could be parsed into int64_t correctly */ + g_assert_nonnull (v); + + /* Add the value to the total */ + *total += *v; +} + +static void +double_array_for_each (const double *v, gpointer user_data) +{ + double *total = user_data; + g_assert_nonnull (total); + + /* Test all the array values could be parsed into double correctly */ + g_assert_nonnull (v); + + /* Add the value to the total */ + *total += *v; +} + +static void +string_array_for_each (const char *v, gpointer user_data) +{ + char *buffer = user_data; + g_assert_nonnull (buffer); + + /* Test all the array values could be parsed into strings correctly */ + g_assert_nonnull (v); + + /* Concatenate */ + g_strlcat(buffer, v, 256); +} + +static void +unparsable_int64_array_for_each (const int64_t *v, gpointer user_data) +{ + /* Make sure the value is null */ + g_assert_null (v); +} + +static void +test_basic_array (void) +{ + /* Parse the file and get its table */ + g_autoptr (WpTomlFile) file = wp_toml_file_new (TOML_FILE_BASIC_ARRAY); + g_assert_nonnull (file); + g_autoptr (WpTomlTable) table = wp_toml_file_get_table (file); + g_assert_nonnull (table); + + /* Test bool array */ + { + g_autoptr (WpTomlArray) a = wp_toml_table_get_array (table, "bool-array"); + g_assert_nonnull (a); + int64_t total_trues = 0; + wp_toml_array_for_each_boolean (a, boolean_array_for_each, &total_trues); + g_assert_cmpuint (total_trues, ==, 2); + } + + /* Test int64 array */ + { + g_autoptr (WpTomlArray) a = wp_toml_table_get_array (table, "int64-array"); + g_assert_nonnull (a); + int64_t total = 0; + wp_toml_array_for_each_int64 (a, int64_array_for_each, &total); + g_assert_cmpuint (total, ==, 15); + } + + /* Test double array */ + { + g_autoptr (WpTomlArray) a = wp_toml_table_get_array (table, "double-array"); + g_assert_nonnull (a); + double total = 0; + wp_toml_array_for_each_double (a, double_array_for_each, &total); + g_assert_cmpfloat_with_epsilon (total, 3.3, 0.01); + } + + /* Test string array */ + { + g_autoptr (WpTomlArray) a = wp_toml_table_get_array (table, "str-array"); + g_assert_nonnull (a); + char buffer[256] = ""; + wp_toml_array_for_each_string (a, string_array_for_each, &buffer); + g_assert_cmpstr (buffer, ==, "a string array"); + } + + /* Try to parse a string array as an int64 array */ + { + g_autoptr (WpTomlArray) a = wp_toml_table_get_array (table, "str-array"); + g_assert_nonnull (a); + wp_toml_array_for_each_int64 (a, unparsable_int64_array_for_each, NULL); + } +} + +static void +test_nested_table (void) +{ + /* Parse the file and get its table */ + g_autoptr (WpTomlFile) file = wp_toml_file_new (TOML_FILE_NESTED_TABLE); + g_assert_nonnull (file); + g_autoptr (WpTomlTable) table = wp_toml_file_get_table (file); + g_assert_nonnull (table); + + /* Get the first nested table */ + g_autoptr (WpTomlTable) table1 = wp_toml_table_get_table (table, "table"); + g_assert_nonnull (table1); + + /* Get the key1 and key2 values of the first nested table */ + double key1 = 0; + wp_toml_table_get_double (table1, "key1", &key1); + g_assert_cmpfloat_with_epsilon (key1, 0.1, 0.01); + int32_t key2 = 0; + wp_toml_table_get_int32 (table1, "key2", &key2); + g_assert_cmpint (key2, ==, 1284); + + /* Get the second nested table */ + g_autoptr (WpTomlTable) table2 = wp_toml_table_get_table (table1, "subtable"); + g_assert_nonnull (table2); + + /* Get the key3 value of the second nested table */ + g_autofree char *key3 = wp_toml_table_get_string (table2, "key3"); + g_assert_nonnull (key3); + g_assert_cmpstr (key3, ==, "hello world"); +} + +static void +nested_array_for_each (WpTomlArray *a, gpointer user_data) +{ + int *count = user_data; + g_assert_nonnull (count); + + /* Test all the array values could be parsed into arrays correctly */ + g_assert_nonnull (a); + + /* Parse the nested arrays for each type */ + switch (*count) { + case 0: { + int64_t total = 0; + wp_toml_array_for_each_int64 (a, int64_array_for_each, &total); + g_assert_cmpint (total, ==, 15); + break; + } + case 1: { + char buffer[256] = ""; + wp_toml_array_for_each_string (a, string_array_for_each, &buffer); + g_assert_cmpstr (buffer, ==, "helloworld"); + break; + } + case 2: { + double total = 0; + wp_toml_array_for_each_double (a, double_array_for_each, &total); + g_assert_cmpfloat_with_epsilon (total, 3.3, 0.01); + break; + } + default: + break; + } + + /* Increase the counter */ + (*count)++; +} + +static void +test_nested_array () +{ + /* Parse the file and get its table */ + g_autoptr (WpTomlFile) file = wp_toml_file_new (TOML_FILE_NESTED_ARRAY); + g_assert_nonnull (file); + g_autoptr (WpTomlTable) table = wp_toml_file_get_table (file); + g_assert_nonnull (table); + + /* Test nested array */ + g_autoptr (WpTomlArray) a = wp_toml_table_get_array (table, "nested-array"); + g_assert_nonnull (a); + int count = 0; + wp_toml_array_for_each_array (a, nested_array_for_each, &count); + g_assert_cmpint (count, ==, 3); +} + +static void +table_array_for_each (const WpTomlTable *table, gpointer user_data) +{ + char *buffer = user_data; + + /* Test all the array values could be parsed into a table correctly */ + g_assert_nonnull (table); + + /* Check for key1 string */ + g_autofree char *key1 = wp_toml_table_get_string (table, "key1"); + g_assert_nonnull (key1); + + /* Concatenate */ + g_strlcat(buffer, key1, 256); +} + +static void +test_table_array () +{ + /* Parse the file and get its table */ + g_autoptr (WpTomlFile) file = wp_toml_file_new (TOML_FILE_TABLE_ARRAY); + g_assert_nonnull (file); + g_autoptr (WpTomlTable) table = wp_toml_file_get_table (file); + g_assert_nonnull (table); + + /* Get the table array */ + g_autoptr (WpTomlTableArray) table_array = wp_toml_table_get_array_table ( + table, "table-array"); + g_assert_nonnull (table_array); + + /* Iterate */ + char buffer[256] = ""; + wp_toml_table_array_for_each (table_array, table_array_for_each, buffer); + g_assert_cmpstr (buffer, ==, "hello, can you hear me?"); +} + +int +main (int argc, char *argv[]) +{ + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/wptoml/basic_table", test_basic_table); + g_test_add_func ("/wptoml/basic_array", test_basic_array); + g_test_add_func ("/wptoml/nested_table", test_nested_table); + g_test_add_func ("/wptoml/nested_array", test_nested_array); + g_test_add_func ("/wptoml/table_array", test_table_array); + + return g_test_run (); +}