diff --git a/src/libnm-core-impl/nm-setting.c b/src/libnm-core-impl/nm-setting.c index 542ae6a80f..ce47c9bd1a 100644 --- a/src/libnm-core-impl/nm-setting.c +++ b/src/libnm-core-impl/nm-setting.c @@ -645,11 +645,16 @@ _property_direct_set_string(const NMSettInfoSetting *sett_info, char **dst; char *s; + nm_assert(property_info->property_type->direct_type == NM_VALUE_TYPE_STRING); nm_assert(((!!property_info->direct_set_string_ascii_strdown) + (!!property_info->direct_set_string_strip) + (property_info->direct_set_string_mac_address_len > 0) + (property_info->direct_set_string_ip_address_addr_family != 0)) - <= 1); + <= (property_info->direct_hook.set_string_fcn ? 0 : 1)); + + if (property_info->direct_hook.set_string_fcn) { + return property_info->direct_hook.set_string_fcn(sett_info, property_info, setting, src); + } dst = _nm_setting_get_private(setting, sett_info, property_info->direct_offset); diff --git a/src/libnm-core-impl/tests/test-setting.c b/src/libnm-core-impl/tests/test-setting.c index 9ccedab806..0540b716a4 100644 --- a/src/libnm-core-impl/tests/test-setting.c +++ b/src/libnm-core-impl/tests/test-setting.c @@ -4430,6 +4430,7 @@ test_setting_metadata(void) GArray *property_types_data; guint prop_idx_val; gboolean can_set_including_default = FALSE; + gboolean can_have_direct_hook = FALSE; int n_special_options; g_assert(sip->name); @@ -4572,6 +4573,7 @@ test_setting_metadata(void) g_assert(g_variant_type_equal(sip->property_type->dbus_type, "s")); g_assert(sip->property_type->to_dbus_fcn == _nm_setting_property_to_dbus_fcn_direct); + can_have_direct_hook = TRUE; } g_assert(sip->param_spec); g_assert(sip->param_spec->value_type == G_TYPE_STRING); @@ -4596,6 +4598,9 @@ test_setting_metadata(void) g_assert(sip->property_type->direct_type == NM_VALUE_TYPE_STRING); } + if (!can_have_direct_hook) + g_assert(!sip->direct_hook.set_string_fcn); + n_special_options = (sip->direct_set_string_mac_address_len != 0) + (!!sip->direct_set_string_strip) + (!!sip->direct_set_string_ascii_strdown) diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h index 50590f12a3..aee2a47263 100644 --- a/src/libnm-core-intern/nm-core-internal.h +++ b/src/libnm-core-intern/nm-core-internal.h @@ -746,8 +746,37 @@ struct _NMSettInfoProperty { GParamSpec *param_spec; + /* We want that our properties follow a small number of "default" types + * and behaviors. For example, we have int32 and string properties, but + * most properties of a certain type should behave in a similar way. + * + * That common behavior is realized via the property_type, which defines + * general behaviors for the property. + * + * Note that we still will need some property-specific additional tweaks. + * Of course, the name and param_spec are per-property. But below there are + * also flags and hooks, that can augment the behavior in the property_type. + * For example, the property_type in general might be of type string, but + * then we might want for some properties that the setter will strip + * whitespace. That is for example express with the flag direct_set_string_strip, + * which now is per-property-info, and no longer per-property-type. + * + * The distinction between those two is fixed. At the most extreme, we could + * move all fields from property_type to NMSettInfoProperty or we could move + * behavioral tweaks into the classes themselves. It's chosen this way so + * that we still have sensible common behaviors (string type), but minor + * tweaks are per property-info (and don't require a separate property-type). */ const NMSettInfoPropertType *property_type; + union { + /* Optional hook for direct string properties, this gets called when setting the string. + * Return whether the value changed. */ + gboolean (*set_string_fcn)(const NMSettInfoSetting *sett_info, + const NMSettInfoProperty *property_info, + NMSetting *setting, + const char *src); + } direct_hook; + /* This only has meaning for direct properties (property_type->direct_type != NM_VALUE_TYPE_UNSPEC). * In that case, this is the offset where _nm_setting_get_private() can find * the direct location. */