libnm: refactor NMSettInfoProperty to save memory for simple properties

In total, we register 447 property informations. Out of these,
326 are plain, GObject property based without special implementations.

The NMSettInfoProperty had all function pointers directly embedded,
currently this amounts to 5 function pointers and the "dbus_type" field.

That means, at runtime we have 326 times trivial implementations with
waste 326*6*8 bytes of NULL pointers. We can compact these by moving
them to a separate structure.

Before:

    447 * 5 function pointers
    447 * "dbus_type" pointer
    = 2682 pointers

After:

    447 * 1 pointers (for NMSettInfoProperty.property_type)
     89 * 6 pointers (for the distinct NMSettInfoPropertType data)
    = 981 pointers

So, in total this saves 13608 byes of runtime memory (on 64 bit arch).

The 89 NMSettInfoPropertType instances are the remaining distinct instances.
Note that every NMSettInfoProperty has a "property_type" pointer, but most of them are
shared. That is because the underlying type and the operations are the same.

Also nice is that the NMSettInfoPropertType are actually constant,
static fields and initialized very early.

This change also makes sense form a design point of view. Previously,
NMSettInfoProperty contained both per-property data (the "name") but
also the behavior. Now, the "behavioral" part is moved to a separate
structure (where it is also shared). That means, the parts that are
concerned with the type of the property (the behavior) are separate
from the actual data of the property.
This commit is contained in:
Thomas Haller
2019-09-22 08:53:06 +02:00
parent f36a0d408b
commit 3f36f69156
19 changed files with 265 additions and 249 deletions

View File

@@ -712,10 +712,7 @@ typedef void (*NMSettInfoPropGPropFromDBusFcn) (GVariant *from,
const NMSettInfoSetting *nmtst_sett_info_settings (void);
struct _NMSettInfoProperty {
const char *name;
GParamSpec *param_spec;
typedef struct {
const GVariantType *dbus_type;
NMSettInfoPropToDBusFcn to_dbus_fcn;
@@ -726,6 +723,14 @@ struct _NMSettInfoProperty {
* on the GValue value of the GObject property. */
NMSettInfoPropGPropToDBusFcn gprop_to_dbus_fcn;
NMSettInfoPropGPropFromDBusFcn gprop_from_dbus_fcn;
} NMSettInfoPropertType;
struct _NMSettInfoProperty {
const char *name;
GParamSpec *param_spec;
const NMSettInfoPropertType *property_type;
};
typedef struct {

View File

@@ -973,7 +973,7 @@ nm_setting_bond_class_init (NMSettingBondClass *klass)
_properties_override_add_transform (properties_override,
obj_properties[PROP_OPTIONS],
G_VARIANT_TYPE ("a{ss}"),
NM_G_VARIANT_TYPE ("a{ss}"),
_nm_utils_strdict_to_dbus,
_nm_utils_strdict_from_dbus);

View File

@@ -576,7 +576,7 @@ nm_setting_bridge_port_class_init (NMSettingBridgePortClass *klass)
_properties_override_add_override (properties_override,
obj_properties[PROP_VLANS],
G_VARIANT_TYPE ("aa{sv}"),
NM_G_VARIANT_TYPE ("aa{sv}"),
_nm_utils_bridge_vlans_to_dbus,
_nm_utils_bridge_vlans_from_dbus,
NULL);

View File

@@ -1469,7 +1469,7 @@ nm_setting_bridge_class_init (NMSettingBridgeClass *klass)
_properties_override_add_override (properties_override,
obj_properties[PROP_VLANS],
G_VARIANT_TYPE ("aa{sv}"),
NM_G_VARIANT_TYPE ("aa{sv}"),
_nm_utils_bridge_vlans_to_dbus,
_nm_utils_bridge_vlans_from_dbus,
NULL);

View File

@@ -1100,7 +1100,7 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
_properties_override_add_transform (properties_override,
obj_properties[PROP_PRIORITY_FLOW_CONTROL],
G_VARIANT_TYPE ("au"),
NM_G_VARIANT_TYPE ("au"),
_nm_setting_dcb_uint_array_to_dbus,
_nm_setting_dcb_uint_array_from_dbus);
@@ -1148,7 +1148,7 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
_properties_override_add_transform (properties_override,
obj_properties[PROP_PRIORITY_GROUP_ID],
G_VARIANT_TYPE ("au"),
NM_G_VARIANT_TYPE ("au"),
_nm_setting_dcb_uint_array_to_dbus,
_nm_setting_dcb_uint_array_from_dbus);
@@ -1175,7 +1175,7 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
_properties_override_add_transform (properties_override,
obj_properties[PROP_PRIORITY_GROUP_BANDWIDTH],
G_VARIANT_TYPE ("au"),
NM_G_VARIANT_TYPE ("au"),
_nm_setting_dcb_uint_array_to_dbus,
_nm_setting_dcb_uint_array_from_dbus);
@@ -1204,7 +1204,7 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
_properties_override_add_transform (properties_override,
obj_properties[PROP_PRIORITY_BANDWIDTH],
G_VARIANT_TYPE ("au"),
NM_G_VARIANT_TYPE ("au"),
_nm_setting_dcb_uint_array_to_dbus,
_nm_setting_dcb_uint_array_from_dbus);
@@ -1231,7 +1231,7 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
_properties_override_add_transform (properties_override,
obj_properties[PROP_PRIORITY_STRICT_BANDWIDTH],
G_VARIANT_TYPE ("au"),
NM_G_VARIANT_TYPE ("au"),
_nm_setting_dcb_uint_array_to_dbus,
_nm_setting_dcb_uint_array_from_dbus);
@@ -1257,7 +1257,7 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
_properties_override_add_transform (properties_override,
obj_properties[PROP_PRIORITY_TRAFFIC_CLASS],
G_VARIANT_TYPE ("au"),
NM_G_VARIANT_TYPE ("au"),
_nm_setting_dcb_uint_array_to_dbus,
_nm_setting_dcb_uint_array_from_dbus);

View File

@@ -5209,7 +5209,7 @@ _nm_sett_info_property_override_create_array_ip_config (void)
*/
_properties_override_add_dbus_only (properties_override,
NM_SETTING_IP_CONFIG_ROUTING_RULES,
G_VARIANT_TYPE ("aa{sv}"),
NM_G_VARIANT_TYPE ("aa{sv}"),
_routing_rules_dbus_only_synth,
_routing_rules_dbus_only_set);

View File

@@ -799,7 +799,7 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *klass)
_properties_override_add_transform (properties_override,
g_object_class_find_property (G_OBJECT_CLASS (setting_class),
NM_SETTING_IP_CONFIG_DNS),
G_VARIANT_TYPE ("au"),
NM_G_VARIANT_TYPE ("au"),
ip4_dns_to_dbus,
ip4_dns_from_dbus);
@@ -821,7 +821,7 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *klass)
_properties_override_add_override (properties_override,
g_object_class_find_property (G_OBJECT_CLASS (setting_class),
NM_SETTING_IP_CONFIG_ADDRESSES),
G_VARIANT_TYPE ("aau"),
NM_G_VARIANT_TYPE ("aau"),
ip4_addresses_get,
ip4_addresses_set,
NULL);
@@ -843,7 +843,7 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *klass)
*/
_properties_override_add_dbus_only (properties_override,
"address-data",
G_VARIANT_TYPE ("aa{sv}"),
NM_G_VARIANT_TYPE ("aa{sv}"),
ip4_address_data_get,
ip4_address_data_set);
@@ -867,7 +867,7 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *klass)
_properties_override_add_override (properties_override,
g_object_class_find_property (G_OBJECT_CLASS (setting_class),
NM_SETTING_IP_CONFIG_ROUTES),
G_VARIANT_TYPE ("aau"),
NM_G_VARIANT_TYPE ("aau"),
ip4_routes_get,
ip4_routes_set,
NULL);
@@ -887,7 +887,7 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *klass)
*/
_properties_override_add_dbus_only (properties_override,
"route-data",
G_VARIANT_TYPE ("aa{sv}"),
NM_G_VARIANT_TYPE ("aa{sv}"),
ip4_route_data_get,
ip4_route_data_set);

