From 093f434cd0c745b544f098a1745d0e1015af869f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 20 Oct 2021 10:53:39 +0200 Subject: [PATCH] libnm: add direct property type "flags" "flags" are a g_param_spec_flags() and correspond to G_TYPE_FLAGS type. They are internally stored as guint, and exported on D-Bus as "u" (32 bit integer). --- src/libnm-core-impl/nm-setting-private.h | 61 ++++++++++++++++++ src/libnm-core-impl/nm-setting.c | 82 ++++++++++++++++++++++++ src/libnm-core-impl/tests/test-setting.c | 18 ++++++ src/libnm-glib-aux/nm-json-aux.h | 2 + src/libnm-glib-aux/nm-shared-utils.h | 12 ++++ src/libnm-glib-aux/nm-value-type.h | 19 ++++-- 6 files changed, 190 insertions(+), 4 deletions(-) diff --git a/src/libnm-core-impl/nm-setting-private.h b/src/libnm-core-impl/nm-setting-private.h index b7c60536a0..2e72b9342c 100644 --- a/src/libnm-core-impl/nm-setting-private.h +++ b/src/libnm-core-impl/nm-setting-private.h @@ -292,6 +292,7 @@ extern const NMSettInfoPropertType nm_sett_info_propert_type_direct_boolean; extern const NMSettInfoPropertType nm_sett_info_propert_type_direct_int32; extern const NMSettInfoPropertType nm_sett_info_propert_type_direct_uint32; extern const NMSettInfoPropertType nm_sett_info_propert_type_direct_string; +extern const NMSettInfoPropertType nm_sett_info_propert_type_direct_flags; extern const NMSettInfoPropertType nm_sett_info_propert_type_direct_mac_address; NMSettingVerifyResult @@ -659,6 +660,66 @@ _nm_properties_override(GArray *properties_override, const NMSettInfoProperty *p /*****************************************************************************/ +#define _nm_setting_property_define_direct_flags(properties_override, \ + obj_properties, \ + prop_name, \ + prop_id, \ + gtype_flags, \ + default_value, \ + param_flags, \ + private_struct_type, \ + private_struct_field, \ + ... /* extra NMSettInfoProperty fields */) \ + G_STMT_START \ + { \ + GParamSpec *_param_spec; \ + \ + G_STATIC_ASSERT( \ + !NM_FLAGS_ANY((param_flags), \ + ~(NM_SETTING_PARAM_FUZZY_IGNORE | NM_SETTING_PARAM_INFERRABLE))); \ + \ + _param_spec = \ + g_param_spec_flags("" prop_name "", \ + "", \ + "", \ + (gtype_flags), \ + (default_value), \ + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | (param_flags)); \ + \ + (obj_properties)[(prop_id)] = _param_spec; \ + \ + _nm_properties_override_gobj( \ + (properties_override), \ + _param_spec, \ + &nm_sett_info_propert_type_direct_flags, \ + .direct_offset = \ + NM_STRUCT_OFFSET_ENSURE_TYPE(guint, private_struct_type, private_struct_field), \ + __VA_ARGS__); \ + } \ + G_STMT_END + +/*****************************************************************************/ + +#define _nm_setting_property_define_direct_secret_flags(properties_override, \ + obj_properties, \ + prop_name, \ + prop_id, \ + private_struct_type, \ + private_struct_field, \ + ... /* extra NMSettInfoProperty fields */) \ + _nm_setting_property_define_direct_flags((properties_override), \ + (obj_properties), \ + prop_name, \ + (prop_id), \ + NM_TYPE_SETTING_SECRET_FLAGS, \ + NM_SETTING_SECRET_FLAG_NONE, \ + NM_SETTING_PARAM_NONE, \ + private_struct_type, \ + private_struct_field, \ + ##__VA_ARGS__) + +/*****************************************************************************/ + #define _nm_setting_property_define_direct_mac_address(properties_override, \ obj_properties, \ prop_name, \ diff --git a/src/libnm-core-impl/nm-setting.c b/src/libnm-core-impl/nm-setting.c index 57e47de13c..b6f74368e6 100644 --- a/src/libnm-core-impl/nm-setting.c +++ b/src/libnm-core-impl/nm-setting.c @@ -744,6 +744,14 @@ _nm_setting_property_get_property_direct(GObject * object, g_value_set_uint(value, *p_val); return; } + case NM_VALUE_TYPE_FLAGS: + { + const guint *p_val = + _nm_setting_get_private(setting, sett_info, property_info->direct_offset); + + g_value_set_flags(value, *p_val); + return; + } case NM_VALUE_TYPE_STRING: { const char *const *p_val = @@ -823,6 +831,17 @@ _nm_setting_property_set_property_direct(GObject * object, nm_assert(*p_val == v); goto out_notify; } + case NM_VALUE_TYPE_FLAGS: + { + guint *p_val = _nm_setting_get_private(setting, sett_info, property_info->direct_offset); + guint v; + + v = g_value_get_flags(value); + if (*p_val == v) + return; + *p_val = v; + goto out_notify; + } case NM_VALUE_TYPE_STRING: if (!_property_direct_set_string( property_info, @@ -900,6 +919,17 @@ _init_direct(NMSetting *setting) *p_val = def_val; break; } + case NM_VALUE_TYPE_FLAGS: + { + guint *p_val = + _nm_setting_get_private(setting, sett_info, property_info->direct_offset); + guint def_val; + + def_val = NM_G_PARAM_SPEC_GET_DEFAULT_FLAGS(property_info->param_spec); + nm_assert(*p_val == 0); + *p_val = def_val; + break; + } case NM_VALUE_TYPE_STRING: nm_assert(!NM_G_PARAM_SPEC_GET_DEFAULT_STRING(property_info->param_spec)); nm_assert(!( @@ -937,6 +967,7 @@ _finalize_direct(NMSetting *setting) case NM_VALUE_TYPE_BOOL: case NM_VALUE_TYPE_INT32: case NM_VALUE_TYPE_UINT32: + case NM_VALUE_TYPE_FLAGS: break; case NM_VALUE_TYPE_STRING: { @@ -991,6 +1022,17 @@ _nm_setting_property_to_dbus_fcn_direct(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_ return NULL; return g_variant_new_uint32(val); } + case NM_VALUE_TYPE_FLAGS: + { + guint val; + + val = + *((guint *) _nm_setting_get_private(setting, sett_info, property_info->direct_offset)); + if (!property_info->to_dbus_including_default + && val == NM_G_PARAM_SPEC_GET_DEFAULT_FLAGS(property_info->param_spec)) + return NULL; + return g_variant_new_uint32(val); + } case NM_VALUE_TYPE_STRING: { const char *val; @@ -1224,6 +1266,35 @@ _nm_setting_property_from_dbus_fcn_direct(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS *p_val = v; goto out_notify; } + case NM_VALUE_TYPE_FLAGS: + { + const GParamSpecFlags *param_spec; + guint * p_val; + guint v; + + param_spec = NM_G_PARAM_SPEC_CAST_FLAGS(property_info->param_spec); + + if (g_variant_is_of_type(value, G_VARIANT_TYPE_UINT32)) { + G_STATIC_ASSERT(sizeof(guint) >= sizeof(guint32)); + v = g_variant_get_uint32(value); + } else { + if (!_variant_get_value_transform(property_info, + value, + G_TYPE_FROM_CLASS(param_spec->flags_class), + g_value_get_flags, + &v)) + goto out_error_wrong_dbus_type; + } + + p_val = _nm_setting_get_private(setting, sett_info, property_info->direct_offset); + if (*p_val == v) + goto out_unchanged; + + if ((v & param_spec->flags_class->mask) != v) + goto out_error_param_spec_validation; + *p_val = v; + goto out_notify; + } case NM_VALUE_TYPE_STRING: { gs_free char *v_free = NULL; @@ -2144,6 +2215,8 @@ _nm_setting_property_compare_fcn_direct(_NM_SETT_INFO_PROP_COMPARE_FCN_ARGS _nm_ return *((const gint32 *) p_a) == *((const gint32 *) p_b); case NM_VALUE_TYPE_UINT32: return *((const guint32 *) p_a) == *((const guint32 *) p_b); + case NM_VALUE_TYPE_FLAGS: + return *((const guint *) p_a) == *((const guint *) p_b); case NM_VALUE_TYPE_STRING: return nm_streq0(*((const char *const *) p_a), *((const char *const *) p_b)); default: @@ -3198,6 +3271,15 @@ const NMSettInfoPropertType nm_sett_info_propert_type_direct_string = .from_dbus_is_full = TRUE, .from_dbus_direct_allow_transform = TRUE); +const NMSettInfoPropertType nm_sett_info_propert_type_direct_flags = + NM_SETT_INFO_PROPERT_TYPE_DBUS_INIT(G_VARIANT_TYPE_UINT32, + .direct_type = NM_VALUE_TYPE_FLAGS, + .compare_fcn = _nm_setting_property_compare_fcn_direct, + .to_dbus_fcn = _nm_setting_property_to_dbus_fcn_direct, + .from_dbus_fcn = _nm_setting_property_from_dbus_fcn_direct, + .from_dbus_is_full = TRUE, + .from_dbus_direct_allow_transform = TRUE); + const NMSettInfoPropertType nm_sett_info_propert_type_direct_mac_address = NM_SETT_INFO_PROPERT_TYPE_DBUS_INIT( G_VARIANT_TYPE_BYTESTRING, diff --git a/src/libnm-core-impl/tests/test-setting.c b/src/libnm-core-impl/tests/test-setting.c index b71b49fed7..ded2476abc 100644 --- a/src/libnm-core-impl/tests/test-setting.c +++ b/src/libnm-core-impl/tests/test-setting.c @@ -4489,6 +4489,24 @@ test_setting_metadata(void) g_assert_cmpint(pspec->maximum, <=, (guint64) G_MAXUINT32); + can_set_including_default = TRUE; + } else if (sip->property_type->direct_type == NM_VALUE_TYPE_FLAGS) { + const GParamSpecFlags *pspec; + + g_assert(sip->property_type == &nm_sett_info_propert_type_direct_flags); + g_assert(g_variant_type_equal(sip->property_type->dbus_type, "u")); + g_assert(sip->property_type->to_dbus_fcn + == _nm_setting_property_to_dbus_fcn_direct); + g_assert(sip->param_spec); + g_assert(g_type_is_a(sip->param_spec->value_type, G_TYPE_FLAGS)); + g_assert(sip->param_spec->value_type != G_TYPE_FLAGS); + + pspec = NM_G_PARAM_SPEC_CAST_FLAGS(sip->param_spec); + g_assert_cmpint(pspec->flags_class->mask, !=, 0); + g_assert_cmpint(pspec->default_value, + ==, + pspec->flags_class->mask & pspec->default_value); + can_set_including_default = TRUE; } else if (sip->property_type->direct_type == NM_VALUE_TYPE_STRING) { if (sip->property_type == &nm_sett_info_propert_type_direct_mac_address) { diff --git a/src/libnm-glib-aux/nm-json-aux.h b/src/libnm-glib-aux/nm-json-aux.h index ba2b35d27c..6229766898 100644 --- a/src/libnm-glib-aux/nm-json-aux.h +++ b/src/libnm-glib-aux/nm-json-aux.h @@ -380,6 +380,7 @@ nm_value_type_to_json(NMValueType value_type, GString *gstr, gconstpointer p_fie nm_json_gstr_append_uint64(gstr, *((const guint32 *) p_field)); return; case NM_VALUE_TYPE_UINT: + case NM_VALUE_TYPE_FLAGS: nm_json_gstr_append_uint64(gstr, *((const guint *) p_field)); return; case NM_VALUE_TYPE_UINT64: @@ -413,6 +414,7 @@ nm_value_type_from_json(const NMJsonVt * vt, case NM_VALUE_TYPE_UINT32: return (nm_jansson_json_as_uint32(vt, elem, out_val) > 0); case NM_VALUE_TYPE_UINT: + case NM_VALUE_TYPE_FLAGS: return (nm_jansson_json_as_uint(vt, elem, out_val) > 0); case NM_VALUE_TYPE_UINT64: return (nm_jansson_json_as_uint64(vt, elem, out_val) > 0); diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h index 26dfebd35d..6390a85d78 100644 --- a/src/libnm-glib-aux/nm-shared-utils.h +++ b/src/libnm-glib-aux/nm-shared-utils.h @@ -1450,6 +1450,14 @@ GParamSpec *nm_g_object_class_find_property_from_gtype(GType gtype, const char * ((const _c_type *) _param_spec); \ }) +#define _NM_G_PARAM_SPEC_CAST_IS_A(param_spec, _value_type, _c_type) \ + ({ \ + const GParamSpec *const _param_spec = (param_spec); \ + \ + nm_assert(!_param_spec || g_type_is_a(_param_spec->value_type, _value_type)); \ + ((const _c_type *) _param_spec); \ + }) + #define NM_G_PARAM_SPEC_CAST_BOOLEAN(param_spec) \ _NM_G_PARAM_SPEC_CAST(param_spec, G_TYPE_BOOLEAN, GParamSpecBoolean) #define NM_G_PARAM_SPEC_CAST_INT(param_spec) \ @@ -1458,6 +1466,8 @@ GParamSpec *nm_g_object_class_find_property_from_gtype(GType gtype, const char * _NM_G_PARAM_SPEC_CAST(param_spec, G_TYPE_UINT, GParamSpecUInt) #define NM_G_PARAM_SPEC_CAST_UINT64(param_spec) \ _NM_G_PARAM_SPEC_CAST(param_spec, G_TYPE_UINT64, GParamSpecUInt64) +#define NM_G_PARAM_SPEC_CAST_FLAGS(param_spec) \ + _NM_G_PARAM_SPEC_CAST_IS_A(param_spec, G_TYPE_FLAGS, GParamSpecFlags) #define NM_G_PARAM_SPEC_CAST_STRING(param_spec) \ _NM_G_PARAM_SPEC_CAST(param_spec, G_TYPE_STRING, GParamSpecString) @@ -1469,6 +1479,8 @@ GParamSpec *nm_g_object_class_find_property_from_gtype(GType gtype, const char * (NM_G_PARAM_SPEC_CAST_UINT(NM_ENSURE_NOT_NULL(param_spec))->default_value) #define NM_G_PARAM_SPEC_GET_DEFAULT_UINT64(param_spec) \ (NM_G_PARAM_SPEC_CAST_UINT64(NM_ENSURE_NOT_NULL(param_spec))->default_value) +#define NM_G_PARAM_SPEC_GET_DEFAULT_FLAGS(param_spec) \ + (NM_G_PARAM_SPEC_CAST_FLAGS(NM_ENSURE_NOT_NULL(param_spec))->default_value) #define NM_G_PARAM_SPEC_GET_DEFAULT_STRING(param_spec) \ (NM_G_PARAM_SPEC_CAST_STRING(NM_ENSURE_NOT_NULL(param_spec))->default_value) diff --git a/src/libnm-glib-aux/nm-value-type.h b/src/libnm-glib-aux/nm-value-type.h index 4e54ad463c..a64664e14b 100644 --- a/src/libnm-glib-aux/nm-value-type.h +++ b/src/libnm-glib-aux/nm-value-type.h @@ -16,7 +16,13 @@ typedef enum _nm_packed { NM_VALUE_TYPE_UINT32 = 6, NM_VALUE_TYPE_UINT = 7, NM_VALUE_TYPE_UINT64 = 8, - NM_VALUE_TYPE_STRING = 9, + + /* Flags are for G_TYPE_FLAGS. That is, internally they are tracked + * as a guint, they have a g_param_spec_flags() property and they are + * serialized on D-Bus as "u". */ + NM_VALUE_TYPE_FLAGS = 9, + + NM_VALUE_TYPE_STRING = 10, } NMValueType; /*****************************************************************************/ @@ -92,6 +98,7 @@ nm_value_type_cmp(NMValueType value_type, gconstpointer p_a, gconstpointer p_b) NM_CMP_DIRECT(*((const guint32 *) p_a), *((const guint32 *) p_b)); return 0; case NM_VALUE_TYPE_UINT: + case NM_VALUE_TYPE_FLAGS: NM_CMP_DIRECT(*((const guint *) p_a), *((const guint *) p_b)); return 0; case NM_VALUE_TYPE_UINT64: @@ -133,6 +140,7 @@ nm_value_type_copy(NMValueType value_type, gpointer dst, gconstpointer src) (*((guint32 *) dst) = *((const guint32 *) src)); return; case NM_VALUE_TYPE_UINT: + case NM_VALUE_TYPE_FLAGS: (*((guint *) dst) = *((const guint *) src)); return; case NM_VALUE_TYPE_UINT64: @@ -186,7 +194,8 @@ nm_value_type_get_from_variant(NMValueType value_type, case NM_VALUE_TYPE_INT: case NM_VALUE_TYPE_UINT: - /* "int" and "uint" also does not have a defined variant type, because it's not + case NM_VALUE_TYPE_FLAGS: + /* These types don't have a defined variant type, because it's not * clear how many bits we would need. */ /* fall-through */ @@ -219,7 +228,8 @@ nm_value_type_to_variant(NMValueType value_type, gconstpointer src) case NM_VALUE_TYPE_INT: case NM_VALUE_TYPE_UINT: - /* "int" and "uint" also does not have a defined variant type, because it's not + case NM_VALUE_TYPE_FLAGS: + /* These types don't have a defined variant type, because it's not * clear how many bits we would need. */ /* fall-through */ @@ -250,7 +260,8 @@ nm_value_type_get_variant_type(NMValueType value_type) case NM_VALUE_TYPE_INT: case NM_VALUE_TYPE_UINT: - /* "int" and "uint" also does not have a defined variant type, because it's not + case NM_VALUE_TYPE_FLAGS: + /* These types don't have a defined variant type, because it's not * clear how many bits we would need. */ /* fall-through */