sculpt_manager: use update_list_model_from_xml

This patch replaces the use of 'List_model::Update_policy' types by
simpler 'update_list_model_from_xml' function calls.

Issue #4317
This commit is contained in:
Norman Feske 2023-01-10 16:52:31 +01:00 committed by Christian Helmuth
parent 39ca06114b
commit bf231f7fca
13 changed files with 287 additions and 343 deletions

View File

@ -43,40 +43,15 @@ struct Sculpt::Access_point : List_model<Access_point>::Element
bool unprotected() const { return protection == UNPROTECTED; }
bool wpa_protected() const { return protection == WPA_PSK; }
};
/**
* Policy for transforming a 'accesspoints' report into a list model
*/
struct Sculpt::Access_point_update_policy : List_model<Access_point>::Update_policy
{
Allocator &_alloc;
Access_point_update_policy(Allocator &alloc) : _alloc(alloc) { }
void destroy_element(Access_point &elem) { destroy(_alloc, &elem); }
Access_point &create_element(Xml_node node)
bool matches(Xml_node const &node) const
{
auto const protection = node.attribute_value("protection", String<16>());
bool const use_protection = protection == "WPA" || protection == "WPA2";
return *new (_alloc)
Access_point(node.attribute_value("bssid", Access_point::Bssid()),
node.attribute_value("ssid", Access_point::Ssid()),
use_protection ? Access_point::Protection::WPA_PSK
: Access_point::Protection::UNPROTECTED);
return node.attribute_value("ssid", Access_point::Ssid()) == ssid;
}
void update_element(Access_point &ap, Xml_node node)
static bool type_matches(Xml_node const &node)
{
ap.quality = node.attribute_value("quality", 0U);
}
static bool element_matches_xml_node(Access_point const &elem, Xml_node node)
{
return node.attribute_value("ssid", Access_point::Ssid()) == elem.ssid;
return node.has_type("accesspoint");
}
};

View File

@ -37,37 +37,13 @@ struct Sculpt::Block_device : List_model<Block_device>::Element,
:
Storage_device(env, alloc, label, capacity, sigh), model(model)
{ }
};
struct Sculpt::Block_device_update_policy : List_model<Block_device>::Update_policy
{
Env &_env;
Allocator &_alloc;
Signal_context_capability _sigh;
Block_device_update_policy(Env &env, Allocator &alloc, Signal_context_capability sigh)
: _env(env), _alloc(alloc), _sigh(sigh) { }
void destroy_element(Block_device &elem) { destroy(_alloc, &elem); }
Block_device &create_element(Xml_node node)
bool matches(Xml_node const &node) const
{
return *new (_alloc)
Block_device(_env, _alloc, _sigh,
node.attribute_value("label", Block_device::Label()),
node.attribute_value("model", Block_device::Model()),
Capacity { node.attribute_value("block_size", 0ULL)
* node.attribute_value("block_count", 0ULL) });
return node.attribute_value("label", Block_device::Label()) == label;
}
void update_element(Block_device &, Xml_node) { }
static bool element_matches_xml_node(Block_device const &elem, Xml_node node)
{
return node.attribute_value("label", Block_device::Label()) == elem.label;
}
static bool type_matches(Xml_node const &) { return true; }
};
#endif /* _MODEL__BLOCK_DEVICE_H_ */

View File

@ -23,13 +23,13 @@ namespace Sculpt { struct Component; }
struct Sculpt::Component : Noncopyable
{
Route::Update_policy _route_update_policy;
typedef Depot::Archive::Path Path;
typedef Depot::Archive::Name Name;
typedef String<100> Info;
typedef Start_name Service;
Allocator &_alloc;
/* defined at construction time */
Path const path;
Info const info;
@ -49,15 +49,31 @@ struct Sculpt::Component : Noncopyable
List_model<Route> routes { };
Route pd_route { "<pd/>" };
void _update_routes_from_xml(Xml_node const &node)
{
update_list_model_from_xml(routes, node,
/* create */
[&] (Xml_node const &route) -> Route & {
return *new (_alloc) Route(route); },
/* destroy */
[&] (Route &e) { destroy(_alloc, &e); },
/* update */
[&] (Route &, Xml_node) { }
);
}
Component(Allocator &alloc, Path const &path, Info const &info,
Affinity::Space const space)
:
_route_update_policy(alloc), path(path), info(info), affinity_space(space)
_alloc(alloc), path(path), info(info), affinity_space(space)
{ }
~Component()
{
routes.update_from_xml(_route_update_policy, Xml_node("<empty/>"));
_update_routes_from_xml(Xml_node("<empty/>"));
}
void try_apply_blueprint(Xml_node blueprint)
@ -73,7 +89,7 @@ struct Sculpt::Component : Noncopyable
caps = runtime.attribute_value("caps", 0UL);
runtime.with_optional_sub_node("requires", [&] (Xml_node requires) {
routes.update_from_xml(_route_update_policy, requires); });
_update_routes_from_xml(requires); });
});
blueprint_known = true;

