From db9e07ea3978c029c386b689e61e23f973cf3eaf Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Wed, 29 Apr 2020 15:51:11 +1200 Subject: [PATCH] Add FlValue FlValue is a lightweight object used to contain the value types that Flutter uses on platform channels. --- ci/licenses_golden/licenses_flutter | 3 + shell/platform/linux/BUILD.gn | 3 + shell/platform/linux/fl_value.cc | 550 +++++++++++++ shell/platform/linux/fl_value_test.cc | 731 ++++++++++++++++++ .../linux/public/flutter_linux/fl_value.h | 507 ++++++++++++ .../public/flutter_linux/flutter_linux.h | 1 + 6 files changed, 1795 insertions(+) create mode 100644 shell/platform/linux/fl_value.cc create mode 100644 shell/platform/linux/fl_value_test.cc create mode 100644 shell/platform/linux/public/flutter_linux/fl_value.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 7da60486822fe..05a04b2fd54ce 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1182,10 +1182,13 @@ FILE: ../../../flutter/shell/platform/linux/fl_renderer.cc FILE: ../../../flutter/shell/platform/linux/fl_renderer.h FILE: ../../../flutter/shell/platform/linux/fl_renderer_x11.cc FILE: ../../../flutter/shell/platform/linux/fl_renderer_x11.h +FILE: ../../../flutter/shell/platform/linux/fl_value.cc +FILE: ../../../flutter/shell/platform/linux/fl_value_test.cc FILE: ../../../flutter/shell/platform/linux/fl_view.cc FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_dart_project.h FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_engine.h +FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_value.h FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_view.h FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/flutter_linux.h FILE: ../../../flutter/shell/platform/windows/angle_surface_manager.cc diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index 213374bdc15ac..e469168212985 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -47,6 +47,7 @@ _public_headers = [ "public/flutter_linux/fl_binary_messenger.h", "public/flutter_linux/fl_dart_project.h", "public/flutter_linux/fl_engine.h", + "public/flutter_linux/fl_value.h", "public/flutter_linux/fl_view.h", "public/flutter_linux/flutter_linux.h", ] @@ -64,6 +65,7 @@ source_set("flutter_linux") { "fl_engine.cc", "fl_renderer.cc", "fl_renderer_x11.cc", + "fl_value.cc", "fl_view.cc", ] @@ -90,6 +92,7 @@ executable("flutter_linux_unittests") { sources = [ "fl_dart_project_test.cc", + "fl_value_test.cc", ] public_configs = [ "//flutter:config" ] diff --git a/shell/platform/linux/fl_value.cc b/shell/platform/linux/fl_value.cc new file mode 100644 index 0000000000000..4c68cbc1cf6d0 --- /dev/null +++ b/shell/platform/linux/fl_value.cc @@ -0,0 +1,550 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/linux/public/flutter_linux/fl_value.h" + +#include + +struct _FlValue { + FlValueType type; + int ref_count; +}; + +typedef struct { + FlValue parent; + bool value; +} FlValueBool; + +typedef struct { + FlValue parent; + int64_t value; +} FlValueInt; + +typedef struct { + FlValue parent; + double value; +} FlValueDouble; + +typedef struct { + FlValue parent; + gchar* value; +} FlValueString; + +typedef struct { + FlValue parent; + uint8_t* values; + size_t values_length; +} FlValueUint8List; + +typedef struct { + FlValue parent; + int32_t* values; + size_t values_length; +} FlValueInt32List; + +typedef struct { + FlValue parent; + int64_t* values; + size_t values_length; +} FlValueInt64List; + +typedef struct { + FlValue parent; + double* values; + size_t values_length; +} FlValueFloatList; + +typedef struct { + FlValue parent; + GPtrArray* values; +} FlValueList; + +typedef struct { + FlValue parent; + GPtrArray* keys; + GPtrArray* values; +} FlValueMap; + +static FlValue* fl_value_new(FlValueType type, size_t size) { + FlValue* self = static_cast(g_malloc0(size)); + self->type = type; + self->ref_count = 1; + return self; +} + +// Helper function to match GDestroyNotify type. +static void fl_value_destroy(gpointer value) { + fl_value_unref(static_cast(value)); +} + +// Finds the index of a key in a FlValueMap. +// FIXME(robert-ancell) This is highly inefficient, and should be optimised if +// necessary. +static ssize_t fl_value_lookup_index(FlValue* self, FlValue* key) { + g_return_val_if_fail(self->type == FL_VALUE_TYPE_MAP, -1); + + for (size_t i = 0; i < fl_value_get_length(self); i++) { + FlValue* k = fl_value_get_map_key(self, i); + if (fl_value_equal(k, key)) + return i; + } + return -1; +} + +G_MODULE_EXPORT FlValue* fl_value_new_null() { + return fl_value_new(FL_VALUE_TYPE_NULL, sizeof(FlValue)); +} + +G_MODULE_EXPORT FlValue* fl_value_new_bool(bool value) { + FlValueBool* self = reinterpret_cast( + fl_value_new(FL_VALUE_TYPE_BOOL, sizeof(FlValueBool))); + self->value = value ? true : false; + return reinterpret_cast(self); +} + +G_MODULE_EXPORT FlValue* fl_value_new_int(int64_t value) { + FlValueInt* self = reinterpret_cast( + fl_value_new(FL_VALUE_TYPE_INT, sizeof(FlValueInt))); + self->value = value; + return reinterpret_cast(self); +} + +G_MODULE_EXPORT FlValue* fl_value_new_float(double value) { + FlValueDouble* self = reinterpret_cast( + fl_value_new(FL_VALUE_TYPE_FLOAT, sizeof(FlValueDouble))); + self->value = value; + return reinterpret_cast(self); +} + +G_MODULE_EXPORT FlValue* fl_value_new_string(const gchar* value) { + FlValueString* self = reinterpret_cast( + fl_value_new(FL_VALUE_TYPE_STRING, sizeof(FlValueString))); + self->value = g_strdup(value); + return reinterpret_cast(self); +} + +G_MODULE_EXPORT FlValue* fl_value_new_string_sized(const gchar* value, + size_t value_length) { + FlValueString* self = reinterpret_cast( + fl_value_new(FL_VALUE_TYPE_STRING, sizeof(FlValueString))); + self->value = + value_length == 0 ? g_strdup("") : g_strndup(value, value_length); + return reinterpret_cast(self); +} + +G_MODULE_EXPORT FlValue* fl_value_new_uint8_list(const uint8_t* data, + size_t data_length) { + FlValueUint8List* self = reinterpret_cast( + fl_value_new(FL_VALUE_TYPE_UINT8_LIST, sizeof(FlValueUint8List))); + self->values_length = data_length; + self->values = static_cast(g_malloc(sizeof(uint8_t) * data_length)); + memcpy(self->values, data, sizeof(uint8_t) * data_length); + return reinterpret_cast(self); +} + +G_MODULE_EXPORT FlValue* fl_value_new_uint8_list_from_bytes(GBytes* data) { + gsize length; + const uint8_t* d = + static_cast(g_bytes_get_data(data, &length)); + return fl_value_new_uint8_list(d, length); +} + +G_MODULE_EXPORT FlValue* fl_value_new_int32_list(const int32_t* data, + size_t data_length) { + FlValueInt32List* self = reinterpret_cast( + fl_value_new(FL_VALUE_TYPE_INT32_LIST, sizeof(FlValueInt32List))); + self->values_length = data_length; + self->values = static_cast(g_malloc(sizeof(int32_t) * data_length)); + memcpy(self->values, data, sizeof(int32_t) * data_length); + return reinterpret_cast(self); +} + +G_MODULE_EXPORT FlValue* fl_value_new_int64_list(const int64_t* data, + size_t data_length) { + FlValueInt64List* self = reinterpret_cast( + fl_value_new(FL_VALUE_TYPE_INT64_LIST, sizeof(FlValueInt64List))); + self->values_length = data_length; + self->values = static_cast(g_malloc(sizeof(int64_t) * data_length)); + memcpy(self->values, data, sizeof(int64_t) * data_length); + return reinterpret_cast(self); +} + +G_MODULE_EXPORT FlValue* fl_value_new_float_list(const double* data, + size_t data_length) { + FlValueFloatList* self = reinterpret_cast( + fl_value_new(FL_VALUE_TYPE_FLOAT_LIST, sizeof(FlValueFloatList))); + self->values_length = data_length; + self->values = static_cast(g_malloc(sizeof(double) * data_length)); + memcpy(self->values, data, sizeof(double) * data_length); + return reinterpret_cast(self); +} + +G_MODULE_EXPORT FlValue* fl_value_new_list() { + FlValueList* self = reinterpret_cast( + fl_value_new(FL_VALUE_TYPE_LIST, sizeof(FlValueList))); + self->values = g_ptr_array_new_with_free_func(fl_value_destroy); + return reinterpret_cast(self); +} + +G_MODULE_EXPORT FlValue* fl_value_new_list_from_strv( + const gchar* const* str_array) { + g_return_val_if_fail(str_array != nullptr, nullptr); + g_autoptr(FlValue) value = fl_value_new_list(); + for (int i = 0; str_array[i] != nullptr; i++) + fl_value_append_take(value, fl_value_new_string(str_array[i])); + return fl_value_ref(value); +} + +G_MODULE_EXPORT FlValue* fl_value_new_map() { + FlValueMap* self = reinterpret_cast( + fl_value_new(FL_VALUE_TYPE_MAP, sizeof(FlValueMap))); + self->keys = g_ptr_array_new_with_free_func(fl_value_destroy); + self->values = g_ptr_array_new_with_free_func(fl_value_destroy); + return reinterpret_cast(self); +} + +G_MODULE_EXPORT FlValue* fl_value_ref(FlValue* self) { + self->ref_count++; + return self; +} + +G_MODULE_EXPORT void fl_value_unref(FlValue* self) { + g_return_if_fail(self->ref_count > 0); + self->ref_count--; + if (self->ref_count != 0) + return; + + switch (self->type) { + case FL_VALUE_TYPE_STRING: { + FlValueString* v = reinterpret_cast(self); + g_free(v->value); + break; + } + case FL_VALUE_TYPE_UINT8_LIST: { + FlValueUint8List* v = reinterpret_cast(self); + g_free(v->values); + break; + } + case FL_VALUE_TYPE_INT32_LIST: { + FlValueInt32List* v = reinterpret_cast(self); + g_free(v->values); + break; + } + case FL_VALUE_TYPE_INT64_LIST: { + FlValueInt64List* v = reinterpret_cast(self); + g_free(v->values); + break; + } + case FL_VALUE_TYPE_FLOAT_LIST: { + FlValueFloatList* v = reinterpret_cast(self); + g_free(v->values); + break; + } + case FL_VALUE_TYPE_LIST: { + FlValueList* v = reinterpret_cast(self); + g_ptr_array_unref(v->values); + break; + } + case FL_VALUE_TYPE_MAP: { + FlValueMap* v = reinterpret_cast(self); + g_ptr_array_unref(v->keys); + g_ptr_array_unref(v->values); + break; + } + case FL_VALUE_TYPE_NULL: + case FL_VALUE_TYPE_BOOL: + case FL_VALUE_TYPE_INT: + case FL_VALUE_TYPE_FLOAT: + break; + } + g_free(self); +} + +G_MODULE_EXPORT FlValueType fl_value_get_type(FlValue* self) { + g_return_val_if_fail(self != nullptr, FL_VALUE_TYPE_NULL); + return self->type; +} + +G_MODULE_EXPORT bool fl_value_equal(FlValue* a, FlValue* b) { + g_return_val_if_fail(a != nullptr, false); + g_return_val_if_fail(b != nullptr, false); + + if (a->type != b->type) + return false; + + switch (a->type) { + case FL_VALUE_TYPE_NULL: + return true; + case FL_VALUE_TYPE_BOOL: + return fl_value_get_bool(a) == fl_value_get_bool(b); + case FL_VALUE_TYPE_INT: + return fl_value_get_int(a) == fl_value_get_int(b); + case FL_VALUE_TYPE_FLOAT: + return fl_value_get_float(a) == fl_value_get_float(b); + case FL_VALUE_TYPE_STRING: { + FlValueString* a_ = reinterpret_cast(a); + FlValueString* b_ = reinterpret_cast(b); + return g_strcmp0(a_->value, b_->value) == 0; + } + case FL_VALUE_TYPE_UINT8_LIST: { + if (fl_value_get_length(a) != fl_value_get_length(b)) + return false; + const uint8_t* values_a = fl_value_get_uint8_list(a); + const uint8_t* values_b = fl_value_get_uint8_list(b); + for (size_t i = 0; i < fl_value_get_length(a); i++) { + if (values_a[i] != values_b[i]) + return false; + } + return true; + } + case FL_VALUE_TYPE_INT32_LIST: { + if (fl_value_get_length(a) != fl_value_get_length(b)) + return false; + const int32_t* values_a = fl_value_get_int32_list(a); + const int32_t* values_b = fl_value_get_int32_list(b); + for (size_t i = 0; i < fl_value_get_length(a); i++) { + if (values_a[i] != values_b[i]) + return false; + } + return true; + } + case FL_VALUE_TYPE_INT64_LIST: { + if (fl_value_get_length(a) != fl_value_get_length(b)) + return false; + const int64_t* values_a = fl_value_get_int64_list(a); + const int64_t* values_b = fl_value_get_int64_list(b); + for (size_t i = 0; i < fl_value_get_length(a); i++) { + if (values_a[i] != values_b[i]) + return false; + } + return true; + } + case FL_VALUE_TYPE_FLOAT_LIST: { + if (fl_value_get_length(a) != fl_value_get_length(b)) + return false; + const double* values_a = fl_value_get_float_list(a); + const double* values_b = fl_value_get_float_list(b); + for (size_t i = 0; i < fl_value_get_length(a); i++) { + if (values_a[i] != values_b[i]) + return false; + } + return true; + } + case FL_VALUE_TYPE_LIST: { + if (fl_value_get_length(a) != fl_value_get_length(b)) + return false; + for (size_t i = 0; i < fl_value_get_length(a); i++) { + if (!fl_value_equal(fl_value_get_list_value(a, i), + fl_value_get_list_value(b, i))) + return false; + } + return true; + } + case FL_VALUE_TYPE_MAP: { + if (fl_value_get_length(a) != fl_value_get_length(b)) + return false; + for (size_t i = 0; i < fl_value_get_length(a); i++) { + FlValue* key = fl_value_get_map_key(a, i); + FlValue* value_b = fl_value_lookup(b, key); + if (value_b == nullptr) + return false; + FlValue* value_a = fl_value_get_map_value(a, i); + if (!fl_value_equal(value_a, value_b)) + return false; + } + return true; + } + } +} + +G_MODULE_EXPORT void fl_value_append(FlValue* self, FlValue* value) { + g_return_if_fail(self->type == FL_VALUE_TYPE_LIST); + g_return_if_fail(value != nullptr); + + fl_value_append_take(self, fl_value_ref(value)); +} + +G_MODULE_EXPORT void fl_value_append_take(FlValue* self, FlValue* value) { + g_return_if_fail(self->type == FL_VALUE_TYPE_LIST); + g_return_if_fail(value != nullptr); + + FlValueList* v = reinterpret_cast(self); + g_ptr_array_add(v->values, value); +} + +G_MODULE_EXPORT void fl_value_set(FlValue* self, FlValue* key, FlValue* value) { + g_return_if_fail(self->type == FL_VALUE_TYPE_MAP); + g_return_if_fail(key != nullptr); + g_return_if_fail(value != nullptr); + + fl_value_set_take(self, fl_value_ref(key), fl_value_ref(value)); +} + +G_MODULE_EXPORT void fl_value_set_take(FlValue* self, + FlValue* key, + FlValue* value) { + g_return_if_fail(self->type == FL_VALUE_TYPE_MAP); + g_return_if_fail(key != nullptr); + g_return_if_fail(value != nullptr); + + FlValueMap* v = reinterpret_cast(self); + ssize_t index = fl_value_lookup_index(self, key); + if (index < 0) { + g_ptr_array_add(v->keys, key); + g_ptr_array_add(v->values, value); + } else { + fl_value_destroy(v->keys->pdata[index]); + v->keys->pdata[index] = key; + fl_value_destroy(v->values->pdata[index]); + v->values->pdata[index] = value; + } +} + +G_MODULE_EXPORT void fl_value_set_string(FlValue* self, + const gchar* key, + FlValue* value) { + g_return_if_fail(self->type == FL_VALUE_TYPE_MAP); + g_return_if_fail(key != nullptr); + g_return_if_fail(value != nullptr); + + fl_value_set_take(self, fl_value_new_string(key), fl_value_ref(value)); +} + +G_MODULE_EXPORT void fl_value_set_string_take(FlValue* self, + const gchar* key, + FlValue* value) { + g_return_if_fail(self->type == FL_VALUE_TYPE_MAP); + g_return_if_fail(key != nullptr); + g_return_if_fail(value != nullptr); + + fl_value_set_take(self, fl_value_new_string(key), value); +} + +G_MODULE_EXPORT bool fl_value_get_bool(FlValue* self) { + g_return_val_if_fail(self->type == FL_VALUE_TYPE_BOOL, FALSE); + FlValueBool* v = reinterpret_cast(self); + return v->value; +} + +G_MODULE_EXPORT int64_t fl_value_get_int(FlValue* self) { + g_return_val_if_fail(self->type == FL_VALUE_TYPE_INT, 0); + FlValueInt* v = reinterpret_cast(self); + return v->value; +} + +G_MODULE_EXPORT double fl_value_get_float(FlValue* self) { + g_return_val_if_fail(self->type == FL_VALUE_TYPE_FLOAT, 0.0); + FlValueDouble* v = reinterpret_cast(self); + return v->value; +} + +G_MODULE_EXPORT const gchar* fl_value_get_string(FlValue* self) { + g_return_val_if_fail(self->type == FL_VALUE_TYPE_STRING, nullptr); + FlValueString* v = reinterpret_cast(self); + return v->value; +} + +G_MODULE_EXPORT const uint8_t* fl_value_get_uint8_list(FlValue* self) { + g_return_val_if_fail(self->type == FL_VALUE_TYPE_UINT8_LIST, nullptr); + FlValueUint8List* v = reinterpret_cast(self); + return v->values; +} + +G_MODULE_EXPORT const int32_t* fl_value_get_int32_list(FlValue* self) { + g_return_val_if_fail(self->type == FL_VALUE_TYPE_INT32_LIST, nullptr); + FlValueInt32List* v = reinterpret_cast(self); + return v->values; +} + +G_MODULE_EXPORT const int64_t* fl_value_get_int64_list(FlValue* self) { + g_return_val_if_fail(self->type == FL_VALUE_TYPE_INT64_LIST, nullptr); + FlValueInt64List* v = reinterpret_cast(self); + return v->values; +} + +G_MODULE_EXPORT const double* fl_value_get_float_list(FlValue* self) { + g_return_val_if_fail(self->type == FL_VALUE_TYPE_FLOAT_LIST, nullptr); + FlValueFloatList* v = reinterpret_cast(self); + return v->values; +} + +G_MODULE_EXPORT size_t fl_value_get_length(FlValue* self) { + g_return_val_if_fail(self->type == FL_VALUE_TYPE_UINT8_LIST || + self->type == FL_VALUE_TYPE_INT32_LIST || + self->type == FL_VALUE_TYPE_INT64_LIST || + self->type == FL_VALUE_TYPE_FLOAT_LIST || + self->type == FL_VALUE_TYPE_LIST || + self->type == FL_VALUE_TYPE_MAP, + 0); + + switch (self->type) { + case FL_VALUE_TYPE_UINT8_LIST: { + FlValueUint8List* v = reinterpret_cast(self); + return v->values_length; + } + case FL_VALUE_TYPE_INT32_LIST: { + FlValueInt32List* v = reinterpret_cast(self); + return v->values_length; + } + case FL_VALUE_TYPE_INT64_LIST: { + FlValueInt64List* v = reinterpret_cast(self); + return v->values_length; + } + case FL_VALUE_TYPE_FLOAT_LIST: { + FlValueFloatList* v = reinterpret_cast(self); + return v->values_length; + } + case FL_VALUE_TYPE_LIST: { + FlValueList* v = reinterpret_cast(self); + return v->values->len; + } + case FL_VALUE_TYPE_MAP: { + FlValueMap* v = reinterpret_cast(self); + return v->keys->len; + } + case FL_VALUE_TYPE_NULL: + case FL_VALUE_TYPE_BOOL: + case FL_VALUE_TYPE_INT: + case FL_VALUE_TYPE_FLOAT: + case FL_VALUE_TYPE_STRING: + return 0; + } + + return 0; +} + +G_MODULE_EXPORT FlValue* fl_value_get_list_value(FlValue* self, size_t index) { + g_return_val_if_fail(self->type == FL_VALUE_TYPE_LIST, nullptr); + + FlValueList* v = reinterpret_cast(self); + return static_cast(g_ptr_array_index(v->values, index)); +} + +G_MODULE_EXPORT FlValue* fl_value_get_map_key(FlValue* self, size_t index) { + g_return_val_if_fail(self->type == FL_VALUE_TYPE_MAP, nullptr); + + FlValueMap* v = reinterpret_cast(self); + return static_cast(g_ptr_array_index(v->keys, index)); +} + +G_MODULE_EXPORT FlValue* fl_value_get_map_value(FlValue* self, size_t index) { + g_return_val_if_fail(self->type == FL_VALUE_TYPE_MAP, nullptr); + + FlValueMap* v = reinterpret_cast(self); + return static_cast(g_ptr_array_index(v->values, index)); +} + +G_MODULE_EXPORT FlValue* fl_value_lookup(FlValue* self, FlValue* key) { + g_return_val_if_fail(self->type == FL_VALUE_TYPE_MAP, nullptr); + + ssize_t index = fl_value_lookup_index(self, key); + if (index < 0) + return nullptr; + return fl_value_get_map_value(self, index); +} + +FlValue* fl_value_lookup_string(FlValue* self, const gchar* key) { + g_autoptr(FlValue) string_key = fl_value_new_string(key); + return fl_value_lookup(self, string_key); +} diff --git a/shell/platform/linux/fl_value_test.cc b/shell/platform/linux/fl_value_test.cc new file mode 100644 index 0000000000000..9cc570453b2c0 --- /dev/null +++ b/shell/platform/linux/fl_value_test.cc @@ -0,0 +1,731 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/linux/public/flutter_linux/fl_value.h" +#include "gtest/gtest.h" + +#include + +TEST(FlDartProjectTest, Null) { + g_autoptr(FlValue) value = fl_value_new_null(); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_NULL); +} + +TEST(FlValueTest, NullEqual) { + g_autoptr(FlValue) value1 = fl_value_new_null(); + g_autoptr(FlValue) value2 = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, BoolTrue) { + g_autoptr(FlValue) value = fl_value_new_bool(TRUE); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_BOOL); + EXPECT_TRUE(fl_value_get_bool(value)); +} + +TEST(FlValueTest, BoolFalse) { + g_autoptr(FlValue) value = fl_value_new_bool(FALSE); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_BOOL); + EXPECT_FALSE(fl_value_get_bool(value)); +} + +TEST(FlValueTest, BoolEqual) { + g_autoptr(FlValue) value1 = fl_value_new_bool(TRUE); + g_autoptr(FlValue) value2 = fl_value_new_bool(TRUE); + EXPECT_TRUE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, BoolNotEqual) { + g_autoptr(FlValue) value1 = fl_value_new_bool(TRUE); + g_autoptr(FlValue) value2 = fl_value_new_bool(FALSE); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, IntZero) { + g_autoptr(FlValue) value = fl_value_new_int(0); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_INT); + EXPECT_EQ(fl_value_get_int(value), 0); +} + +TEST(FlValueTest, IntOne) { + g_autoptr(FlValue) value = fl_value_new_int(1); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_INT); + EXPECT_EQ(fl_value_get_int(value), 1); +} + +TEST(FlValueTest, IntMinusOne) { + g_autoptr(FlValue) value = fl_value_new_int(-1); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_INT); + EXPECT_EQ(fl_value_get_int(value), -1); +} + +TEST(FlValueTest, IntMin) { + g_autoptr(FlValue) value = fl_value_new_int(G_MININT64); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_INT); + EXPECT_EQ(fl_value_get_int(value), G_MININT64); +} + +TEST(FlValueTest, IntMax) { + g_autoptr(FlValue) value = fl_value_new_int(G_MAXINT64); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_INT); + EXPECT_EQ(fl_value_get_int(value), G_MAXINT64); +} + +TEST(FlValueTest, IntEqual) { + g_autoptr(FlValue) value1 = fl_value_new_int(42); + g_autoptr(FlValue) value2 = fl_value_new_int(42); + EXPECT_TRUE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, IntNotEqual) { + g_autoptr(FlValue) value1 = fl_value_new_int(42); + g_autoptr(FlValue) value2 = fl_value_new_int(99); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, FloatZero) { + g_autoptr(FlValue) value = fl_value_new_float(0.0); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_FLOAT); + EXPECT_EQ(fl_value_get_float(value), 0.0); +} + +TEST(FlValueTest, FloatOne) { + g_autoptr(FlValue) value = fl_value_new_float(1.0); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_FLOAT); + EXPECT_EQ(fl_value_get_float(value), 1.0); +} + +TEST(FlValueTest, FloatMinusOne) { + g_autoptr(FlValue) value = fl_value_new_float(-1.0); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_FLOAT); + EXPECT_EQ(fl_value_get_float(value), -1.0); +} + +TEST(FlValueTest, FloatPi) { + g_autoptr(FlValue) value = fl_value_new_float(M_PI); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_FLOAT); + EXPECT_EQ(fl_value_get_float(value), M_PI); +} + +TEST(FlValueTest, FloatEqual) { + g_autoptr(FlValue) value1 = fl_value_new_float(M_PI); + g_autoptr(FlValue) value2 = fl_value_new_float(M_PI); + EXPECT_TRUE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, FloatNotEqual) { + g_autoptr(FlValue) value1 = fl_value_new_float(M_PI); + g_autoptr(FlValue) value2 = fl_value_new_float(M_E); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, String) { + g_autoptr(FlValue) value = fl_value_new_string("hello"); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_STRING); + EXPECT_STREQ(fl_value_get_string(value), "hello"); +} + +TEST(FlValueTest, StringEmpty) { + g_autoptr(FlValue) value = fl_value_new_string(""); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_STRING); + EXPECT_STREQ(fl_value_get_string(value), ""); +} + +TEST(FlValueTest, StringSized) { + g_autoptr(FlValue) value = fl_value_new_string_sized("hello", 2); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_STRING); + EXPECT_STREQ(fl_value_get_string(value), "he"); +} + +TEST(FlValueTest, StringSizedNULL) { + g_autoptr(FlValue) value = fl_value_new_string_sized(nullptr, 0); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_STRING); + EXPECT_STREQ(fl_value_get_string(value), ""); +} + +TEST(FlValueTest, StringSizedZeroLength) { + g_autoptr(FlValue) value = fl_value_new_string_sized("hello", 0); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_STRING); + EXPECT_STREQ(fl_value_get_string(value), ""); +} + +TEST(FlValueTest, StringEqual) { + g_autoptr(FlValue) value1 = fl_value_new_string("hello"); + g_autoptr(FlValue) value2 = fl_value_new_string("hello"); + EXPECT_TRUE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, StringNotEqual) { + g_autoptr(FlValue) value1 = fl_value_new_string("hello"); + g_autoptr(FlValue) value2 = fl_value_new_string("world"); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, Uint8List) { + uint8_t data[] = {0x00, 0x01, 0xFE, 0xFF}; + g_autoptr(FlValue) value = fl_value_new_uint8_list(data, 4); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_UINT8_LIST); + ASSERT_EQ(fl_value_get_length(value), static_cast(4)); + EXPECT_EQ(fl_value_get_uint8_list(value)[0], 0x00); + EXPECT_EQ(fl_value_get_uint8_list(value)[1], 0x01); + EXPECT_EQ(fl_value_get_uint8_list(value)[2], 0xFE); + EXPECT_EQ(fl_value_get_uint8_list(value)[3], 0xFF); +} + +TEST(FlValueTest, Uint8ListNULL) { + g_autoptr(FlValue) value = fl_value_new_uint8_list(nullptr, 0); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_UINT8_LIST); + ASSERT_EQ(fl_value_get_length(value), static_cast(0)); +} + +TEST(FlValueTest, Uint8ListEqual) { + uint8_t data1[] = {1, 2, 3}; + g_autoptr(FlValue) value1 = fl_value_new_uint8_list(data1, 3); + uint8_t data2[] = {1, 2, 3}; + g_autoptr(FlValue) value2 = fl_value_new_uint8_list(data2, 3); + EXPECT_TRUE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, Uint8ListEmptyEqual) { + g_autoptr(FlValue) value1 = fl_value_new_uint8_list(nullptr, 0); + g_autoptr(FlValue) value2 = fl_value_new_uint8_list(nullptr, 0); + EXPECT_TRUE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, Uint8ListNotEqualSameSize) { + uint8_t data1[] = {1, 2, 3}; + g_autoptr(FlValue) value1 = fl_value_new_uint8_list(data1, 3); + uint8_t data2[] = {1, 2, 4}; + g_autoptr(FlValue) value2 = fl_value_new_uint8_list(data2, 3); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, Uint8ListNotEqualDifferentSize) { + uint8_t data1[] = {1, 2, 3}; + g_autoptr(FlValue) value1 = fl_value_new_uint8_list(data1, 3); + uint8_t data2[] = {1, 2, 3, 4}; + g_autoptr(FlValue) value2 = fl_value_new_uint8_list(data2, 4); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, Uint8ListEmptyNotEqual) { + g_autoptr(FlValue) value1 = fl_value_new_uint8_list(nullptr, 0); + uint8_t data[] = {1, 2, 3}; + g_autoptr(FlValue) value2 = fl_value_new_uint8_list(data, 3); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, Int32List) { + int32_t data[] = {0, -1, G_MAXINT32, G_MININT32}; + g_autoptr(FlValue) value = fl_value_new_int32_list(data, 4); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_INT32_LIST); + ASSERT_EQ(fl_value_get_length(value), static_cast(4)); + EXPECT_EQ(fl_value_get_int32_list(value)[0], 0); + EXPECT_EQ(fl_value_get_int32_list(value)[1], -1); + EXPECT_EQ(fl_value_get_int32_list(value)[2], G_MAXINT32); + EXPECT_EQ(fl_value_get_int32_list(value)[3], G_MININT32); +} + +TEST(FlValueTest, Int32ListNULL) { + g_autoptr(FlValue) value = fl_value_new_int32_list(nullptr, 0); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_INT32_LIST); + ASSERT_EQ(fl_value_get_length(value), static_cast(0)); +} + +TEST(FlValueTest, Int32ListEqual) { + int32_t data1[] = {0, G_MAXINT32, G_MININT32}; + g_autoptr(FlValue) value1 = fl_value_new_int32_list(data1, 3); + int32_t data2[] = {0, G_MAXINT32, G_MININT32}; + g_autoptr(FlValue) value2 = fl_value_new_int32_list(data2, 3); + EXPECT_TRUE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, Int32ListEmptyEqual) { + g_autoptr(FlValue) value1 = fl_value_new_int32_list(nullptr, 0); + g_autoptr(FlValue) value2 = fl_value_new_int32_list(nullptr, 0); + EXPECT_TRUE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, Int32ListNotEqualSameSize) { + int32_t data1[] = {0, G_MAXINT32, G_MININT32}; + g_autoptr(FlValue) value1 = fl_value_new_int32_list(data1, 3); + int32_t data2[] = {0, G_MININT32, G_MAXINT32}; + g_autoptr(FlValue) value2 = fl_value_new_int32_list(data2, 3); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, Int32ListNotEqualDifferentSize) { + int32_t data1[] = {0, G_MAXINT32, G_MININT32}; + g_autoptr(FlValue) value1 = fl_value_new_int32_list(data1, 3); + int32_t data2[] = {0, G_MAXINT32, G_MININT32, -1}; + g_autoptr(FlValue) value2 = fl_value_new_int32_list(data2, 4); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, Int32ListEmptyNotEqual) { + g_autoptr(FlValue) value1 = fl_value_new_int32_list(nullptr, 0); + int32_t data[] = {0, G_MAXINT32, G_MININT32}; + g_autoptr(FlValue) value2 = fl_value_new_int32_list(data, 3); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, Int64List) { + int64_t data[] = {0, -1, G_MAXINT64, G_MININT64}; + g_autoptr(FlValue) value = fl_value_new_int64_list(data, 4); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_INT64_LIST); + ASSERT_EQ(fl_value_get_length(value), static_cast(4)); + EXPECT_EQ(fl_value_get_int64_list(value)[0], 0); + EXPECT_EQ(fl_value_get_int64_list(value)[1], -1); + EXPECT_EQ(fl_value_get_int64_list(value)[2], G_MAXINT64); + EXPECT_EQ(fl_value_get_int64_list(value)[3], G_MININT64); +} + +TEST(FlValueTest, Int64ListNULL) { + g_autoptr(FlValue) value = fl_value_new_int64_list(nullptr, 0); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_INT64_LIST); + ASSERT_EQ(fl_value_get_length(value), static_cast(0)); +} + +TEST(FlValueTest, Int64ListEqual) { + int64_t data1[] = {0, G_MAXINT64, G_MININT64}; + g_autoptr(FlValue) value1 = fl_value_new_int64_list(data1, 3); + int64_t data2[] = {0, G_MAXINT64, G_MININT64}; + g_autoptr(FlValue) value2 = fl_value_new_int64_list(data2, 3); + EXPECT_TRUE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, Int64ListEmptyEqual) { + g_autoptr(FlValue) value1 = fl_value_new_int64_list(nullptr, 0); + g_autoptr(FlValue) value2 = fl_value_new_int64_list(nullptr, 0); + EXPECT_TRUE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, Int64ListNotEqualSameSize) { + int64_t data1[] = {0, G_MAXINT64, G_MININT64}; + g_autoptr(FlValue) value1 = fl_value_new_int64_list(data1, 3); + int64_t data2[] = {0, G_MININT64, G_MAXINT64}; + g_autoptr(FlValue) value2 = fl_value_new_int64_list(data2, 3); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, Int64ListNotEqualDifferentSize) { + int64_t data1[] = {0, G_MAXINT64, G_MININT64}; + g_autoptr(FlValue) value1 = fl_value_new_int64_list(data1, 3); + int64_t data2[] = {0, G_MAXINT64, G_MININT64, -1}; + g_autoptr(FlValue) value2 = fl_value_new_int64_list(data2, 4); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, Int64ListEmptyNotEqual) { + g_autoptr(FlValue) value1 = fl_value_new_int64_list(nullptr, 0); + int64_t data[] = {0, G_MAXINT64, G_MININT64}; + g_autoptr(FlValue) value2 = fl_value_new_int64_list(data, 3); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, FloatList) { + double data[] = {0.0, -1.0, M_PI}; + g_autoptr(FlValue) value = fl_value_new_float_list(data, 4); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_FLOAT_LIST); + ASSERT_EQ(fl_value_get_length(value), static_cast(4)); + EXPECT_EQ(fl_value_get_float_list(value)[0], 0); + EXPECT_EQ(fl_value_get_float_list(value)[1], -1.0); + EXPECT_EQ(fl_value_get_float_list(value)[2], M_PI); +} + +TEST(FlValueTest, FloatListNULL) { + g_autoptr(FlValue) value = fl_value_new_float_list(nullptr, 0); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_FLOAT_LIST); + ASSERT_EQ(fl_value_get_length(value), static_cast(0)); +} + +TEST(FlValueTest, FloatListEqual) { + double data1[] = {0, -0.5, M_PI}; + g_autoptr(FlValue) value1 = fl_value_new_float_list(data1, 3); + double data2[] = {0, -0.5, M_PI}; + g_autoptr(FlValue) value2 = fl_value_new_float_list(data2, 3); + EXPECT_TRUE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, FloatListEmptyEqual) { + g_autoptr(FlValue) value1 = fl_value_new_float_list(nullptr, 0); + g_autoptr(FlValue) value2 = fl_value_new_float_list(nullptr, 0); + EXPECT_TRUE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, FloatListNotEqualSameSize) { + double data1[] = {0, -0.5, M_PI}; + g_autoptr(FlValue) value1 = fl_value_new_float_list(data1, 3); + double data2[] = {0, -0.5, M_E}; + g_autoptr(FlValue) value2 = fl_value_new_float_list(data2, 3); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, FloatListNotEqualDifferentSize) { + double data1[] = {0, -0.5, M_PI}; + g_autoptr(FlValue) value1 = fl_value_new_float_list(data1, 3); + double data2[] = {0, -0.5, M_PI, 42}; + g_autoptr(FlValue) value2 = fl_value_new_float_list(data2, 4); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, FloatListEmptyNotEqual) { + g_autoptr(FlValue) value1 = fl_value_new_float_list(nullptr, 0); + double data[] = {0, -0.5, M_PI}; + g_autoptr(FlValue) value2 = fl_value_new_float_list(data, 3); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, ListEmpty) { + g_autoptr(FlValue) value = fl_value_new_list(); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_LIST); + ASSERT_EQ(fl_value_get_length(value), static_cast(0)); +} + +TEST(FlValueTest, ListAdd) { + g_autoptr(FlValue) value = fl_value_new_list(); + g_autoptr(FlValue) child = fl_value_new_null(); + fl_value_append(value, child); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_LIST); + ASSERT_EQ(fl_value_get_length(value), static_cast(1)); + EXPECT_EQ(fl_value_get_type(fl_value_get_list_value(value, 0)), + FL_VALUE_TYPE_NULL); +} + +TEST(FlValueTest, ListAddTake) { + g_autoptr(FlValue) value = fl_value_new_list(); + fl_value_append_take(value, fl_value_new_null()); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_LIST); + ASSERT_EQ(fl_value_get_length(value), static_cast(1)); + EXPECT_EQ(fl_value_get_type(fl_value_get_list_value(value, 0)), + FL_VALUE_TYPE_NULL); +} + +TEST(FlValueTest, ListChildTypes) { + g_autoptr(FlValue) value = fl_value_new_list(); + fl_value_append_take(value, fl_value_new_null()); + fl_value_append_take(value, fl_value_new_bool(TRUE)); + fl_value_append_take(value, fl_value_new_int(42)); + fl_value_append_take(value, fl_value_new_float(M_PI)); + fl_value_append_take(value, fl_value_new_uint8_list(nullptr, 0)); + fl_value_append_take(value, fl_value_new_int32_list(nullptr, 0)); + fl_value_append_take(value, fl_value_new_int64_list(nullptr, 0)); + fl_value_append_take(value, fl_value_new_float_list(nullptr, 0)); + fl_value_append_take(value, fl_value_new_list()); + fl_value_append_take(value, fl_value_new_map()); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_LIST); + ASSERT_EQ(fl_value_get_length(value), static_cast(10)); + EXPECT_EQ(fl_value_get_type(fl_value_get_list_value(value, 0)), + FL_VALUE_TYPE_NULL); + EXPECT_EQ(fl_value_get_type(fl_value_get_list_value(value, 1)), + FL_VALUE_TYPE_BOOL); + EXPECT_EQ(fl_value_get_type(fl_value_get_list_value(value, 2)), + FL_VALUE_TYPE_INT); + EXPECT_EQ(fl_value_get_type(fl_value_get_list_value(value, 3)), + FL_VALUE_TYPE_FLOAT); + EXPECT_EQ(fl_value_get_type(fl_value_get_list_value(value, 4)), + FL_VALUE_TYPE_UINT8_LIST); + EXPECT_EQ(fl_value_get_type(fl_value_get_list_value(value, 5)), + FL_VALUE_TYPE_INT32_LIST); + EXPECT_EQ(fl_value_get_type(fl_value_get_list_value(value, 6)), + FL_VALUE_TYPE_INT64_LIST); + EXPECT_EQ(fl_value_get_type(fl_value_get_list_value(value, 7)), + FL_VALUE_TYPE_FLOAT_LIST); + EXPECT_EQ(fl_value_get_type(fl_value_get_list_value(value, 8)), + FL_VALUE_TYPE_LIST); + EXPECT_EQ(fl_value_get_type(fl_value_get_list_value(value, 9)), + FL_VALUE_TYPE_MAP); +} + +TEST(FlValueTest, ListStrv) { + g_auto(GStrv) words = g_strsplit("hello:world", ":", -1); + g_autoptr(FlValue) value = fl_value_new_list_from_strv(words); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_LIST); + ASSERT_EQ(fl_value_get_length(value), static_cast(2)); + ASSERT_EQ(fl_value_get_type(fl_value_get_list_value(value, 0)), + FL_VALUE_TYPE_STRING); + EXPECT_STREQ(fl_value_get_string(fl_value_get_list_value(value, 0)), "hello"); + ASSERT_EQ(fl_value_get_type(fl_value_get_list_value(value, 1)), + FL_VALUE_TYPE_STRING); + EXPECT_STREQ(fl_value_get_string(fl_value_get_list_value(value, 1)), "world"); +} + +TEST(FlValueTest, ListStrvEmpty) { + g_auto(GStrv) words = g_strsplit("", ":", -1); + g_autoptr(FlValue) value = fl_value_new_list_from_strv(words); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_LIST); + ASSERT_EQ(fl_value_get_length(value), static_cast(0)); +} + +TEST(FlValueTest, ListEqual) { + g_autoptr(FlValue) value1 = fl_value_new_list(); + fl_value_append_take(value1, fl_value_new_int(1)); + fl_value_append_take(value1, fl_value_new_int(2)); + fl_value_append_take(value1, fl_value_new_int(3)); + g_autoptr(FlValue) value2 = fl_value_new_list(); + fl_value_append_take(value2, fl_value_new_int(1)); + fl_value_append_take(value2, fl_value_new_int(2)); + fl_value_append_take(value2, fl_value_new_int(3)); + EXPECT_TRUE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, ListEmptyEqual) { + g_autoptr(FlValue) value1 = fl_value_new_list(); + g_autoptr(FlValue) value2 = fl_value_new_list(); + EXPECT_TRUE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, ListNotEqualSameSize) { + g_autoptr(FlValue) value1 = fl_value_new_list(); + fl_value_append_take(value1, fl_value_new_int(1)); + fl_value_append_take(value1, fl_value_new_int(2)); + fl_value_append_take(value1, fl_value_new_int(3)); + g_autoptr(FlValue) value2 = fl_value_new_list(); + fl_value_append_take(value2, fl_value_new_int(1)); + fl_value_append_take(value2, fl_value_new_int(2)); + fl_value_append_take(value2, fl_value_new_int(4)); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, ListNotEqualDifferentSize) { + g_autoptr(FlValue) value1 = fl_value_new_list(); + fl_value_append_take(value1, fl_value_new_int(1)); + fl_value_append_take(value1, fl_value_new_int(2)); + fl_value_append_take(value1, fl_value_new_int(3)); + g_autoptr(FlValue) value2 = fl_value_new_list(); + fl_value_append_take(value2, fl_value_new_int(1)); + fl_value_append_take(value2, fl_value_new_int(2)); + fl_value_append_take(value2, fl_value_new_int(3)); + fl_value_append_take(value2, fl_value_new_int(4)); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, ListEmptyNotEqual) { + g_autoptr(FlValue) value1 = fl_value_new_list(); + g_autoptr(FlValue) value2 = fl_value_new_list(); + fl_value_append_take(value2, fl_value_new_int(1)); + fl_value_append_take(value2, fl_value_new_int(2)); + fl_value_append_take(value2, fl_value_new_int(3)); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, MapEmpty) { + g_autoptr(FlValue) value = fl_value_new_map(); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_MAP); + ASSERT_EQ(fl_value_get_length(value), static_cast(0)); +} + +TEST(FlValueTest, MapSet) { + g_autoptr(FlValue) value = fl_value_new_map(); + g_autoptr(FlValue) k = fl_value_new_string("count"); + g_autoptr(FlValue) v = fl_value_new_int(42); + fl_value_set(value, k, v); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_MAP); + ASSERT_EQ(fl_value_get_length(value), static_cast(1)); + ASSERT_EQ(fl_value_get_type(fl_value_get_map_key(value, 0)), + FL_VALUE_TYPE_STRING); + EXPECT_STREQ(fl_value_get_string(fl_value_get_map_key(value, 0)), "count"); + ASSERT_EQ(fl_value_get_type(fl_value_get_map_value(value, 0)), + FL_VALUE_TYPE_INT); + EXPECT_EQ(fl_value_get_int(fl_value_get_map_value(value, 0)), 42); +} + +TEST(FlValueTest, MapSetTake) { + g_autoptr(FlValue) value = fl_value_new_map(); + fl_value_set_take(value, fl_value_new_string("count"), fl_value_new_int(42)); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_MAP); + ASSERT_EQ(fl_value_get_length(value), static_cast(1)); + ASSERT_EQ(fl_value_get_type(fl_value_get_map_key(value, 0)), + FL_VALUE_TYPE_STRING); + EXPECT_STREQ(fl_value_get_string(fl_value_get_map_key(value, 0)), "count"); + ASSERT_EQ(fl_value_get_type(fl_value_get_map_value(value, 0)), + FL_VALUE_TYPE_INT); + EXPECT_EQ(fl_value_get_int(fl_value_get_map_value(value, 0)), 42); +} + +TEST(FlValueTest, MapSetString) { + g_autoptr(FlValue) value = fl_value_new_map(); + g_autoptr(FlValue) v = fl_value_new_int(42); + fl_value_set_string(value, "count", v); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_MAP); + ASSERT_EQ(fl_value_get_length(value), static_cast(1)); + ASSERT_EQ(fl_value_get_type(fl_value_get_map_key(value, 0)), + FL_VALUE_TYPE_STRING); + EXPECT_STREQ(fl_value_get_string(fl_value_get_map_key(value, 0)), "count"); + ASSERT_EQ(fl_value_get_type(fl_value_get_map_value(value, 0)), + FL_VALUE_TYPE_INT); + EXPECT_EQ(fl_value_get_int(fl_value_get_map_value(value, 0)), 42); +} + +TEST(FlValueTest, MapSetStringTake) { + g_autoptr(FlValue) value = fl_value_new_map(); + fl_value_set_string_take(value, "count", fl_value_new_int(42)); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_MAP); + ASSERT_EQ(fl_value_get_length(value), static_cast(1)); + ASSERT_EQ(fl_value_get_type(fl_value_get_map_key(value, 0)), + FL_VALUE_TYPE_STRING); + EXPECT_STREQ(fl_value_get_string(fl_value_get_map_key(value, 0)), "count"); + ASSERT_EQ(fl_value_get_type(fl_value_get_map_value(value, 0)), + FL_VALUE_TYPE_INT); + EXPECT_EQ(fl_value_get_int(fl_value_get_map_value(value, 0)), 42); +} + +TEST(FlValueTest, MapLookup) { + g_autoptr(FlValue) value = fl_value_new_map(); + fl_value_set_string_take(value, "one", fl_value_new_int(1)); + fl_value_set_string_take(value, "two", fl_value_new_int(2)); + fl_value_set_string_take(value, "three", fl_value_new_int(3)); + ASSERT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_MAP); + g_autoptr(FlValue) two_key = fl_value_new_string("two"); + FlValue* v = fl_value_lookup(value, two_key); + ASSERT_NE(v, nullptr); + ASSERT_EQ(fl_value_get_type(v), FL_VALUE_TYPE_INT); + EXPECT_EQ(fl_value_get_int(v), 2); + g_autoptr(FlValue) four_key = fl_value_new_string("four"); + v = fl_value_lookup(value, four_key); + ASSERT_EQ(v, nullptr); +} + +TEST(FlValueTest, MapLookupString) { + g_autoptr(FlValue) value = fl_value_new_map(); + fl_value_set_string_take(value, "one", fl_value_new_int(1)); + fl_value_set_string_take(value, "two", fl_value_new_int(2)); + fl_value_set_string_take(value, "three", fl_value_new_int(3)); + FlValue* v = fl_value_lookup_string(value, "two"); + ASSERT_NE(v, nullptr); + ASSERT_EQ(fl_value_get_type(v), FL_VALUE_TYPE_INT); + EXPECT_EQ(fl_value_get_int(v), 2); + v = fl_value_lookup_string(value, "four"); + ASSERT_EQ(v, nullptr); +} + +TEST(FlValueTest, MapEqual) { + g_autoptr(FlValue) value1 = fl_value_new_map(); + fl_value_set_string_take(value1, "one", fl_value_new_int(1)); + fl_value_set_string_take(value1, "two", fl_value_new_int(2)); + fl_value_set_string_take(value1, "three", fl_value_new_int(3)); + g_autoptr(FlValue) value2 = fl_value_new_map(); + fl_value_set_string_take(value2, "one", fl_value_new_int(1)); + fl_value_set_string_take(value2, "two", fl_value_new_int(2)); + fl_value_set_string_take(value2, "three", fl_value_new_int(3)); + EXPECT_TRUE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, MapEqualDifferentOrder) { + g_autoptr(FlValue) value1 = fl_value_new_map(); + fl_value_set_string_take(value1, "one", fl_value_new_int(1)); + fl_value_set_string_take(value1, "two", fl_value_new_int(2)); + fl_value_set_string_take(value1, "three", fl_value_new_int(3)); + g_autoptr(FlValue) value2 = fl_value_new_map(); + fl_value_set_string_take(value2, "one", fl_value_new_int(1)); + fl_value_set_string_take(value2, "three", fl_value_new_int(3)); + fl_value_set_string_take(value2, "two", fl_value_new_int(2)); + EXPECT_TRUE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, MapEmptyEqual) { + g_autoptr(FlValue) value1 = fl_value_new_map(); + g_autoptr(FlValue) value2 = fl_value_new_map(); + EXPECT_TRUE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, MapNotEqualSameSizeDifferentKeys) { + g_autoptr(FlValue) value1 = fl_value_new_map(); + fl_value_set_string_take(value1, "one", fl_value_new_int(1)); + fl_value_set_string_take(value1, "two", fl_value_new_int(2)); + fl_value_set_string_take(value1, "three", fl_value_new_int(3)); + g_autoptr(FlValue) value2 = fl_value_new_map(); + fl_value_set_string_take(value2, "one", fl_value_new_int(1)); + fl_value_set_string_take(value2, "two", fl_value_new_int(2)); + fl_value_set_string_take(value2, "four", fl_value_new_int(3)); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, MapNotEqualSameSizeDifferentValues) { + g_autoptr(FlValue) value1 = fl_value_new_map(); + fl_value_set_string_take(value1, "one", fl_value_new_int(1)); + fl_value_set_string_take(value1, "two", fl_value_new_int(2)); + fl_value_set_string_take(value1, "three", fl_value_new_int(3)); + g_autoptr(FlValue) value2 = fl_value_new_map(); + fl_value_set_string_take(value2, "one", fl_value_new_int(1)); + fl_value_set_string_take(value2, "two", fl_value_new_int(2)); + fl_value_set_string_take(value2, "three", fl_value_new_int(4)); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, MapNotEqualDifferentSize) { + g_autoptr(FlValue) value1 = fl_value_new_map(); + fl_value_set_string_take(value1, "one", fl_value_new_int(1)); + fl_value_set_string_take(value1, "two", fl_value_new_int(2)); + fl_value_set_string_take(value1, "three", fl_value_new_int(3)); + g_autoptr(FlValue) value2 = fl_value_new_map(); + fl_value_set_string_take(value2, "one", fl_value_new_int(1)); + fl_value_set_string_take(value2, "two", fl_value_new_int(2)); + fl_value_set_string_take(value2, "three", fl_value_new_int(3)); + fl_value_set_string_take(value2, "four", fl_value_new_int(4)); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, MapEmptyNotEqual) { + g_autoptr(FlValue) value1 = fl_value_new_map(); + g_autoptr(FlValue) value2 = fl_value_new_map(); + fl_value_set_string_take(value2, "one", fl_value_new_int(1)); + fl_value_set_string_take(value2, "two", fl_value_new_int(2)); + fl_value_set_string_take(value2, "three", fl_value_new_int(3)); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, EqualSameObject) { + g_autoptr(FlValue) value = fl_value_new_null(); + EXPECT_TRUE(fl_value_equal(value, value)); +} + +TEST(FlValueTest, NullIntNotEqual) { + g_autoptr(FlValue) value1 = fl_value_new_null(); + g_autoptr(FlValue) value2 = fl_value_new_int(0); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, NullBoolNotEqual) { + g_autoptr(FlValue) value1 = fl_value_new_bool(FALSE); + g_autoptr(FlValue) value2 = fl_value_new_int(0); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, StringUint8ListNotEqual) { + uint8_t data[] = {'h', 'e', 'l', 'l', 'o'}; + g_autoptr(FlValue) value1 = fl_value_new_uint8_list(data, 5); + g_autoptr(FlValue) value2 = fl_value_new_string("hello"); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, Uint8ListInt32ListNotEqual) { + uint8_t data8[] = {0, 1, 2, 3, 4}; + int32_t data32[] = {0, 1, 2, 3, 4}; + g_autoptr(FlValue) value1 = fl_value_new_uint8_list(data8, 5); + g_autoptr(FlValue) value2 = fl_value_new_int32_list(data32, 5); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, Int32ListInt64ListNotEqual) { + int32_t data32[] = {0, 1, 2, 3, 4}; + int64_t data64[] = {0, 1, 2, 3, 4}; + g_autoptr(FlValue) value1 = fl_value_new_int32_list(data32, 5); + g_autoptr(FlValue) value2 = fl_value_new_int64_list(data64, 5); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, Int64ListFloatListNotEqual) { + int64_t data64[] = {0, 1, 2, 3, 4}; + double dataf[] = {0.0, 1.0, 2.0, 3.0, 4.0}; + g_autoptr(FlValue) value1 = fl_value_new_int64_list(data64, 5); + g_autoptr(FlValue) value2 = fl_value_new_float_list(dataf, 5); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} + +TEST(FlValueTest, ListMapNotEqual) { + g_autoptr(FlValue) value1 = fl_value_new_list(); + g_autoptr(FlValue) value2 = fl_value_new_map(); + EXPECT_FALSE(fl_value_equal(value1, value2)); +} diff --git a/shell/platform/linux/public/flutter_linux/fl_value.h b/shell/platform/linux/public/flutter_linux/fl_value.h new file mode 100644 index 0000000000000..2aba673e42a7f --- /dev/null +++ b/shell/platform/linux/public/flutter_linux/fl_value.h @@ -0,0 +1,507 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_VALUE_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_VALUE_H_ + +#include +#include +#include + +#if !defined(__FLUTTER_LINUX_INSIDE__) && !defined(FLUTTER_LINUX_COMPILATION) +#error "Only can be included directly." +#endif + +G_BEGIN_DECLS + +/** + * FlValue: + * + * #FlValue is an object that contains the data types used in the platform + * channel codecs provided by Flutter. + * + * In Dart the values are represented as follows: + * - #FL_VALUE_TYPE_NULL: null + * - #FL_VALUE_TYPE_BOOL: bool + * - #FL_VALUE_TYPE_INT: num + * - #FL_VALUE_TYPE_FLOAT: num + * - #FL_VALUE_TYPE_STRING: String + * - #FL_VALUE_TYPE_UINT8_LIST: Uint8List + * - #FL_VALUE_TYPE_INT32_LIST: Int32List + * - #FL_VALUE_TYPE_INT64_LIST: Int64List + * - #FL_VALUE_TYPE_FLOAT_LIST: Float64List + * - #FL_VALUE_TYPE_LIST: List + * - #FL_VALUE_TYPE_MAP: Map + */ +typedef struct _FlValue FlValue; + +/** + * FlValueType: + * @FL_VALUE_TYPE_NULL: The null value. + * @FL_VALUE_TYPE_BOOL: A boolean. + * @FL_VALUE_TYPE_INT: A 64 bit signed integer. + * @FL_VALUE_TYPE_FLOAT: A 64 bit floating point number. + * @FL_VALUE_TYPE_STRING: UTF-8 text. + * @FL_VALUE_TYPE_UINT8_LIST: An ordered list of unsigned 8 bit integers. + * @FL_VALUE_TYPE_INT32_LIST: An ordered list of 32 bit integers. + * @FL_VALUE_TYPE_INT64_LIST: An ordered list of 64 bit integers. + * @FL_VALUE_TYPE_FLOAT_LIST: An ordered list of floating point numbers. + * @FL_VALUE_TYPE_LIST: An ordered list of #FlValue objects. + * @FL_VALUE_TYPE_MAP: A map of #FlValue objects keyed by #FlValue object. + * + * Types of #FlValue. + */ +typedef enum { + FL_VALUE_TYPE_NULL, + FL_VALUE_TYPE_BOOL, + FL_VALUE_TYPE_INT, + FL_VALUE_TYPE_FLOAT, + FL_VALUE_TYPE_STRING, + FL_VALUE_TYPE_UINT8_LIST, + FL_VALUE_TYPE_INT32_LIST, + FL_VALUE_TYPE_INT64_LIST, + FL_VALUE_TYPE_FLOAT_LIST, + FL_VALUE_TYPE_LIST, + FL_VALUE_TYPE_MAP, +} FlValueType; + +/** + * fl_value_new_null: + * + * Creates an #FlValue that contains a null value. + * + * Returns: a new #FlValue. + */ +FlValue* fl_value_new_null(); + +/** + * fl_value_new_bool: + * @value: the value. + * + * Creates an #FlValue that contains a boolean value. + * + * Returns: a new #FlValue. + */ +FlValue* fl_value_new_bool(bool value); + +/** + * fl_value_new_int: + * @value: the value. + * + * Creates an #FlValue that contains an integer number. + * + * Returns: a new #FlValue. + */ +FlValue* fl_value_new_int(int64_t value); + +/** + * fl_value_new_float: + * @value: the value. + * + * Creates an #FlValue that contains a floating point number. + * + * Returns: a new #FlValue. + */ +FlValue* fl_value_new_float(double value); + +/** + * fl_value_new_string: + * @value: a nul terminated UTF-8 string. + * + * Creates an #FlValue that contains UTF-8 text. + * + * Returns: a new #FlValue. + */ +FlValue* fl_value_new_string(const gchar* value); + +/** + * fl_value_new_string: + * @value: a buffer containing UTF-8 text. It does not require a nul terminator. + * @value_length: the number of bytes to use from @value. + * + * Creates an #FlValue that contains UTF-8 text. + * + * Returns: a new #FlValue. + */ +FlValue* fl_value_new_string_sized(const gchar* value, size_t value_length); + +/** + * fl_value_new_uint8_list: + * @data: Data to copy. + * @data_length: number of elements in @data. + * + * Creates an ordered list containing 8 bit unsigned integers. + * + * Returns: a new #FlValue. + */ +FlValue* fl_value_new_uint8_list(const uint8_t* data, size_t data_length); + +/** + * fl_value_new_uint8_list: + * @data: Data to copy + * + * Creates an ordered list containing 8 bit unsigned integers. + * + * Returns: a new #FlValue. + */ +FlValue* fl_value_new_uint8_list_from_bytes(GBytes* data); + +/** + * fl_value_new_int32_list: + * + * Creates an ordered list containing 32 bit integers. + * + * Returns: a new #FlValue. + */ +FlValue* fl_value_new_int32_list(const int32_t* data, size_t data_length); + +/** + * fl_value_new_int64_list: + * + * Creates an ordered list containing 64 bit integers. + * + * Returns: a new #FlValue. + */ +FlValue* fl_value_new_int64_list(const int64_t* data, size_t data_length); + +/** + * fl_value_new_float_list: + * + * Creates an ordered list containing floating point numbers. + * + * Returns: a new #FlValue. + */ +FlValue* fl_value_new_float_list(const double* data, size_t data_length); + +/** + * fl_value_new_list: + * + * Creates an ordered list. Children can be added to the list using + * fl_value_append(). The children are accessed using fl_value_get_length() + * and fl_value_get_list_value(). + * + * Returns: a new #FlValue. + */ +FlValue* fl_value_new_list(); + +/** + * fl_value_new_list_from_strv: + * @str_array: a %NULL-terminated array of strings. + * + * Creates an ordered list containing #FlString values. + * + * Returns: a new #FlValue. + */ +FlValue* fl_value_new_list_from_strv(const gchar* const* str_array); + +/** + * fl_value_new_map: + * + * Creates an ordered associative array. Children can be added to the map + * using fl_value_set(), fl_value_set_take(), fl_value_set_string(), + * fl_value_set_string_take(). The children are accessed using + * fl_value_get_length(), fl_value_get_map_key(), fl_value_get_map_value(), + * fl_value_lookup() and fl_value_lookup_string(). + * + * Returns: a new #FlValue. + */ +FlValue* fl_value_new_map(); + +/** + * fl_value_ref: + * @value: an #FlValue + * + * Increases the reference count of an #FlValue. + * + * Returns: the value that was referenced. + */ +FlValue* fl_value_ref(FlValue* value); + +/** + * fl_value_ref: + * @value: an #FlValue + * + * Dereases the reference count of an #FlValue. When the refernece count hits + * zero @value is destroyed and no longer valid. + */ +void fl_value_unref(FlValue* value); + +/** + * fl_value_get_type: + * @value: an #FlValue + * + * Gets the type of @value. + * + * Returns: an #FlValueType. + */ +FlValueType fl_value_get_type(FlValue* value); + +/** + * fl_value_equal: + * @a: an #FlValue + * @b: an #FlValue + * + * Compares two #FlValue to see if they are equivalent. Two values are + * considered equivalent if they are of the same type and their data is the same + * including any child values. For values of type #FL_VALUE_TYPE_MAP the order + * of the values does not matter. + * + * Returns: %TRUE if both values are equivalent. + */ +bool fl_value_equal(FlValue* a, FlValue* b); + +/** + * fl_value_append: + * @value: an #FlValue of type #FL_VALUE_TYPE_LIST + * @child: an #FlValue + * + * Adds @child to the end of @value. Calling this with an #FlValue that is not + * of type #FL_VALUE_TYPE_LIST is a programming error. + */ +void fl_value_append(FlValue* value, FlValue* child); + +/** + * fl_value_append: + * @value: an #FlValue of type #FL_VALUE_TYPE_LIST + * @child: (transfer full): an #FlValue + * + * Adds @child to the end of @value. Ownership of @child is taken by @value. + * Calling this with an #FlValue that is not of type #FL_VALUE_TYPE_LIST is a + * programming error. + */ +void fl_value_append_take(FlValue* value, FlValue* child); + +/** + * fl_value_set: + * @value: an #FlValue of type #FL_VALUE_TYPE_MAP + * @key: an #FlValue + * @child_value: an #FlValue + * + * Sets @key in @value to @child_value. If an existing value was in the map with + * the same key it is replaced. Calling this with an #FlValue that is not of + * type #FL_VALUE_TYPE_MAP is a programming error. + */ +void fl_value_set(FlValue* value, FlValue* key, FlValue* child_value); + +/** + * fl_value_set_take: + * @value: an #FlValue of type #FL_VALUE_TYPE_MAP + * @key: (transfer full): an #FlValue + * @child_value: (transfer full): an #FlValue + * + * Sets @key in @value to @child_value. Ownership of both @key and @child_value + * is taken by @value. If an existing value was in the map with the same key it + * is replaced. Calling this with an #FlValue that is not of type + * #FL_VALUE_TYPE_MAP is a programming error. + */ +void fl_value_set_take(FlValue* value, FlValue* key, FlValue* child_value); + +/** + * fl_value_set_string: + * @value: an #FlValue of type #FL_VALUE_TYPE_MAP + * @key: a UTF-8 text key + * @child_value: an #FlValue + * + * Sets a value in the map with a text key. If an existing value was in the map + * with the same key it is replaced. Calling this with an #FlValue that is not + * of type #FL_VALUE_TYPE_MAP is a programming error. + */ +void fl_value_set_string(FlValue* value, + const gchar* key, + FlValue* child_value); + +/** + * fl_value_set_string_take: + * @value: an #FlValue of type #FL_VALUE_TYPE_MAP + * @key: a UTF-8 text key + * @child_value: (transfer full): an #FlValue + * + * Sets a value in the map with a text key, taking ownership of the value. If an + * existing value was in the map with the same key it is replaced. Calling this + * with an #FlValue that is not of type #FL_VALUE_TYPE_MAP is a programming + * error. + */ +void fl_value_set_string_take(FlValue* value, + const gchar* key, + FlValue* child_value); + +/** + * fl_value_get_bool: + * @value: an #FlValue of type #FL_VALUE_TYPE_BOOL + * + * Gets the boolean value of @value. Calling this with an #FlValue that is + * not of type #FL_VALUE_TYPE_BOOL is a programming error. + * + * Returns: a boolean value. + */ +bool fl_value_get_bool(FlValue* value); + +/** + * fl_value_get_int: + * @value: an #FlValue of type #FL_VALUE_TYPE_INT + * + * Gets the integer number of @value. Calling this with an #FlValue that is + * not of type #FL_VALUE_TYPE_INT is a programming error. + * + * Returns: an integer number. + */ +int64_t fl_value_get_int(FlValue* value); + +/** + * fl_value_get_double: + * @value: an #FlValue of type #FL_VALUE_TYPE_FLOAT + * + * Gets the floating point number of @value. Calling this with an #FlValue + * that is not of type #FL_VALUE_TYPE_FLOAT is a programming error. + * + * Returns: a UTF-8 encoded string. + */ +double fl_value_get_float(FlValue* value); + +/** + * fl_value_get_string: + * @value: an #FlValue of type #FL_VALUE_TYPE_STRING + * + * Gets the UTF-8 text contained in @value. Calling this with an #FlValue + * that is not of type #FL_VALUE_TYPE_STRING is a programming error. + * + * Returns: a UTF-8 encoded string. + */ +const gchar* fl_value_get_string(FlValue* value); + +/** + * fl_value_get_length: + * @value: an #FlValue of type #FL_VALUE_TYPE_UINT8_LIST, + * #FL_VALUE_TYPE_INT32_LIST, #FL_VALUE_TYPE_INT64_LIST, + * #FL_VALUE_TYPE_FLOAT_LIST, #FL_VALUE_TYPE_LIST or #FL_VALUE_TYPE_MAP. + * + * Gets the number of elements @value contains. This is only valid for list + * and map types. Calling this with other types is a programming error. + * + * Returns: the number of elements inside @value. + */ +size_t fl_value_get_length(FlValue* value); + +/** + * fl_value_get_uint8_list: + * @value: an #FlValue of type #FL_VALUE_TYPE_UINT8_LIST + * + * Gets the array of unisigned 8 bit integers @value contains. The data + * contains fl_get_length() elements. Calling this with an #FlValue that is + * not of type #FL_VALUE_TYPE_UINT8_LIST is a programming error. + * + * Returns: an array of unsigned 8 bit integers. + */ +const uint8_t* fl_value_get_uint8_list(FlValue* value); + +/** + * fl_value_get_int32_list: + * @value: an #FlValue of type #FL_VALUE_TYPE_INT32_LIST + * + * Gets the array of 32 bit integers @value contains. The data contains + * fl_get_length() elements. Calling this with an #FlValue that is not of + * type #FL_VALUE_TYPE_INT32_LIST is a programming error. + * + * Returns: an array of 32 bit integers. + */ +const int32_t* fl_value_get_int32_list(FlValue* value); + +/** + * fl_value_get_int64_list: + * @value: an #FlValue of type #FL_VALUE_TYPE_INT64_LIST + * + * Gets the array of 64 bit integers @value contains. The data contains + * fl_get_length() elements. Calling this with an #FlValue that is not of + * type #FL_VALUE_TYPE_INT64_LIST is a programming error. + * + * Returns: an array of 64 bit integers. + */ +const int64_t* fl_value_get_int64_list(FlValue* value); + +/** + * fl_value_get_float_list: + * @value: an #FlValue of type #FL_VALUE_TYPE_FLOAT_LIST + * + * Gets the array of floating point numbers @value contains. The data + * contains fl_get_length() elements. Calling this with an #FlValue that is + * not of type #FL_VALUE_TYPE_FLOAT_LIST is a programming error. + * + * Returns: an array of floating point numbers. + */ +const double* fl_value_get_float_list(FlValue* value); + +/** + * fl_value_get_list_value: + * @value: an #FlValue of type #FL_VALUE_TYPE_LIST. + * @index: an index in the list. + * + * Gets a child element of the list. It is a programming error to request an + * index that is outside the size of the list as returned from + * fl_value_get_length(). + * + * Returns: an #FlValue + */ +FlValue* fl_value_get_list_value(FlValue* value, size_t index); + +/** + * fl_value_get_map_key: + * @value: an #FlValue of type #FL_VALUE_TYPE_MAP. + * @index: an index in the map. + * + * Gets an key from the map. It is a programming error to request an index that + * is outside the size of the list as returned from fl_value_get_length(). + * + * Returns: an #FlValue + */ +FlValue* fl_value_get_map_key(FlValue* value, size_t index); + +/** + * fl_value_get_map_key: + * @value: an #FlValue of type #FL_VALUE_TYPE_MAP. + * @index: an index in the map. + * + * Gets a value from the map. It is a programming error to request an index that + * is outside the size of the list as returned from fl_value_get_length(). + * + * Returns: an #FlValue + */ +FlValue* fl_value_get_map_value(FlValue* value, size_t index); + +/** + * fl_value_lookup: + * @value: an #FlValue of type #FL_VALUE_TYPE_MAP + * @key: a key value + * + * Gets the map entry that matches @key. Keys are checked using + * fl_value_equal(). + * + * Map lookups are not optimised for performance - if have a large map or need + * frequent access you should copy the data into another structure, e.g. + * #GHashTable. + * + * Returns: (allow-none): the value with this key or %NULL if not one present. + */ +FlValue* fl_value_lookup(FlValue* value, FlValue* key); + +/** + * fl_value_lookup_string: + * @value: an #FlValue of type #FL_VALUE_TYPE_MAP + * @key: a key value + * + * Gets the map entry that matches @key. Keys are checked using + * fl_value_equal(). + * + * Map lookups are not optimised for performance - if have a large map or need + * frequent access you should copy the data into another structure, e.g. + * #GHashTable. + * + * Returns: (allow-none): the value with this key or %NULL if not one present. + */ +FlValue* fl_value_lookup_string(FlValue* value, const gchar* key); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FlValue, fl_value_unref) + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_VALUE_H_ diff --git a/shell/platform/linux/public/flutter_linux/flutter_linux.h b/shell/platform/linux/public/flutter_linux/flutter_linux.h index 74e8a142496dd..eba981f208340 100644 --- a/shell/platform/linux/public/flutter_linux/flutter_linux.h +++ b/shell/platform/linux/public/flutter_linux/flutter_linux.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #undef __FLUTTER_LINUX_INSIDE__