View File

@@ -883,7 +883,7 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *klass)
_properties_override_add_transform (properties_override,
g_object_class_find_property (G_OBJECT_CLASS (setting_class),
NM_SETTING_IP_CONFIG_DNS),
G_VARIANT_TYPE ("aay"),
NM_G_VARIANT_TYPE ("aay"),
ip6_dns_to_dbus,
ip6_dns_from_dbus);
@@ -904,7 +904,7 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *klass)
_properties_override_add_override (properties_override,
g_object_class_find_property (G_OBJECT_CLASS (setting_class),
NM_SETTING_IP_CONFIG_ADDRESSES),
G_VARIANT_TYPE ("a(ayuay)"),
NM_G_VARIANT_TYPE ("a(ayuay)"),
ip6_addresses_get,
ip6_addresses_set,
NULL);
@@ -920,7 +920,7 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *klass)
*/
_properties_override_add_dbus_only (properties_override,
"address-data",
G_VARIANT_TYPE ("aa{sv}"),
NM_G_VARIANT_TYPE ("aa{sv}"),
ip6_address_data_get,
ip6_address_data_set);
@@ -941,7 +941,7 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *klass)
_properties_override_add_override (properties_override,
g_object_class_find_property (G_OBJECT_CLASS (setting_class),
NM_SETTING_IP_CONFIG_ROUTES),
G_VARIANT_TYPE ("a(ayuayu)"),
NM_G_VARIANT_TYPE ("a(ayuayu)"),
ip6_routes_get,
ip6_routes_set,
NULL);
@@ -961,7 +961,7 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *klass)
*/
_properties_override_add_dbus_only (properties_override,
"route-data",
G_VARIANT_TYPE ("aa{sv}"),
NM_G_VARIANT_TYPE ("aa{sv}"),
ip6_route_data_get,
ip6_route_data_set);