View File

@ -45,6 +45,16 @@ class Sculpt::Launchers : public Noncopyable
struct Launcher : Dict::Element, List_model<Launcher>::Element
{
bool matches(Xml_node const &node) const
{
return node.attribute_value("name", Path()) == name;
}
static bool type_matches(Xml_node const &node)
{
return node.has_type("file");
}
Launcher(Dict &dict, Path const &path) : Dict::Element(dict, path) { }
};
@ -52,46 +62,32 @@ class Sculpt::Launchers : public Noncopyable
List_model<Launcher> _launchers { };
struct Update_policy : List_model<Launcher>::Update_policy
{
Allocator &_alloc;
Dict &_sorted;
Update_policy(Allocator &alloc, Dict &sorted)
: _alloc(alloc), _sorted(sorted) { }
void destroy_element(Launcher &elem) { destroy(_alloc, &elem); }
Launcher &create_element(Xml_node node)
{
return *new (_alloc)
Launcher(_sorted, node.attribute_value("name", Path()));
}
void update_element(Launcher &, Xml_node) { }
static bool element_matches_xml_node(Launcher const &elem, Xml_node node)
{
return node.attribute_value("name", Path()) == elem.name;
}
};
public:
Launchers(Allocator &alloc) : _alloc(alloc) { }
void update_from_xml(Xml_node const &node)
void update_from_xml(Xml_node const &launchers)
{
Update_policy policy(_alloc, _sorted);
_launchers.update_from_xml(policy, node);
update_list_model_from_xml(_launchers, launchers,
/* create */
[&] (Xml_node const &node) -> Launcher & {
return *new (_alloc)
Launcher(_sorted,
node.attribute_value("name", Path())); },
/* destroy */
[&] (Launcher &e) { destroy(_alloc, &e); },
/* update */
[&] (Launcher &, Xml_node) { }
);
}
template <typename FN>
void for_each(FN const &fn) const
{
_sorted.for_each([&] (Dict::Element const &e) {
fn(Info(e.name)); });
_sorted.for_each([&] (Dict::Element const &e) { fn(Info(e.name)); });
}
};

View File

