diff options
Diffstat (limited to 'kernel/kapi')
| -rw-r--r-- | kernel/kapi/boot_modules/device.cpp | 6 | ||||
| -rw-r--r-- | kernel/kapi/devices.cpp | 4 | ||||
| -rw-r--r-- | kernel/kapi/devices/bus.cpp | 11 | ||||
| -rw-r--r-- | kernel/kapi/devices/device.cpp | 14 | ||||
| -rw-r--r-- | kernel/kapi/devices/driver.cpp | 2 | ||||
| -rw-r--r-- | kernel/kapi/devices/driver.tests.cpp | 78 | ||||
| -rw-r--r-- | kernel/kapi/devices/driver_registry.cpp | 2 | ||||
| -rw-r--r-- | kernel/kapi/devices/driver_registry.tests.cpp | 21 | ||||
| -rw-r--r-- | kernel/kapi/devices/facet_registry.cpp | 216 | ||||
| -rw-r--r-- | kernel/kapi/devices/facet_registry.tests.cpp (renamed from kernel/kapi/devices/interface_registry.tests.cpp) | 112 | ||||
| -rw-r--r-- | kernel/kapi/devices/interface_registry.cpp | 218 |
11 files changed, 351 insertions, 333 deletions
diff --git a/kernel/kapi/boot_modules/device.cpp b/kernel/kapi/boot_modules/device.cpp index 84a43c1c..b9262abf 100644 --- a/kernel/kapi/boot_modules/device.cpp +++ b/kernel/kapi/boot_modules/device.cpp @@ -26,14 +26,14 @@ namespace kapi::boot_modules return m_module; } - auto device::query_interface(kapi::devices::interface_id interface) -> void * + auto device::query_facet(kapi::capabilities::facet_id facet) -> void * { - if (interface == boot_module_signature::id) + if (facet == boot_module_signature::id) { return static_cast<boot_module_signature *>(this); } - return kapi::devices::device::query_interface(interface); + return kapi::devices::device::query_facet(facet); } } // namespace kapi::boot_modules
\ No newline at end of file diff --git a/kernel/kapi/devices.cpp b/kernel/kapi/devices.cpp index c3c9e595..2505779a 100644 --- a/kernel/kapi/devices.cpp +++ b/kernel/kapi/devices.cpp @@ -27,7 +27,7 @@ namespace kapi::devices } device_registry::init(); - interface_registry::init(); + facet_registry::init(); root_bus = kstd::make_shared<kernel::bus::root>(); device_registry::get().add(root_bus); @@ -49,7 +49,7 @@ namespace kapi::test_support::devices auto deinit() -> void { deinit_driver_registry(); - deinit_interface_registry(); + deinit_facet_registry(); deinit_device_registry(); kapi::devices::root_bus.reset(); diff --git a/kernel/kapi/devices/bus.cpp b/kernel/kapi/devices/bus.cpp index a9bba4fb..9eecced0 100644 --- a/kernel/kapi/devices/bus.cpp +++ b/kernel/kapi/devices/bus.cpp @@ -37,19 +37,14 @@ namespace kapi::devices return {m_devices.data(), m_devices.size()}; } - auto bus::protocol() -> struct bus_protocol * + auto bus::query_facet(kapi::capabilities::facet_id facet) -> void * { - return nullptr; - } - - auto bus::query_interface(interface_id interface) -> void * - { - if (interface == bus::id) + if (facet == bus::id) { return this; } - return device::query_interface(interface); + return device::query_facet(facet); } } // namespace kapi::devices
\ No newline at end of file diff --git a/kernel/kapi/devices/device.cpp b/kernel/kapi/devices/device.cpp index 01096165..2628e4f4 100644 --- a/kernel/kapi/devices/device.cpp +++ b/kernel/kapi/devices/device.cpp @@ -12,19 +12,19 @@ namespace kapi::devices : m_name(name) {} - auto device::as(interface_id interface) noexcept -> void * + auto device::facet(kapi::capabilities::facet_id facet) noexcept -> void * { - return query_interface(interface); + return query_facet(facet); } - auto device::as(interface_id interface) const noexcept -> void const * + auto device::facet(kapi::capabilities::facet_id facet) const noexcept -> void const * { - return const_cast<device *>(this)->query_interface(interface); + return const_cast<device *>(this)->query_facet(facet); } - auto device::is_a(interface_id interface) const noexcept -> bool + auto device::has_facet(kapi::capabilities::facet_id facet) const noexcept -> bool { - return const_cast<device *>(this)->query_interface(interface) != nullptr; + return const_cast<device *>(this)->query_facet(facet) != nullptr; } auto device::name() const -> kstd::string const & @@ -67,7 +67,7 @@ namespace kapi::devices m_driver_data = data; } - auto device::query_interface(interface_id) -> void * + auto device::query_facet(kapi::capabilities::facet_id) -> void * { return nullptr; } diff --git a/kernel/kapi/devices/driver.cpp b/kernel/kapi/devices/driver.cpp index be2866f0..55b7507b 100644 --- a/kernel/kapi/devices/driver.cpp +++ b/kernel/kapi/devices/driver.cpp @@ -11,7 +11,7 @@ namespace kapi::devices return std::nullopt; } - auto driver::query_interface(interface_id) -> void * + auto driver::query_facet(kapi::capabilities::facet_id) -> void * { return nullptr; } diff --git a/kernel/kapi/devices/driver.tests.cpp b/kernel/kapi/devices/driver.tests.cpp index e65e48e0..560cc1bc 100644 --- a/kernel/kapi/devices/driver.tests.cpp +++ b/kernel/kapi/devices/driver.tests.cpp @@ -16,39 +16,49 @@ namespace { struct controller_identification { - constexpr auto static id = kapi::devices::interface_id{"stacking_test_controller_identification"}; + constexpr auto static id = kapi::capabilities::facet_id{"stacking_test_controller_identification"}; virtual ~controller_identification() = default; [[nodiscard]] virtual auto controller_name() const -> std::string_view = 0; }; struct controller_driver_identification { - constexpr auto static id = kapi::devices::interface_id{"stacking_test_controller_driver_identification"}; + constexpr auto static id = kapi::capabilities::facet_id{"stacking_test_controller_driver_identification"}; virtual ~controller_driver_identification() = default; [[nodiscard]] virtual auto supported_names() const -> std::span<std::string_view const> = 0; }; - struct controller_bus final : kapi::devices::bus, kapi::devices::bus_protocol + struct controller_protocol : kapi::devices::bus_protocol { - using kapi::devices::bus::bus; + constexpr auto static id = kapi::capabilities::facet_id{"stacking_test_controller_protocol"}; auto enumerate(kapi::devices::bus &) -> void override {} [[nodiscard]] auto match(kapi::devices::device const & dev, kapi::devices::driver const & drv) const -> kstd::result<std::uint32_t> override { - auto const * ident = dev.as<controller_identification>(); - auto const * claims = drv.as<controller_driver_identification>(); + auto const * ident = dev.facet<controller_identification>(); + auto const * claims = drv.facet<controller_driver_identification>(); if (!ident || !claims || !std::ranges::contains(claims->supported_names(), ident->controller_name())) { return kstd::failure(kapi::devices::driver_match_errc::no_match); } return 0u; } + } constinit controller_protocol_instance{}; + + struct controller_bus final : kapi::devices::bus + { + using kapi::devices::bus::bus; - [[nodiscard]] auto protocol() -> kapi::devices::bus_protocol * override + [[nodiscard]] auto query_facet(kapi::capabilities::facet_id id) -> void * override { - return this; + if (id == controller_protocol::id || id == kapi::devices::bus_protocol::id) + { + return &controller_protocol_instance; + } + + return kapi::devices::bus::query_facet(id); } }; @@ -64,26 +74,26 @@ namespace } protected: - auto query_interface(kapi::devices::interface_id interface) -> void * override + auto query_facet(kapi::capabilities::facet_id facet) -> void * override { - if (interface == controller_identification::id) + if (facet == controller_identification::id) { return static_cast<controller_identification *>(this); } - return kapi::devices::bus::query_interface(interface); + return kapi::devices::bus::query_facet(facet); } }; struct leaf_identification { - constexpr auto static id = kapi::devices::interface_id{"stacking_test_leaf_identification"}; + constexpr auto static id = kapi::capabilities::facet_id{"stacking_test_leaf_identification"}; virtual ~leaf_identification() = default; [[nodiscard]] virtual auto leaf_name() const -> std::string_view = 0; }; struct leaf_driver_identification { - constexpr auto static id = kapi::devices::interface_id{"stacking_test_leaf_driver_identification"}; + constexpr auto static id = kapi::capabilities::facet_id{"stacking_test_leaf_driver_identification"}; virtual ~leaf_driver_identification() = default; [[nodiscard]] virtual auto supported_names() const -> std::span<std::string_view const> = 0; }; @@ -100,19 +110,19 @@ namespace } protected: - auto query_interface(kapi::devices::interface_id interface) -> void * override + auto query_facet(kapi::capabilities::facet_id facet) -> void * override { - if (interface == leaf_identification::id) + if (facet == leaf_identification::id) { return static_cast<leaf_identification *>(this); } - return kapi::devices::device::query_interface(interface); + return kapi::devices::device::query_facet(facet); } }; - struct leaf_bus final : kapi::devices::bus, kapi::devices::bus_protocol + struct leaf_protocol final : kapi::devices::bus_protocol { - using kapi::devices::bus::bus; + constexpr auto static id = kapi::capabilities::facet_id{"stacking_test_leaf_protocol"}; auto enumerate(kapi::devices::bus & self) -> void override { @@ -122,18 +132,28 @@ namespace [[nodiscard]] auto match(kapi::devices::device const & dev, kapi::devices::driver const & drv) const -> kstd::result<std::uint32_t> override { - auto const * ident = dev.as<leaf_identification>(); - auto const * claims = drv.as<leaf_driver_identification>(); + auto const * ident = dev.facet<leaf_identification>(); + auto const * claims = drv.facet<leaf_driver_identification>(); if (!ident || !claims || !std::ranges::contains(claims->supported_names(), ident->leaf_name())) { return kstd::failure(kapi::devices::driver_match_errc::no_match); } return 0u; } + } constinit leaf_protocol_instance{}; + + struct leaf_bus final : kapi::devices::bus + { + using kapi::devices::bus::bus; - [[nodiscard]] auto protocol() -> kapi::devices::bus_protocol * override + [[nodiscard]] auto query_facet(kapi::capabilities::facet_id id) -> void * override { - return this; + if (id == leaf_protocol::id || id == kapi::devices::bus_protocol::id) + { + return &leaf_protocol_instance; + } + + return kapi::devices::bus::query_facet(id); } }; @@ -144,7 +164,7 @@ namespace auto self_as_bus = kstd::static_pointer_cast<kapi::devices::bus>(dev.shared_from_this()); auto leaf = kstd::make_shared<leaf_bus>("stacking_test_leaf_bus"); self_as_bus->add_child(leaf); - leaf->enumerate(*leaf); + leaf->facet<leaf_protocol>()->enumerate(*leaf); return kstd::success(); } @@ -163,14 +183,14 @@ namespace } protected: - auto query_interface(kapi::devices::interface_id interface) -> void * override + auto query_facet(kapi::capabilities::facet_id facet) -> void * override { - if (interface == controller_driver_identification::id) + if (facet == controller_driver_identification::id) { return static_cast<controller_driver_identification *>(this); } - return kapi::devices::driver::query_interface(interface); + return kapi::devices::driver::query_facet(facet); } }; @@ -195,14 +215,14 @@ namespace } protected: - auto query_interface(kapi::devices::interface_id interface) -> void * override + auto query_facet(kapi::capabilities::facet_id facet) -> void * override { - if (interface == leaf_driver_identification::id) + if (facet == leaf_driver_identification::id) { return static_cast<leaf_driver_identification *>(this); } - return kapi::devices::driver::query_interface(interface); + return kapi::devices::driver::query_facet(facet); } }; } // namespace diff --git a/kernel/kapi/devices/driver_registry.cpp b/kernel/kapi/devices/driver_registry.cpp index cb101d27..842dbc1d 100644 --- a/kernel/kapi/devices/driver_registry.cpp +++ b/kernel/kapi/devices/driver_registry.cpp @@ -79,7 +79,7 @@ namespace kapi::devices } auto parent = device->parent(); - auto protocol = parent ? parent->protocol() : nullptr; + auto protocol = parent ? parent->facet<kapi::devices::bus_protocol>() : nullptr; if (!protocol) { return; diff --git a/kernel/kapi/devices/driver_registry.tests.cpp b/kernel/kapi/devices/driver_registry.tests.cpp index d4d8a174..c7d1744d 100644 --- a/kernel/kapi/devices/driver_registry.tests.cpp +++ b/kernel/kapi/devices/driver_registry.tests.cpp @@ -15,7 +15,7 @@ namespace struct test_identification { - constexpr auto static id = kapi::devices::interface_id{"test_identification"}; + constexpr auto static id = kapi::capabilities::facet_id{"test_identification"}; virtual ~test_identification() = default; @@ -25,6 +25,8 @@ namespace struct test_protocol final : kapi::devices::bus_protocol { + constexpr auto static id = kapi::capabilities::facet_id{"test_protocol"}; + explicit test_protocol(unsigned * match_calls) : match_calls{match_calls} {} @@ -36,7 +38,7 @@ namespace { ++*match_calls; - auto const * identification = driver.as<test_identification>(); + auto const * identification = driver.facet<test_identification>(); if (!identification) { return kstd::failure(kapi::devices::driver_match_errc::no_match); @@ -52,9 +54,14 @@ namespace { using kapi::devices::bus::bus; - [[nodiscard]] auto protocol() -> kapi::devices::bus_protocol * override + [[nodiscard]] auto query_facet(kapi::capabilities::facet_id id) -> void * override { - return &bus_protocol; + if (id == test_protocol::id || id == kapi::devices::bus_protocol::id) + { + return &bus_protocol; + } + + return kapi::devices::bus::query_facet(id); } unsigned match_calls{}; @@ -106,14 +113,14 @@ namespace mutable unsigned probe_calls; protected: - auto query_interface(kapi::devices::interface_id interface) -> void * override + auto query_facet(kapi::capabilities::facet_id facet) -> void * override { - if (interface == test_identification::id) + if (facet == test_identification::id) { return static_cast<test_identification *>(this); } - return kapi::devices::driver::query_interface(interface); + return kapi::devices::driver::query_facet(facet); } private: diff --git a/kernel/kapi/devices/facet_registry.cpp b/kernel/kapi/devices/facet_registry.cpp new file mode 100644 index 00000000..4aeebfc1 --- /dev/null +++ b/kernel/kapi/devices/facet_registry.cpp @@ -0,0 +1,216 @@ +#include <kapi/devices/facet_registry.hpp> + +#include <kapi/devices.hpp> +#include <kapi/system.hpp> +#include <kapi/test_support/devices.hpp> + +#include <kstd/memory.hpp> +#include <kstd/result.hpp> +#include <kstd/string.hpp> +#include <kstd/system_error.hpp> +#include <kstd/vector.hpp> + +#include <algorithm> +#include <optional> +#include <string_view> +#include <utility> + +namespace kapi::devices +{ + + namespace + { + constinit auto static registry = std::optional<facet_registry>{}; + } + + auto facet_registry::init() -> void + { + if (registry.has_value()) + { + system::panic("[kernel] Device facet registry has already been initialized."); + } + + registry.emplace(); + } + + auto facet_registry::get() -> facet_registry & + { + if (!registry) + { + system::panic("[kernel] Device facet registry has not been initialized."); + } + + return *registry; + } + + auto facet_registry::do_publish(kstd::shared_ptr<device> device, kstd::string name, kapi::capabilities::facet_id id, + void * facet) -> kstd::result<void> + { + // TODO: lock registry + + erase_if(m_entries, [id](auto e) { return e.id() == id && !e.device(); }); + + if (!device || !facet || name.empty()) + { + return kstd::failure(make_error_code(kstd::errc::invalid_argument)); + } + + auto already_published = std::ranges::any_of( + m_entries, [&](auto const & entry) { return entry.id() == id && entry.device().get() == device.get(); }); + + if (already_published) + { + return kstd::failure(make_error_code(kstd::errc::file_exists)); + } + + auto & published = m_entries.emplace_back(device, std::move(name), id, facet); + + do_notify_published(id, published); + + return kstd::success(); + } + + auto facet_registry::do_notify_published(kapi::capabilities::facet_id id, entry const & published) -> void + { + std::ranges::for_each(m_observers, [&](auto observer) { + if (auto locked_observer = observer.lock()) + { + locked_observer->on_facet_published(id, published); + } + }); + + std::ranges::for_each(m_static_observers, [&](auto observer) { observer->on_facet_published(id, published); }); + } + + auto facet_registry::do_notify_withdrawn(kapi::capabilities::facet_id id, device const & device) -> void + { + std::ranges::for_each(m_observers, [&](auto observer) { + if (auto locked_observer = observer.lock()) + { + locked_observer->on_facet_withdrawn(id, const_cast<devices::device &>(device)); + } + }); + + std::ranges::for_each(m_static_observers, [&](auto observer) { + observer->on_facet_withdrawn(id, const_cast<devices::device &>(device)); + }); + } + + auto facet_registry::withdraw(device const & device, kapi::capabilities::facet_id id) -> void + { + // TODO: lock registry + + auto did_remove = erase_if(m_entries, [&](auto e) { + auto locked_device = e.device(); + return e.id() == id && locked_device && locked_device.get() == &device; + }) != 0; + + if (did_remove) + { + do_notify_withdrawn(id, device); + } + } + + auto facet_registry::withdraw_all_for(device const & device) -> void + { + // TODO: lock registry + + auto withdrawn_facets = kstd::vector<kapi::capabilities::facet_id>{}; + + erase_if(m_entries, [&](auto e) { + auto locked_device = e.device(); + auto do_erase = locked_device && locked_device.get() == &device; + if (do_erase) + { + withdrawn_facets.push_back(e.id()); + } + return do_erase; + }); + + std::ranges::for_each(withdrawn_facets, [&](auto facet) { do_notify_withdrawn(facet, device); }); + } + + auto facet_registry::all(kapi::capabilities::facet_id id) const -> kstd::vector<entry> + { + // TODO: lock registry + + auto filtered = m_entries; + erase_if(filtered, [&](auto e) { + auto locked_device = e.device(); + return !(e.id() == id && locked_device); + }); + return filtered; + } + + auto facet_registry::resolve(kapi::capabilities::facet_id id, std::string_view name) -> void * + { + // TODO: lock registry + + auto found = std::ranges::find_if(m_entries, [&](auto e) { return e.name() == name && e.device(); }); + + if (found == m_entries.cend()) + { + return nullptr; + } + else if (auto device = found->device()) + { + return resolve(id, *device); + } + + return nullptr; + } + + auto facet_registry::resolve(kapi::capabilities::facet_id id, device & device) -> void * + { + // TODO: lock registry + + if (auto by_device = device.facet(id)) + { + return by_device; + } + + auto found = std::ranges::find_if(m_entries, [&](auto e) { + auto locked_device = e.device(); + return e.id() == id && locked_device && locked_device.get() == &device; + }); + + if (found == m_entries.cend()) + { + return nullptr; + } + + return found->untyped_facet(); + } + + auto facet_registry::subscribe(kstd::weak_ptr<facet_registry_observer> observer) -> void + { + // TODO: lock registry + + erase_if(m_observers, [](auto const & observer) { return observer.expired(); }); + m_observers.push_back(observer); + } + + auto facet_registry::subscribe(facet_registry_observer & observer) -> void + { + // TODO: lock registry + + m_static_observers.push_back(&observer); + } + + auto facet_registry::unsubscribe(facet_registry_observer & observer) -> void + { + // TODO: lock registry + + erase_if(m_observers, [&](auto const & subscribed) { return subscribed.lock().get() == &observer; }); + erase(m_static_observers, &observer); + } + +} // namespace kapi::devices + +namespace kapi::test_support::devices +{ + auto deinit_facet_registry() -> void + { + kapi::devices::registry.reset(); + } +} // namespace kapi::test_support::devices diff --git a/kernel/kapi/devices/interface_registry.tests.cpp b/kernel/kapi/devices/facet_registry.tests.cpp index 071b9a6d..4ad3f763 100644 --- a/kernel/kapi/devices/interface_registry.tests.cpp +++ b/kernel/kapi/devices/facet_registry.tests.cpp @@ -10,7 +10,7 @@ namespace { struct probe_device { - constexpr auto static id = kapi::devices::interface_id{"probe"}; + constexpr auto static id = kapi::capabilities::facet_id{"probe"}; virtual ~probe_device() = default; @@ -19,7 +19,7 @@ namespace struct const_device { - constexpr auto static id = kapi::devices::interface_id{"flip"}; + constexpr auto static id = kapi::capabilities::facet_id{"flip"}; virtual ~const_device() = default; @@ -31,7 +31,7 @@ namespace struct unimplemented_device { - constexpr auto static id = kapi::devices::interface_id{"unimplemented"}; + constexpr auto static id = kapi::capabilities::facet_id{"unimplemented"}; virtual ~unimplemented_device() = default; }; @@ -49,18 +49,18 @@ namespace return m_value; } - auto query_interface(kapi::devices::interface_id interface) -> void * override + auto query_facet(kapi::capabilities::facet_id facet) -> void * override { - if (interface == probe_device::id) + if (facet == probe_device::id) { return static_cast<probe_device *>(this); } - if (interface == const_device::id) + if (facet == const_device::id) { return m_const_device; } - return kapi::devices::device::query_interface(interface); + return kapi::devices::device::query_facet(facet); } private: @@ -68,15 +68,14 @@ namespace const_device * m_const_device; }; - struct counting_observer final : kapi::devices::interface_registry_observer + struct counting_observer final : kapi::devices::facet_registry_observer { - auto on_interface_published(kapi::devices::interface_id, kapi::devices::interface_registry::entry const &) - -> void override + auto on_facet_published(kapi::capabilities::facet_id, kapi::devices::facet_registry::entry const &) -> void override { ++published; } - auto on_interface_withdrawn(kapi::devices::interface_id, kapi::devices::device &) -> void override + auto on_facet_withdrawn(kapi::capabilities::facet_id, kapi::devices::device &) -> void override { ++withdrawn; } @@ -85,19 +84,18 @@ namespace std::size_t withdrawn{}; }; - struct evil_observer final : kapi::devices::interface_registry_observer + struct evil_observer final : kapi::devices::facet_registry_observer { explicit evil_observer(kstd::shared_ptr<counting_observer> & victim) : m_victim{victim} {} - auto on_interface_published(kapi::devices::interface_id, kapi::devices::interface_registry::entry const &) - -> void override + auto on_facet_published(kapi::capabilities::facet_id, kapi::devices::facet_registry::entry const &) -> void override { m_victim.reset(); } - auto on_interface_withdrawn(kapi::devices::interface_id, kapi::devices::device &) -> void override + auto on_facet_withdrawn(kapi::capabilities::facet_id, kapi::devices::device &) -> void override { m_victim.reset(); } @@ -108,46 +106,46 @@ namespace } // namespace -SCENARIO("Publishing and finding a device", "[kapi][devices][interface_registry]") +SCENARIO("Publishing and finding a device", "[kapi][devices][facet_registry]") { - GIVEN("An empty registry, a device, and an interface the device implements by inheritance") + GIVEN("An empty registry, a device, and a facet the device implements by inheritance") { - auto registry = kapi::devices::interface_registry{}; - auto free_standing_interface = const_device{}; - auto device = kstd::make_shared<test_device>(128, free_standing_interface); + auto registry = kapi::devices::facet_registry{}; + auto free_standing_facet = const_device{}; + auto device = kstd::make_shared<test_device>(128, free_standing_facet); - THEN("Publishing an interface without a name fails") + THEN("Publishing an facet without a name fails") { REQUIRE_FALSE(registry.publish<probe_device>(device, "")); } - WHEN("publishing the interface for the device") + WHEN("publishing the facet for the device") { - CHECK(device->is_a<probe_device>()); - CHECK(device->is_a<const_device>()); - auto published = registry.publish(device, "probe0", device->as<probe_device>()); + CHECK(device->has_facet<probe_device>()); + CHECK(device->has_facet<const_device>()); + auto published = registry.publish(device, "probe0", device->facet<probe_device>()); THEN("publishing is successful") { REQUIRE(published); } - THEN("publishing the same device and interface with a different name fails") + THEN("publishing the same device and facet with a different name fails") { - REQUIRE_FALSE(registry.publish(device, "probe1", device->as<probe_device>())); + REQUIRE_FALSE(registry.publish(device, "probe1", device->facet<probe_device>())); } - THEN("publishing a second interface for the same device succeeds") + THEN("publishing a second facet for the same device succeeds") { REQUIRE(registry.publish<const_device>(device, "probe0")); } - THEN("publishing a free standing second interface for the same device succeeds") + THEN("publishing a free standing second facet for the same device succeeds") { - REQUIRE(registry.publish(device, "probe0", &free_standing_interface)); + REQUIRE(registry.publish(device, "probe0", &free_standing_facet)); } - AND_WHEN("getting all devices implementing that interface") + AND_WHEN("getting all devices implementing that facet") { auto probeable_devices = registry.all(probe_device::id); @@ -168,12 +166,12 @@ SCENARIO("Publishing and finding a device", "[kapi][devices][interface_registry] THEN("the returned implementation equals the result of device::as") { - REQUIRE(probeable_devices[0].implementation() == device->as<probe_device>()); + REQUIRE(probeable_devices[0].untyped_facet() == device->facet<probe_device>()); } - THEN("the interface provided function can be invoked") + THEN("the facet provided function can be invoked") { - auto implementation = probeable_devices[0].as<probe_device>(); + auto implementation = probeable_devices[0].facet<probe_device>(); REQUIRE(implementation->get_value() == device->get_value()); } } @@ -198,7 +196,7 @@ SCENARIO("Publishing and finding a device", "[kapi][devices][interface_registry] REQUIRE_FALSE(registry.resolve<probe_device>("probe1")); } - THEN("withdrawing an interface for a device removes it from the registry") + THEN("withdrawing an facet for a device removes it from the registry") { registry.withdraw(*device, probe_device::id); REQUIRE_FALSE(registry.resolve<probe_device>("probe0")); @@ -207,7 +205,7 @@ SCENARIO("Publishing and finding a device", "[kapi][devices][interface_registry] WHEN("the device is destroyed without withdrawing it") { - CHECK(registry.publish(device, "probe0", device->as<probe_device>())); + CHECK(registry.publish(device, "probe0", device->facet<probe_device>())); device.reset(); THEN("querying all does no longer report it") @@ -224,7 +222,7 @@ SCENARIO("Publishing and finding a device", "[kapi][devices][interface_registry] GIVEN("no device has ever been published") { - auto registry = kapi::devices::interface_registry{}; + auto registry = kapi::devices::facet_registry{}; THEN("all() returns an empty vector") { @@ -234,31 +232,31 @@ SCENARIO("Publishing and finding a device", "[kapi][devices][interface_registry] GIVEN("a null device") { - auto registry = kapi::devices::interface_registry{}; + auto registry = kapi::devices::facet_registry{}; auto device = kstd::shared_ptr<kapi::devices::device>{}; - auto interface = const_device{}; + auto facet = const_device{}; - THEN("publishing the interface for the device fails") + THEN("publishing the facet for the device fails") { - REQUIRE_FALSE(registry.publish(device, "probe0", &interface)); + REQUIRE_FALSE(registry.publish(device, "probe0", &facet)); } } } -SCENARIO("Interface registry notifies subscribers", "[kapi][devices][interface_registry]") +SCENARIO("facet registry notifies subscribers", "[kapi][devices][facet_registry]") { GIVEN("a device and a subscribed observer") { - auto registry = kapi::devices::interface_registry{}; - auto free_standing_interface = const_device{}; - auto device = kstd::make_shared<test_device>(128, free_standing_interface); + auto registry = kapi::devices::facet_registry{}; + auto free_standing_facet = const_device{}; + auto device = kstd::make_shared<test_device>(128, free_standing_facet); auto observer = kstd::make_shared<counting_observer>(); registry.subscribe(observer); - WHEN("an interface is published for the device") + WHEN("an facet is published for the device") { - CHECK(registry.publish(device, "probe0", device->as<probe_device>())); + CHECK(registry.publish(device, "probe0", device->facet<probe_device>())); THEN("the observer is notified exactly once") { @@ -267,9 +265,9 @@ SCENARIO("Interface registry notifies subscribers", "[kapi][devices][interface_r } } - WHEN("an interface is published and then withdrawn") + WHEN("an facet is published and then withdrawn") { - CHECK(registry.publish(device, "probe0", device->as<probe_device>())); + CHECK(registry.publish(device, "probe0", device->facet<probe_device>())); registry.withdraw(*device, probe_device::id); THEN("the observer is notified of both exactly one") @@ -285,7 +283,7 @@ SCENARIO("Interface registry notifies subscribers", "[kapi][devices][interface_r THEN("publishing afterward does not crash") { - REQUIRE_NOTHROW(registry.publish(device, "probe0", device->as<probe_device>())); + REQUIRE_NOTHROW(registry.publish(device, "probe0", device->facet<probe_device>())); } } @@ -295,12 +293,12 @@ SCENARIO("Interface registry notifies subscribers", "[kapi][devices][interface_r THEN("publishing afterward does not crash") { - REQUIRE_NOTHROW(registry.publish(device, "probe0", device->as<probe_device>())); + REQUIRE_NOTHROW(registry.publish(device, "probe0", device->facet<probe_device>())); } THEN("the subscriber is not notified") { - REQUIRE_NOTHROW(registry.publish(device, "probe0", device->as<probe_device>())); + REQUIRE_NOTHROW(registry.publish(device, "probe0", device->facet<probe_device>())); REQUIRE_NOTHROW(registry.withdraw(*device, probe_device::id)); REQUIRE(observer->published == 0); REQUIRE(observer->withdrawn == 0); @@ -310,9 +308,9 @@ SCENARIO("Interface registry notifies subscribers", "[kapi][devices][interface_r GIVEN("two subscriber, the first destroying the second") { - auto registry = kapi::devices::interface_registry{}; - auto free_standing_interface = const_device{}; - auto device = kstd::make_shared<test_device>(128, free_standing_interface); + auto registry = kapi::devices::facet_registry{}; + auto free_standing_facet = const_device{}; + auto device = kstd::make_shared<test_device>(128, free_standing_facet); auto second = kstd::make_shared<counting_observer>(); auto first = kstd::make_shared<evil_observer>(second); @@ -320,9 +318,9 @@ SCENARIO("Interface registry notifies subscribers", "[kapi][devices][interface_r registry.subscribe(first); registry.subscribe(second); - THEN("publishing an interface does not crash") + THEN("publishing an facet does not crash") { - REQUIRE_NOTHROW(registry.publish(device, "probe0", device->as<probe_device>())); + REQUIRE_NOTHROW(registry.publish(device, "probe0", device->facet<probe_device>())); REQUIRE(second == nullptr); } } diff --git a/kernel/kapi/devices/interface_registry.cpp b/kernel/kapi/devices/interface_registry.cpp deleted file mode 100644 index 1d456b30..00000000 --- a/kernel/kapi/devices/interface_registry.cpp +++ /dev/null @@ -1,218 +0,0 @@ -#include <kapi/devices/interface_registry.hpp> - -#include <kapi/devices.hpp> -#include <kapi/system.hpp> -#include <kapi/test_support/devices.hpp> - -#include <kstd/memory.hpp> -#include <kstd/result.hpp> -#include <kstd/string.hpp> -#include <kstd/system_error.hpp> -#include <kstd/vector.hpp> - -#include <algorithm> -#include <optional> -#include <string_view> -#include <utility> - -namespace kapi::devices -{ - - namespace - { - constinit auto static registry = std::optional<interface_registry>{}; - } - - auto interface_registry::init() -> void - { - if (registry.has_value()) - { - system::panic("[kernel] Device interface registry has already been initialized."); - } - - registry.emplace(); - } - - auto interface_registry::get() -> interface_registry & - { - if (!registry) - { - system::panic("[kernel] Device interface registry has not been initialized."); - } - - return *registry; - } - - auto interface_registry::do_publish(kstd::shared_ptr<device> device, kstd::string name, interface_id interface, - void * implementation) -> kstd::result<void> - { - // TODO: lock registry - - erase_if(m_entries, [interface](auto e) { return e.interface() == interface && !e.device(); }); - - if (!device || !implementation || name.empty()) - { - return kstd::failure(make_error_code(kstd::errc::invalid_argument)); - } - - auto already_published = std::ranges::any_of(m_entries, [&](auto const & entry) { - return entry.interface() == interface && entry.device().get() == device.get(); - }); - - if (already_published) - { - return kstd::failure(make_error_code(kstd::errc::file_exists)); - } - - auto & published = m_entries.emplace_back(device, std::move(name), interface, implementation); - - do_notify_published(interface, published); - - return kstd::success(); - } - - auto interface_registry::do_notify_published(interface_id interface, entry const & published) -> void - { - std::ranges::for_each(m_observers, [&](auto observer) { - if (auto locked_observer = observer.lock()) - { - locked_observer->on_interface_published(interface, published); - } - }); - - std::ranges::for_each(m_static_observers, - [&](auto observer) { observer->on_interface_published(interface, published); }); - } - - auto interface_registry::do_notify_withdrawn(interface_id interface, device const & device) -> void - { - std::ranges::for_each(m_observers, [&](auto observer) { - if (auto locked_observer = observer.lock()) - { - locked_observer->on_interface_withdrawn(interface, const_cast<devices::device &>(device)); - } - }); - - std::ranges::for_each(m_static_observers, [&](auto observer) { - observer->on_interface_withdrawn(interface, const_cast<devices::device &>(device)); - }); - } - - auto interface_registry::withdraw(device const & device, interface_id interface) -> void - { - // TODO: lock registry - - auto did_remove = erase_if(m_entries, [&](auto e) { - auto locked_device = e.device(); - return e.interface() == interface && locked_device && locked_device.get() == &device; - }) != 0; - - if (did_remove) - { - do_notify_withdrawn(interface, device); - } - } - - auto interface_registry::withdraw_all_for(device const & device) -> void - { - // TODO: lock registry - - auto withdrawn_interfaces = kstd::vector<interface_id>{}; - - erase_if(m_entries, [&](auto e) { - auto locked_device = e.device(); - auto do_erase = locked_device && locked_device.get() == &device; - if (do_erase) - { - withdrawn_interfaces.push_back(e.interface()); - } - return do_erase; - }); - - std::ranges::for_each(withdrawn_interfaces, [&](auto interface) { do_notify_withdrawn(interface, device); }); - } - - auto interface_registry::all(interface_id interface) const -> kstd::vector<entry> - { - // TODO: lock registry - - auto filtered = m_entries; - erase_if(filtered, [&](auto e) { - auto locked_device = e.device(); - return !(e.interface() == interface && locked_device); - }); - return filtered; - } - - auto interface_registry::resolve(interface_id interface, std::string_view name) -> void * - { - // TODO: lock registry - - auto found = std::ranges::find_if(m_entries, [&](auto e) { return e.name() == name && e.device(); }); - - if (found == m_entries.cend()) - { - return nullptr; - } - else if (auto device = found->device()) - { - return resolve(interface, *device); - } - - return nullptr; - } - - auto interface_registry::resolve(interface_id interface, device & device) -> void * - { - // TODO: lock registry - - if (auto by_device = device.as(interface)) - { - return by_device; - } - - auto found = std::ranges::find_if(m_entries, [&](auto e) { - auto locked_device = e.device(); - return e.interface() == interface && locked_device && locked_device.get() == &device; - }); - - if (found == m_entries.cend()) - { - return nullptr; - } - - return found->implementation(); - } - - auto interface_registry::subscribe(kstd::weak_ptr<interface_registry_observer> observer) -> void - { - // TODO: lock registry - - erase_if(m_observers, [](auto const & observer) { return observer.expired(); }); - m_observers.push_back(observer); - } - - auto interface_registry::subscribe(interface_registry_observer & observer) -> void - { - // TODO: lock registry - - m_static_observers.push_back(&observer); - } - - auto interface_registry::unsubscribe(interface_registry_observer & observer) -> void - { - // TODO: lock registry - - erase_if(m_observers, [&](auto const & subscribed) { return subscribed.lock().get() == &observer; }); - erase(m_static_observers, &observer); - } - -} // namespace kapi::devices - -namespace kapi::test_support::devices -{ - auto deinit_interface_registry() -> void - { - kapi::devices::registry.reset(); - } -} // namespace kapi::test_support::devices |