View File

@@ -143,6 +143,15 @@ _nm_setting_class_commit (NMSettingClass *setting_class,
__VA_ARGS__ \
}))
#define NM_SETT_INFO_PROPERT_TYPE(...) \
({ \
static const NMSettInfoPropertType _g = { \
__VA_ARGS__ \
}; \
\
&_g; \
})
#define NM_SETT_INFO_PROPERTY(...) \
(&((const NMSettInfoProperty) { \
__VA_ARGS__ \
@@ -151,32 +160,129 @@ _nm_setting_class_commit (NMSettingClass *setting_class,
void _properties_override_add_struct (GArray *properties_override,
const NMSettInfoProperty *prop_info);
void _properties_override_add__helper (GArray *properties_override,
NMSettInfoProperty *prop_info);
#define _properties_override_add(properties_override, \
...) \
(_properties_override_add_struct (properties_override, \
NM_SETT_INFO_PROPERTY (__VA_ARGS__)))
void _properties_override_add_dbus_only (GArray *properties_override,
const char *property_name,
const GVariantType *dbus_type,
NMSettInfoPropToDBusFcn to_dbus_fcn,
NMSettInfoPropFromDBusFcn from_dbus_fcn);
/**
* _properties_override_add_dbus_only:
* @properties_override: an array collecting the overrides
* @p_property_name: the name of the property to override
* @p_dbus_type: the type of the property (in its D-Bus representation)
* @p_to_dbus_fcn: (allow-none): function to call to synthesize a value for the property
* @p_from_dbus_fcn: (allow-none): function to call to set the value of the property
*
* Registers a property named @p_property_name, which will be used in the D-Bus
* serialization of objects of this setting type, but which does not correspond to
* a #GObject property.
*
* When serializing a setting to D-Bus, @p_to_dbus_fcn will be called to synthesize
* a value for the property. (If it returns %NULL, no value will be added to the
* serialization. If @p_to_dbus_fcn is %NULL, the property will always be omitted
* in the serialization.)
*
* When deserializing a D-Bus representation into a setting, if @p_property_name
* is present, then @p_from_dbus_fcn will be called to set it. (If @p_from_dbus_fcn is %NULL
* then the property will be ignored when deserializing.)
*/
#define _properties_override_add_dbus_only(properties_override, \
p_property_name, \
p_dbus_type, \
p_to_dbus_fcn, \
p_from_dbus_fcn) \
_properties_override_add ((properties_override), \
.name = (p_property_name), \
.property_type = NM_SETT_INFO_PROPERT_TYPE ( \
.dbus_type = (p_dbus_type), \
.to_dbus_fcn = (p_to_dbus_fcn), \
.from_dbus_fcn = (p_from_dbus_fcn), \
))
void _properties_override_add_override (GArray *properties_override,
GParamSpec *param_spec,
const GVariantType *dbus_type,
NMSettInfoPropToDBusFcn to_dbus_fcn,
NMSettInfoPropFromDBusFcn from_dbus_fcn,
NMSettInfoPropMissingFromDBusFcn missing_from_dbus_fcn);
/**
* _properties_override_add_override:
* @properties_override: an array collecting the overrides
* @p_param_spec: the name of the property to override
* @p_dbus_type: the type of the property (in its D-Bus representation)
* @p_to_dbus_fcn: (allow-none): function to call to get the value of the property
* @p_from_dbus_fcn: (allow-none): function to call to set the value of the property
* @p_missing_from_dbus_fcn: (allow-none): function to call to indicate the property was not set
*
* Overrides the D-Bus representation of the #GObject property that shares the
* same name as @p_param_spec.
*
* When serializing a setting to D-Bus, if @p_to_dbus_fcn is non-%NULL, then it will
* be called to get the property's value. If it returns a #GVariant, the
* property will be added to the hash, and if it returns %NULL, the property
* will be omitted. (If @p_to_dbus_fcn is %NULL, the property will be read normally
* with g_object_get_property(), and added to the hash if it is not the default
* value.)
*
* When deserializing a D-Bus representation into a setting, if a value with
* the name of @p_param_spec is present, then @p_from_dbus_fcn will be called to set it.
* (If @p_from_dbus_fcn is %NULL then the property will be set normally with
* g_object_set_property().)
*
* If @p_missing_from_dbus_fcn is non-%NULL, then it will be called when deserializing a
* representation that does NOT contain a value for the property. This can be used,
* eg, if a new property needs to be initialized from some older deprecated property
* when it is not present.
*/
#define _properties_override_add_override(properties_override, \
p_param_spec, \
p_dbus_type, \
p_to_dbus_fcn, \
p_from_dbus_fcn, \
p_missing_from_dbus_fcn) \
({ \
GParamSpec *const _param_spec = (p_param_spec); \
\
nm_assert (_param_spec); \
\
_properties_override_add ((properties_override), \
.param_spec = (_param_spec), \
.property_type = NM_SETT_INFO_PROPERT_TYPE ( \
.dbus_type = (p_dbus_type), \
.to_dbus_fcn = (p_to_dbus_fcn), \
.from_dbus_fcn = (p_from_dbus_fcn), \
.missing_from_dbus_fcn = (p_missing_from_dbus_fcn), \
)); \
})
void _properties_override_add_transform (GArray *properties_override,
GParamSpec *param_spec,
const GVariantType *dbus_type,
NMSettInfoPropGPropToDBusFcn gprop_to_dbus_fcn,
NMSettInfoPropGPropFromDBusFcn gprop_from_dbus_fcn);
/**
* _properties_override_add_transform:
* @properties_override: an array collecting the overrides
* @p_param_spec: the param spec of the property to transform.
* @p_dbus_type: the type of the property (in its D-Bus representation)
* @p_gprop_to_dbus_fcn: function to convert from object to D-Bus format
* @p_gprop_from_dbus_fcn: function to convert from D-Bus to object format
*
* Indicates that @property on @setting_class does not have the same format as
* its corresponding D-Bus representation, and so must be transformed when
* serializing/deserializing.
*
* The transformation will also be used by nm_setting_compare(), meaning that
* the underlying object property does not need to be of a type that
* nm_property_compare() recognizes, as long as it recognizes @p_dbus_type.
*/
#define _properties_override_add_transform(properties_override, \
p_param_spec, \
p_dbus_type, \
p_gprop_to_dbus_fcn, \
p_gprop_from_dbus_fcn) \
({ \
GParamSpec *const _param_spec = (p_param_spec); \
\
nm_assert (_param_spec); \
\
_properties_override_add ((properties_override), \
.param_spec = (_param_spec), \
.property_type = NM_SETT_INFO_PROPERT_TYPE ( \
.dbus_type = (p_dbus_type), \
.gprop_to_dbus_fcn = (p_gprop_to_dbus_fcn), \
.gprop_from_dbus_fcn = (p_gprop_from_dbus_fcn), \
)); \
})
/*****************************************************************************/