@ -133,28 +133,8 @@ struct Sculpt::Partition : List_model<Partition>::Element
{ }
bool whole_device() const { return !number.valid(); }
};
/**
* Policy for transforming a part_block report into a list of partitions
*/
struct Sculpt::Partition_update_policy : List_model<Partition>::Update_policy
{
Allocator &_alloc;
Partition_update_policy(Allocator &alloc) : _alloc(alloc) { }
void destroy_element(Partition &elem) { destroy(_alloc, &elem); }
Partition &create_element(Xml_node node)
{
return *new (_alloc) Partition(Partition::Args::from_xml(node));
}
void update_element(Partition &, Xml_node) { }
static bool node_is_element(Xml_node node)
static bool type_matches(Xml_node node)
{
/*
* Partition "0" is a pseudo partition that refers to the whole device
@ -163,9 +143,9 @@ struct Sculpt::Partition_update_policy : List_model<Partition>::Update_policy
return (node.attribute_value("number", Partition::Number()) != "0");
}
static bool element_matches_xml_node(Partition const &elem, Xml_node node)
bool matches(Xml_node node) const
{
return node.attribute_value("number", Partition::Number()) == elem.number;
return node.attribute_value("number", Partition::Number()) == number;
}
};

View File

@ -148,34 +148,16 @@ struct Sculpt::Route : List_model<Route>::Element
});
}
struct Update_policy
bool matches(Xml_node node) const
{
typedef Route Element;
return required == _required(node)
&& required_label == node.attribute_value("label", Label());
}
Allocator &_alloc;
Update_policy(Allocator &alloc) : _alloc(alloc) { }
void destroy_element(Route &elem) { destroy(_alloc, &elem); }
Route &create_element(Xml_node node)
{
return *new (_alloc) Route(node);
}
void update_element(Route &, Xml_node) { }
static bool element_matches_xml_node(Route const &elem, Xml_node node)
{
return elem.required == _required(node)
&& elem.required_label == node.attribute_value("label", Label());
}
static bool node_is_element(Xml_node node)
{
return _required(node) != Service::Type::UNDEFINED;
}
};
static bool type_matches(Xml_node node)
{
return _required(node) != Service::Type::UNDEFINED;
}
};
#endif /* _MODEL__ROUTE_H_ */

View File

@ -167,35 +167,15 @@ class Sculpt::Runtime_config
Child_service(Start_name server, Xml_node provides)
: Service(server, type_from_xml(provides), Label()) { }
struct Update_policy
static bool type_matches(Xml_node const &node)
{
typedef Child_service Element;
return type_from_xml(node) != Service::Type::UNDEFINED;
}
Start_name _server;
Allocator &_alloc;
Update_policy(Start_name const &server, Allocator &alloc)
: _server(server), _alloc(alloc) { }
void destroy_element(Element &elem) { destroy(_alloc, &elem); }
Element &create_element(Xml_node node)
{
return *new (_alloc) Child_service(_server, node);
}
void update_element(Element &, Xml_node) { }
static bool element_matches_xml_node(Element const &elem, Xml_node node)
{
return type_from_xml(node) == elem.type;
}
static bool node_is_element(Xml_node node)
{
return type_from_xml(node) != Service::Type::UNDEFINED;
}
};
bool matches(Xml_node const &node) const
{
return type_from_xml(node) == type;
}
};
public:
@ -212,33 +192,15 @@ class Sculpt::Runtime_config
Dep(Start_name to_name) : to_name(to_name) { }
struct Update_policy
bool matches(Xml_node const &node) const
{
typedef Dep Element;
return _to_name(node) == to_name;
}
Allocator &_alloc;
Update_policy(Allocator &alloc) : _alloc(alloc) { }
void destroy_element(Dep &elem) { destroy(_alloc, &elem); }
Dep &create_element(Xml_node node)
{
return *new (_alloc) Dep(_to_name(node));
}
void update_element(Dep &, Xml_node) { }
static bool element_matches_xml_node(Dep const &elem, Xml_node node)
{
return _to_name(node) == elem.to_name;
}
static bool node_is_element(Xml_node node)
{
return _to_name(node).valid();
}
};
static bool type_matches(Xml_node const &node)
{
return _to_name(node).valid();
}
};
/* dependencies on other child components */
@ -262,55 +224,53 @@ class Sculpt::Runtime_config
_child_services.for_each(fn);
}
struct Update_policy
void update_from_xml(Allocator &alloc, Xml_node const &node)
{
typedef Component Element;
primary_dependency = _primary_dependency(node);
Allocator &_alloc;
node.with_optional_sub_node("route", [&] (Xml_node route) {
Update_policy(Allocator &alloc) : _alloc(alloc) { }
update_list_model_from_xml(deps, route,
void destroy_element(Component &elem)
{
/* flush list models */
update_element(elem, Xml_node("<start> <route/> <provides/> </start>"));
/* create */
[&] (Xml_node const &node) -> Dep & {
return *new (alloc) Dep(_to_name(node)); },
destroy(_alloc, &elem);
}
/* destroy */
[&] (Dep &e) { destroy(alloc, &e); },
Component &create_element(Xml_node node)
{
return *new (_alloc)
Component(node.attribute_value("name", Start_name()));
}
/* update */
[&] (Dep &, Xml_node) { }
);
});
void update_element(Component &elem, Xml_node node)
{
elem.primary_dependency = _primary_dependency(node);
node.with_optional_sub_node("provides", [&] (Xml_node provides) {
{
Dep::Update_policy policy { _alloc };
update_list_model_from_xml(_child_services, provides,
node.with_optional_sub_node("route", [&] (Xml_node route) {
elem.deps.update_from_xml(policy, route); });
}
/* create */
[&] (Xml_node const &node) -> Child_service & {
return *new (alloc)
Child_service(name, node); },
{
Child_service::Update_policy policy { elem.name, _alloc };
/* destroy */
[&] (Child_service &e) { destroy(alloc, &e); },
node.with_optional_sub_node("provides", [&] (Xml_node provides) {
elem._child_services.update_from_xml(policy,
provides); });
}
}
/* update */
[&] (Child_service &, Xml_node) { }
);
});
}
static bool element_matches_xml_node(Component const &elem, Xml_node node)
{
return node.attribute_value("name", Start_name()) == elem.name;
}
bool matches(Xml_node const &node) const
{
return node.attribute_value("name", Start_name()) == name;
}
static bool node_is_element(Xml_node node) { return node.has_type("start"); }
};
static bool type_matches(Xml_node const &node)
{
return node.has_type("start");
}
};
private:
@ -377,8 +337,26 @@ class Sculpt::Runtime_config
void update_from_xml(Xml_node config)
{
Component::Update_policy policy(_alloc);
_components.update_from_xml(policy, config);
update_list_model_from_xml(_components, config,
/* create */
[&] (Xml_node const &node) -> Component & {
return *new (_alloc)
Component(node.attribute_value("name", Start_name())); },
/* destroy */
[&] (Component &e) {
/* flush list models */
e.update_from_xml(_alloc, Xml_node("<start> <route/> <provides/> </start>"));
destroy(_alloc, &e);
},
/* update */
[&] (Component &e, Xml_node const &node) {
e.update_from_xml(_alloc, node); }
);
}
template <typename FN>

View File

@ -73,6 +73,33 @@ class Sculpt::Runtime_state : public Runtime_info
bool abandoned_by_user = false;
Child(Start_name const &name) : name(name) { }
bool matches(Xml_node const &node) const
{
return node.attribute_value("name", Start_name()) == name;
}
static bool type_matches(Xml_node const &node)
{
return node.has_type("child");
}
void update_from_xml(Xml_node const &node)
{
node.with_optional_sub_node("ram", [&] (Xml_node const &ram) {
info.assigned_ram = max(ram.attribute_value("assigned", Number_of_bytes()),
ram.attribute_value("quota", Number_of_bytes()));
info.avail_ram = ram.attribute_value("avail", Number_of_bytes());
});
node.with_optional_sub_node("caps", [&] (Xml_node const &caps) {
info.assigned_caps = max(caps.attribute_value("assigned", 0UL),
caps.attribute_value("quota", 0UL));
info.avail_caps = caps.attribute_value("avail", 0UL);
});
info.version.value = node.attribute_value("version", 0U);
}
};
List_model<Child> _children { };
@ -183,50 +210,6 @@ class Sculpt::Runtime_state : public Runtime_info
&& _currently_constructed->construction.constructed();
}
struct Update_policy : List_model<Child>::Update_policy
{
Allocator &_alloc;
Update_policy(Allocator &alloc) : _alloc(alloc) { }
void destroy_element(Child &elem)
{
destroy(_alloc, &elem);
}
Child &create_element(Xml_node node)
{
return *new (_alloc)
Child(node.attribute_value("name", Start_name()));
}
void update_element(Child &child, Xml_node node)
{
if (node.has_sub_node("ram")) {
Xml_node const ram = node.sub_node("ram");
child.info.assigned_ram = max(ram.attribute_value("assigned", Number_of_bytes()),
ram.attribute_value("quota", Number_of_bytes()));
child.info.avail_ram = ram.attribute_value("avail", Number_of_bytes());
}
if (node.has_sub_node("caps")) {
Xml_node const caps = node.sub_node("caps");
child.info.assigned_caps = max(caps.attribute_value("assigned", 0UL),
caps.attribute_value("quota", 0UL));
child.info.avail_caps = caps.attribute_value("avail", 0UL);
}
child.info.version.value = node.attribute_value("version", 0U);
}
static bool element_matches_xml_node(Child const &elem, Xml_node node)
{
return node.attribute_value("name", Start_name()) == elem.name;
}
static bool node_is_element(Xml_node node) { return node.has_type("child"); }
};
/*
* Noncopyable
*/
@ -242,8 +225,20 @@ class Sculpt::Runtime_state : public Runtime_info
void update_from_state_report(Xml_node state)
{
Update_policy policy(_alloc);
_children.update_from_xml(policy, state);
update_list_model_from_xml(_children, state,
/* create */
[&] (Xml_node const &node) -> Child & {
return *new (_alloc)
Child(node.attribute_value("name", Start_name())); },
/* destroy */
[&] (Child &child) { destroy(_alloc, &child); },
/* update */
[&] (Child &child, Xml_node const &node) {
child.update_from_xml(node); }
);
}
/**

View File

@ -52,6 +52,22 @@ struct Sculpt::Storage_device
unsigned _part_block_version = 0;
void _update_partitions_from_xml(Xml_node const &node)
{
update_list_model_from_xml(partitions, node,
/* create */
[&] (Xml_node const &node) -> Partition & {
return *new (_alloc) Partition(Partition::Args::from_xml(node)); },
/* destroy */
[&] (Partition &p) { destroy(_alloc, &p); },
/* update */
[&] (Partition &, Xml_node) { }
);
}
/**
* Trigger the rediscovery of the device, e.g., after partitioning of after
* formatting the whole device.
@ -61,8 +77,7 @@ struct Sculpt::Storage_device
state = UNKNOWN;
_part_block_version++;
Partition_update_policy policy(_alloc);
partitions.update_from_xml(policy, Xml_node("<partitions/>"));
_update_partitions_from_xml(Xml_node("<partitions/>"));
}
void process_part_block_report()
@ -75,8 +90,7 @@ struct Sculpt::Storage_device
whole_device = (report.attribute_value("type", String<16>()) == "disk");
Partition_update_policy policy(_alloc);
partitions.update_from_xml(policy, report);
_update_partitions_from_xml(report);
/*
* Import whole-device partition information.

View File

@ -34,10 +34,27 @@ struct Sculpt::Storage_devices
/**
* Update 'block_devices' from 'block_devices' report
*/
template <typename POLICY>
void update_block_devices_from_xml(POLICY &policy, Xml_node node)
void update_block_devices_from_xml(Env &env, Allocator &alloc, Xml_node node,
Signal_context_capability sigh)
{
block_devices.update_from_xml(policy, node);
update_list_model_from_xml(block_devices, node,
/* create */
[&] (Xml_node const &node) -> Block_device & {
return *new (alloc)
Block_device(env, alloc, sigh,
node.attribute_value("label", Block_device::Label()),
node.attribute_value("model", Block_device::Model()),
Capacity { node.attribute_value("block_size", 0ULL)
* node.attribute_value("block_count", 0ULL) });
},
/* destroy */
[&] (Block_device &b) { destroy(alloc, &b); },
/* update */
[&] (Block_device &, Xml_node const &) { }
);
if (node.has_type("block_devices"))
_block_devices_report_valid = true;
@ -45,17 +62,46 @@ struct Sculpt::Storage_devices
/**
* Update 'usb_storage_devices' from 'usb_active_config' report
*
* \return true if USB storage device was added or vanished
*/
template <typename POLICY>
void update_usb_storage_devices_from_xml(POLICY &policy, Xml_node node)
bool update_usb_storage_devices_from_xml(Env &env, Allocator &alloc, Xml_node node,
Signal_context_capability sigh)
{
usb_storage_devices.update_from_xml(policy, node);
using Label = Usb_storage_device::Label;
bool device_added_or_vanished = false;
update_list_model_from_xml(usb_storage_devices, node,
/* create */
[&] (Xml_node const &node) -> Usb_storage_device &
{
device_added_or_vanished = true;
return *new (alloc)
Usb_storage_device(env, alloc, sigh,
node.attribute_value("label_suffix", Label()));
},
/* destroy */
[&] (Usb_storage_device &elem)
{
device_added_or_vanished = true;
destroy(alloc, &elem);
},
/* update */
[&] (Usb_storage_device &, Xml_node const &) { }
);
_usb_active_config_valid = true;
usb_present = false;
usb_storage_devices.for_each([&] (Storage_device const &) {
usb_present = true; });
return device_added_or_vanished;
}
/**

View File

@ -116,6 +116,16 @@ struct Sculpt::Usb_storage_device : List_model<Usb_storage_device>::Element,
}
inline void gen_usb_block_drv_start_content(Xml_generator &xml) const;
static bool type_matches(Xml_node node)
{
return node.attribute_value("class", String<32>()) == "storage";
}
bool matches(Xml_node node) const
{
return node.attribute_value("label_suffix", Label()) == label;
}
};
@ -151,53 +161,4 @@ void Sculpt::Usb_storage_device::gen_usb_block_drv_start_content(Xml_generator &
});
}
struct Sculpt::Usb_storage_device_update_policy
:
List_model<Usb_storage_device>::Update_policy
{
Env &_env;
Allocator &_alloc;
bool device_added_or_vanished = false;
Signal_context_capability _sigh;
Usb_storage_device_update_policy(Env &env, Allocator &alloc,
Signal_context_capability sigh)
:
_env(env), _alloc(alloc), _sigh(sigh)
{ }
typedef Usb_storage_device::Label Label;
void destroy_element(Usb_storage_device &elem)
{
device_added_or_vanished = true;
destroy(_alloc, &elem);
}
Usb_storage_device &create_element(Xml_node node)
{
device_added_or_vanished = true;
return *new (_alloc)
Usb_storage_device(_env, _alloc, _sigh,
node.attribute_value("label_suffix", Label()));
}
void update_element(Usb_storage_device &, Xml_node) { }
static bool node_is_element(Xml_node node)
{
return node.attribute_value("class", String<32>()) == "storage";
};
static bool element_matches_xml_node(Usb_storage_device const &elem, Xml_node node)
{
return node.attribute_value("label_suffix", Label()) == elem.label;
}
};
#endif /* _MODEL__BLOCK_DEVICE_H_ */

View File

@ -125,8 +125,31 @@ void Sculpt::Network::_handle_wlan_accesspoints()
if (!initial_scan && dialog.ap_list_hovered())
return;
Access_point_update_policy policy(_alloc);
_access_points.update_from_xml(policy, _wlan_accesspoints_rom.xml());
update_list_model_from_xml(_access_points, _wlan_accesspoints_rom.xml(),
/* create */
[&] (Xml_node const &node) -> Access_point &
{
auto const protection = node.attribute_value("protection", String<16>());
bool const use_protection = protection == "WPA" || protection == "WPA2";
return *new (_alloc)
Access_point(node.attribute_value("bssid", Access_point::Bssid()),
node.attribute_value("ssid", Access_point::Ssid()),
use_protection ? Access_point::Protection::WPA_PSK
: Access_point::Protection::UNPROTECTED);
},
/* destroy */
[&] (Access_point &ap) { destroy(_alloc, &ap); },
/* update */
[&] (Access_point &ap, Xml_node const &node)
{
ap.quality = node.attribute_value("quality", 0U);
}
);
_action.update_network_dialog();
}