View File

@@ -1329,7 +1329,7 @@ nm_setting_sriov_class_init (NMSettingSriovClass *klass)
_properties_override_add_override (properties_override,
obj_properties[PROP_VFS],
G_VARIANT_TYPE ("aa{sv}"),
NM_G_VARIANT_TYPE ("aa{sv}"),
vfs_to_dbus,
vfs_from_dbus,
NULL);

View File

@@ -1803,7 +1803,7 @@ nm_setting_tc_config_class_init (NMSettingTCConfigClass *klass)
_properties_override_add_override (properties_override,
obj_properties[PROP_QDISCS],
G_VARIANT_TYPE ("aa{sv}"),
NM_G_VARIANT_TYPE ("aa{sv}"),
tc_qdiscs_get,
tc_qdiscs_set,
NULL);
@@ -1829,7 +1829,7 @@ nm_setting_tc_config_class_init (NMSettingTCConfigClass *klass)
_properties_override_add_override (properties_override,
obj_properties[PROP_TFILTERS],
G_VARIANT_TYPE ("aa{sv}"),
NM_G_VARIANT_TYPE ("aa{sv}"),
tc_tfilters_get,
tc_tfilters_set,
NULL);

View File

@@ -539,9 +539,11 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
#define _property_override(_properties_override, _param_spec, _variant_type, _is_link_watcher) \
_properties_override_add ((_properties_override), \
.param_spec = (_param_spec), \
.dbus_type = G_VARIANT_TYPE (""_variant_type""), \
.property_type = NM_SETT_INFO_PROPERT_TYPE ( \
.dbus_type = NM_G_VARIANT_TYPE (""_variant_type""), \
.to_dbus_fcn = _nm_team_settings_property_to_dbus, \
.gprop_from_dbus_fcn = ((_is_link_watcher) ? _nm_team_settings_property_from_dbus_link_watchers : NULL))
.gprop_from_dbus_fcn = ((_is_link_watcher) ? _nm_team_settings_property_from_dbus_link_watchers : NULL), \
))
/**
* NMSettingTeamPort:config:

View File

@@ -1486,9 +1486,11 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
#define _property_override(_properties_override, _param_spec, _variant_type, _is_link_watcher) \
_properties_override_add ((_properties_override), \
.param_spec = (_param_spec), \
.dbus_type = G_VARIANT_TYPE (""_variant_type""), \
.property_type = NM_SETT_INFO_PROPERT_TYPE ( \
.dbus_type = NM_G_VARIANT_TYPE (""_variant_type""), \
.to_dbus_fcn = _nm_team_settings_property_to_dbus, \
.gprop_from_dbus_fcn = ((_is_link_watcher) ? _nm_team_settings_property_from_dbus_link_watchers : NULL))
.gprop_from_dbus_fcn = ((_is_link_watcher) ? _nm_team_settings_property_from_dbus_link_watchers : NULL), \
))
/**
* NMSettingTeam:config:

View File

@@ -574,7 +574,7 @@ nm_setting_user_class_init (NMSettingUserClass *klass)
_properties_override_add_transform (properties_override,
obj_properties[PROP_DATA],
G_VARIANT_TYPE ("a{ss}"),
NM_G_VARIANT_TYPE ("a{ss}"),
_nm_utils_strdict_to_dbus,
_nm_utils_strdict_from_dbus);

View File

@@ -1132,7 +1132,7 @@ nm_setting_vpn_class_init (NMSettingVpnClass *klass)
_properties_override_add_transform (properties_override,
obj_properties[PROP_DATA],
G_VARIANT_TYPE ("a{ss}"),
NM_G_VARIANT_TYPE ("a{ss}"),
_nm_utils_strdict_to_dbus,
_nm_utils_strdict_from_dbus);
@@ -1159,7 +1159,7 @@ nm_setting_vpn_class_init (NMSettingVpnClass *klass)
_properties_override_add_override (properties_override,
obj_properties[PROP_SECRETS],
G_VARIANT_TYPE ("a{ss}"),
NM_G_VARIANT_TYPE ("a{ss}"),
vpn_secrets_to_dbus,
vpn_secrets_from_dbus,
NULL);

View File

@@ -1591,7 +1591,7 @@ nm_setting_wired_class_init (NMSettingWiredClass *klass)
_properties_override_add_transform (properties_override,
obj_properties[PROP_S390_OPTIONS],
G_VARIANT_TYPE ("a{ss}"),
NM_G_VARIANT_TYPE ("a{ss}"),
_nm_utils_strdict_to_dbus,
_nm_utils_strdict_from_dbus);

View File

@@ -2573,7 +2573,7 @@ nm_setting_wireguard_class_init (NMSettingWireGuardClass *klass)
*/
_properties_override_add_dbus_only (properties_override,
NM_SETTING_WIREGUARD_PEERS,
G_VARIANT_TYPE ("aa{sv}"),
NM_G_VARIANT_TYPE ("aa{sv}"),
_peers_dbus_only_synth,
_peers_dbus_only_set);