View File

@ -32,8 +32,9 @@ void Sculpt::Storage::handle_storage_devices_update()
{
_block_devices_rom.update();
Block_device_update_policy policy(_env, _alloc, _storage_device_update_handler);
_storage_devices.update_block_devices_from_xml(policy, _block_devices_rom.xml());
_storage_devices.update_block_devices_from_xml(_env, _alloc, _block_devices_rom.xml(),
_storage_device_update_handler);
_storage_devices.block_devices.for_each([&] (Block_device &dev) {
process_part_block_report(dev); });
@ -41,12 +42,13 @@ void Sculpt::Storage::handle_storage_devices_update()
{
_usb_active_config_rom.update();
Usb_storage_device_update_policy policy(_env, _alloc, _storage_device_update_handler);
Xml_node const config = _usb_active_config_rom.xml();
_storage_devices.update_usb_storage_devices_from_xml(policy, config);
bool const usb_storage_added_or_vanished =
_storage_devices.update_usb_storage_devices_from_xml(_env, _alloc,
_usb_active_config_rom.xml(),
_storage_device_update_handler);
if (policy.device_added_or_vanished)
if (usb_storage_added_or_vanished)
reconfigure_runtime = true;
_storage_devices.usb_storage_devices.for_each([&] (Usb_storage_device &dev) {