View File

@@ -206,150 +206,31 @@ void
_properties_override_add_struct (GArray *properties_override,
const NMSettInfoProperty *prop_info)
{
NMSettInfoProperty *p;
nm_assert (properties_override);
nm_assert (prop_info);
nm_assert (prop_info->name || prop_info->param_spec);
nm_assert ((!!prop_info->name) != (!!prop_info->param_spec));
nm_assert (!prop_info->param_spec || !prop_info->name || nm_streq0 (prop_info->name, prop_info->param_spec->name));
nm_assert (!_nm_sett_info_property_find_in_array ((NMSettInfoProperty *) properties_override->data,
properties_override->len,
prop_info->name ?: prop_info->param_spec->name));
nm_assert (!prop_info->gprop_from_dbus_fcn || prop_info->dbus_type);
nm_assert (!prop_info->from_dbus_fcn || prop_info->dbus_type);
nm_assert (!prop_info->to_dbus_fcn || prop_info->dbus_type);
#define _PROPERT_EXTRA(prop_info, member) \
({ \
const NMSettInfoProperty *_prop_info = (prop_info); \
\
(_prop_info->property_type ? _prop_info->property_type->member : 0); \
})
nm_assert (!prop_info->to_dbus_fcn || !prop_info->gprop_to_dbus_fcn);
nm_assert (!prop_info->from_dbus_fcn || !prop_info->gprop_from_dbus_fcn);
nm_assert (!_PROPERT_EXTRA (prop_info, gprop_from_dbus_fcn) || _PROPERT_EXTRA (prop_info, dbus_type));
nm_assert (!_PROPERT_EXTRA (prop_info, from_dbus_fcn) || _PROPERT_EXTRA (prop_info, dbus_type));
nm_assert (!_PROPERT_EXTRA (prop_info, to_dbus_fcn) || _PROPERT_EXTRA (prop_info, dbus_type));
nm_assert (!prop_info->gprop_to_dbus_fcn || prop_info->param_spec);
nm_assert (!prop_info->gprop_from_dbus_fcn || prop_info->param_spec);
nm_assert (!_PROPERT_EXTRA (prop_info, to_dbus_fcn) || !_PROPERT_EXTRA (prop_info, gprop_to_dbus_fcn));
nm_assert (!_PROPERT_EXTRA (prop_info, from_dbus_fcn) || !_PROPERT_EXTRA (prop_info, gprop_from_dbus_fcn));
nm_assert (!_PROPERT_EXTRA (prop_info, gprop_to_dbus_fcn) || prop_info->param_spec);
nm_assert (!_PROPERT_EXTRA (prop_info, gprop_from_dbus_fcn) || prop_info->param_spec);
#undef _PROPERT_EXTRA
g_array_append_vals (properties_override, prop_info, 1);
if (!prop_info->name) {
/* for convenience, allow omitting "name" if "param_spec" is given. */
p = &g_array_index (properties_override,
NMSettInfoProperty,
properties_override->len - 1);
nm_assert (p->param_spec);
p->name = p->param_spec->name;
}
}
/**
* _properties_override_add_dbus_only:
* @properties_override: an array collecting the overrides
* @property_name: the name of the property to override
* @dbus_type: the type of the property (in its D-Bus representation)
* @to_dbus_fcn: (allow-none): function to call to synthesize a value for the property
* @from_dbus_fcn: (allow-none): function to call to set the value of the property
*
* Registers a property named @property_name, which will be used in the D-Bus
* serialization of objects of this setting type, but which does not correspond to
* a #GObject property.
*
* When serializing a setting to D-Bus, @to_dbus_fcn will be called to synthesize
* a value for the property. (If it returns %NULL, no value will be added to the
* serialization. If @to_dbus_fcn is %NULL, the property will always be omitted
* in the serialization.)
*
* When deserializing a D-Bus representation into a setting, if @property_name
* is present, then @from_dbus_fcn will be called to set it. (If @from_dbus_fcn is %NULL
* then the property will be ignored when deserializing.)
*/
void
_properties_override_add_dbus_only (GArray *properties_override,
const char *property_name,
const GVariantType *dbus_type,
NMSettInfoPropToDBusFcn to_dbus_fcn,
NMSettInfoPropFromDBusFcn from_dbus_fcn)
{
_properties_override_add (properties_override,
.name = property_name,
.dbus_type = dbus_type,
.to_dbus_fcn = to_dbus_fcn,
.from_dbus_fcn = from_dbus_fcn);
}
/**
* _properties_override_add_override:
* @properties_override: an array collecting the overrides
* @param_spec: the name of the property to override
* @dbus_type: the type of the property (in its D-Bus representation)
* @to_dbus_fcn: (allow-none): function to call to get the value of the property
* @from_dbus_fcn: (allow-none): function to call to set the value of the property
* @missing_from_dbus_fcn: (allow-none): function to call to indicate the property was not set
*
* Overrides the D-Bus representation of the #GObject property that shares the
* same name as @param_spec.
*
* When serializing a setting to D-Bus, if @to_dbus_fcn is non-%NULL, then it will
* be called to get the property's value. If it returns a #GVariant, the
* property will be added to the hash, and if it returns %NULL, the property
* will be omitted. (If @to_dbus_fcn is %NULL, the property will be read normally
* with g_object_get_property(), and added to the hash if it is not the default
* value.)
*
* When deserializing a D-Bus representation into a setting, if a value with
* the name of @param_spec is present, then @from_dbus_fcn will be called to set it.
* (If @from_dbus_fcn is %NULL then the property will be set normally with
* g_object_set_property().)
*
* If @missing_from_dbus_fcn is non-%NULL, then it will be called when deserializing a
* representation that does NOT contain a value for the property. This can be used,
* eg, if a new property needs to be initialized from some older deprecated property
* when it is not present.
*/
void
_properties_override_add_override (GArray *properties_override,
GParamSpec *param_spec,
const GVariantType *dbus_type,
NMSettInfoPropToDBusFcn to_dbus_fcn,
NMSettInfoPropFromDBusFcn from_dbus_fcn,
NMSettInfoPropMissingFromDBusFcn missing_from_dbus_fcn)
{
nm_assert (param_spec);
_properties_override_add (properties_override,
.param_spec = param_spec,
.dbus_type = dbus_type,
.to_dbus_fcn = to_dbus_fcn,
.from_dbus_fcn = from_dbus_fcn,
.missing_from_dbus_fcn = missing_from_dbus_fcn);
}
/**
* _properties_override_add_transform:
* @properties_override: an array collecting the overrides
* @param_spec: the param spec of the property to transform.
* @dbus_type: the type of the property (in its D-Bus representation)
* @gprop_to_dbus_fcn: function to convert from object to D-Bus format
* @gprop_from_dbus_fcn: function to convert from D-Bus to object format
*
* Indicates that @property on @setting_class does not have the same format as
* its corresponding D-Bus representation, and so must be transformed when
* serializing/deserializing.
*
* The transformation will also be used by nm_setting_compare(), meaning that
* the underlying object property does not need to be of a type that
* nm_property_compare() recognizes, as long as it recognizes @dbus_type.
*/
void
_properties_override_add_transform (GArray *properties_override,
GParamSpec *param_spec,
const GVariantType *dbus_type,
NMSettInfoPropGPropToDBusFcn gprop_to_dbus_fcn,
NMSettInfoPropGPropFromDBusFcn gprop_from_dbus_fcn)
{
nm_assert (param_spec);
_properties_override_add (properties_override,
.param_spec = param_spec,
.dbus_type = dbus_type,
.gprop_to_dbus_fcn = gprop_to_dbus_fcn,
.gprop_from_dbus_fcn = gprop_from_dbus_fcn);
}
static NMSettInfoSetting _sett_info_settings[_NM_META_SETTING_TYPE_NUM];
@@ -461,6 +342,18 @@ _nm_setting_class_commit_full (NMSettingClass *setting_class,
property_specs = g_object_class_list_properties (G_OBJECT_CLASS (setting_class),
&n_property_specs);
for (i = 0; i < properties_override->len; i++) {
NMSettInfoProperty *p = &g_array_index (properties_override, NMSettInfoProperty, i);
nm_assert ((!!p->name) != (!!p->param_spec));
if (!p->name) {
nm_assert (p->param_spec);
p->name = p->param_spec->name;
} else
nm_assert (!p->param_spec);
}
#if NM_MORE_ASSERTS > 10
/* assert that properties_override is constructed consistently. */
for (i = 0; i < override_len; i++) {
@@ -502,43 +395,46 @@ _nm_setting_class_commit_full (NMSettingClass *setting_class,
NMSettInfoProperty *p = &g_array_index (properties_override, NMSettInfoProperty, i);
GType vtype;
if (p->dbus_type)
continue;
if (p->property_type)
goto has_property_type;
nm_assert (p->param_spec);
nm_assert (!p->gprop_to_dbus_fcn);
vtype = p->param_spec->value_type;
if (vtype == G_TYPE_BOOLEAN)
p->dbus_type = G_VARIANT_TYPE_BOOLEAN;
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_BOOLEAN);
else if (vtype == G_TYPE_UCHAR)
p->dbus_type = G_VARIANT_TYPE_BYTE;
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_BYTE);
else if (vtype == G_TYPE_INT)
p->dbus_type = G_VARIANT_TYPE_INT32;
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_INT32);
else if (vtype == G_TYPE_UINT)
p->dbus_type = G_VARIANT_TYPE_UINT32;
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_UINT32);
else if (vtype == G_TYPE_INT64)
p->dbus_type = G_VARIANT_TYPE_INT64;
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_INT64);
else if (vtype == G_TYPE_UINT64)
p->dbus_type = G_VARIANT_TYPE_UINT64;
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_UINT64);
else if (vtype == G_TYPE_STRING)
p->dbus_type = G_VARIANT_TYPE_STRING;
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_STRING);
else if (vtype == G_TYPE_DOUBLE)
p->dbus_type = G_VARIANT_TYPE_DOUBLE;
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_DOUBLE);
else if (vtype == G_TYPE_STRV)
p->dbus_type = G_VARIANT_TYPE_STRING_ARRAY;
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_STRING_ARRAY);
else if (vtype == G_TYPE_BYTES) {
p->dbus_type = G_VARIANT_TYPE_BYTESTRING;
p->gprop_to_dbus_fcn = _gprop_to_dbus_fcn_bytes;
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_BYTESTRING,
.gprop_to_dbus_fcn = _gprop_to_dbus_fcn_bytes);
} else if (g_type_is_a (vtype, G_TYPE_ENUM)) {
p->dbus_type = G_VARIANT_TYPE_INT32;
p->gprop_to_dbus_fcn = _gprop_to_dbus_fcn_enum;
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_INT32,
.gprop_to_dbus_fcn = _gprop_to_dbus_fcn_enum);
} else if (g_type_is_a (vtype, G_TYPE_FLAGS)) {
p->dbus_type = G_VARIANT_TYPE_UINT32;
p->gprop_to_dbus_fcn = _gprop_to_dbus_fcn_flags;
}
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_UINT32,
.gprop_to_dbus_fcn = _gprop_to_dbus_fcn_flags);
} else
nm_assert_not_reached ();
nm_assert (p->dbus_type);
has_property_type:
nm_assert (p->property_type);
nm_assert (p->property_type->dbus_type);
nm_assert (g_variant_type_string_is_valid ((const char *) p->property_type->dbus_type));
}
G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMSettInfoProperty, name) == 0);
@@ -685,10 +581,10 @@ property_to_dbus (const NMSettInfoSetting *sett_info,
const NMSettInfoProperty *property = &sett_info->property_infos[property_idx];
GVariant *variant;
nm_assert (property->dbus_type);
nm_assert (property->property_type->dbus_type);
if (!property->param_spec) {
if (!property->to_dbus_fcn)
if (!property->property_type->to_dbus_fcn)
return NULL;
} else if (!ignore_flags) {
if (!NM_FLAGS_HAS (property->param_spec->flags, G_PARAM_WRITABLE))
@@ -726,8 +622,8 @@ property_to_dbus (const NMSettInfoSetting *sett_info,
}
}
if (property->to_dbus_fcn) {
variant = property->to_dbus_fcn (sett_info, property_idx, connection, setting, flags, options);
if (property->property_type->to_dbus_fcn) {
variant = property->property_type->to_dbus_fcn (sett_info, property_idx, connection, setting, flags, options);
nm_g_variant_take_ref (variant);
} else {
nm_auto_unset_gvalue GValue prop_value = { 0, };
@@ -742,15 +638,15 @@ property_to_dbus (const NMSettInfoSetting *sett_info,
&& g_param_value_defaults (property->param_spec, &prop_value))
return NULL;
if (property->gprop_to_dbus_fcn) {
variant = property->gprop_to_dbus_fcn (&prop_value);
if (property->property_type->gprop_to_dbus_fcn) {
variant = property->property_type->gprop_to_dbus_fcn (&prop_value);
nm_g_variant_take_ref (variant);
} else
variant = g_dbus_gvalue_to_gvariant (&prop_value, property->dbus_type);
variant = g_dbus_gvalue_to_gvariant (&prop_value, property->property_type->dbus_type);
}
nm_assert (!variant || !g_variant_is_floating (variant));
nm_assert (!variant || g_variant_is_of_type (variant, property->dbus_type));
nm_assert (!variant || g_variant_is_of_type (variant, property->property_type->dbus_type));
return variant;
}
@@ -761,12 +657,12 @@ set_property_from_dbus (const NMSettInfoProperty *property,
GValue *dst_value)
{
nm_assert (property->param_spec);
nm_assert (property->dbus_type);
nm_assert (property->property_type->dbus_type);
if (property->gprop_from_dbus_fcn) {
if (!g_variant_type_equal (g_variant_get_type (src_value), property->dbus_type))
if (property->property_type->gprop_from_dbus_fcn) {
if (!g_variant_type_equal (g_variant_get_type (src_value), property->property_type->dbus_type))
return FALSE;
property->gprop_from_dbus_fcn (src_value, dst_value);
property->property_type->gprop_from_dbus_fcn (src_value, dst_value);
} else if (dst_value->g_type == G_TYPE_BYTES) {
if (!g_variant_is_of_type (src_value, G_VARIANT_TYPE_BYTESTRING))
return FALSE;
@@ -1002,16 +898,16 @@ init_from_dbus (NMSetting *setting,
g_hash_table_remove (keys, property_info->name);
if ( value
&& property_info->from_dbus_fcn) {
&& property_info->property_type->from_dbus_fcn) {
if (!g_variant_type_equal (g_variant_get_type (value), property_info->dbus_type)) {
if (!g_variant_type_equal (g_variant_get_type (value), property_info->property_type->dbus_type)) {
/* for backward behavior, fail unless best-effort is chosen. */
if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT))
continue;
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("can't set property of type '%s' from value of type '%s'"),
property_info->dbus_type ?
g_variant_type_peek_string (property_info->dbus_type) :
property_info->property_type->dbus_type ?
g_variant_type_peek_string (property_info->property_type->dbus_type) :
property_info->param_spec ?
g_type_name (property_info->param_spec->value_type) : "(unknown)",
g_variant_get_type_string (value));
@@ -1019,7 +915,7 @@ init_from_dbus (NMSetting *setting,
return FALSE;
}
if (!property_info->from_dbus_fcn (setting,
if (!property_info->property_type->from_dbus_fcn (setting,
connection_dict,
property_info->name,
value,
@@ -1034,8 +930,8 @@ init_from_dbus (NMSetting *setting,
return FALSE;
}
} else if ( !value
&& property_info->missing_from_dbus_fcn) {
if (!property_info->missing_from_dbus_fcn (setting,
&& property_info->property_type->missing_from_dbus_fcn) {
if (!property_info->property_type->missing_from_dbus_fcn (setting,
connection_dict,
property_info->name,
parse_flags,
@@ -1059,8 +955,8 @@ init_from_dbus (NMSetting *setting,
continue;
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("can't set property of type '%s' from value of type '%s'"),
property_info->dbus_type
? g_variant_type_peek_string (property_info->dbus_type)
property_info->property_type->dbus_type
? g_variant_type_peek_string (property_info->property_type->dbus_type)
: ( property_info->param_spec
? g_type_name (property_info->param_spec->value_type)
: "(unknown)"),
@@ -1107,9 +1003,10 @@ nm_setting_get_dbus_property_type (NMSetting *setting,
g_return_val_if_fail (property != NULL, NULL);
nm_assert (property->dbus_type);
nm_assert (property->property_type);
nm_assert (g_variant_type_string_is_valid ((const char *) property->property_type->dbus_type));
return property->dbus_type;
return property->property_type->dbus_type;
}
gboolean

View File

@@ -3387,8 +3387,12 @@ test_setting_metadata (void)
if (prop_idx > 0)
g_assert_cmpint (strcmp (sis->property_infos[prop_idx - 1].name, sip->name), <, 0);
g_assert (sip->dbus_type);
g_assert (g_variant_type_string_is_valid ((const char *) sip->dbus_type));
g_assert (sip->property_type);
g_assert (sip->property_type->dbus_type);
g_assert (g_variant_type_string_is_valid ((const char *) sip->property_type->dbus_type));
g_assert (!sip->property_type->to_dbus_fcn || !sip->property_type->gprop_to_dbus_fcn);
g_assert (!sip->property_type->from_dbus_fcn || !sip->property_type->gprop_from_dbus_fcn);
if (!g_hash_table_insert (h_properties, (char *) sip->name, sip->param_spec))
g_assert_not_reached ();