aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/briefs/tb0003-facet-based-capability-dispatch.rst8
1 files changed, 4 insertions, 4 deletions
diff --git a/docs/briefs/tb0003-facet-based-capability-dispatch.rst b/docs/briefs/tb0003-facet-based-capability-dispatch.rst
index 7027a700..321c2694 100644
--- a/docs/briefs/tb0003-facet-based-capability-dispatch.rst
+++ b/docs/briefs/tb0003-facet-based-capability-dispatch.rst
@@ -55,7 +55,7 @@ Every facet type — a pure abstract interface, in the ordinary C++ sense — de
struct block_special_file
{
- constexpr auto static id = kapi::capabilities::facet_id{"block"};
+ constexpr auto static id = kapi::capabilities::facet_id{"fs.spec.block"};
virtual ~block_special_file() = default;
[[nodiscard]] virtual auto read_block(std::size_t block_index, std::span<std::byte> buffer)
@@ -133,7 +133,7 @@ A driver has to be able to say *what it claims to support* using the same vocabu
// arch/x86_64/arch/bus/isa.hpp
struct isa_claim
{
- constexpr auto static id = kapi::capabilities::facet_id{"isa_claim"};
+ constexpr auto static id = kapi::capabilities::facet_id{"clm.drv.isa"};
virtual ~isa_claim() = default;
[[nodiscard]] virtual auto supported_names() const -> std::span<std::string_view const> = 0;
};
@@ -264,7 +264,7 @@ The two device-model facets already shown (``isa_signature``/``isa_claim``, ``bl
{
struct temperature_sensor
{
- constexpr auto static id = kapi::capabilities::facet_id{"temperature_sensor"};
+ constexpr auto static id = kapi::capabilities::facet_id{"sns.cap.temp"};
virtual ~temperature_sensor() = default;
[[nodiscard]] virtual auto read_millicelsius() const -> kstd::result<std::int32_t> = 0;
};
@@ -386,7 +386,7 @@ Drawbacks and Limitations
Stated as plainly as the benefits above, because a design write-up that only lists advantages is not documenting an architecture — it is advertising one.
-* **String-keyed identity has no uniqueness guarantee.** ``facet_id`` equality is ``std::string_view`` content equality. Two unrelated facets that happen to share a literal — a typo, a copy-pasted ``id`` line, or an honest independent choice of the same short word by two different students — become, from the mechanism's point of view, *the same facet*. A ``query_facet()`` handling one of them will hand back a pointer, ``static_cast`` will "succeed" in the sense of not crashing, and the caller will silently operate on an object through the wrong type's vtable. Nothing in the type system catches this; it is a runtime, likely intermittent, memory-safety bug. Unlike COM's GUIDs (128 bits, generated to make an accidental collision practically impossible) or Rust's compiler-derived ``TypeId``, there is currently no mechanism in TeachOS enforcing that two ``facet_id`` values with the same name really do refer to the same facet, or catching it when they do not.
+* **String-keyed identity has no uniqueness guarantee.** ``facet_id`` equality is ``std::string_view`` content equality. Two unrelated facets that happen to share a literal — a typo, a copy-pasted ``id`` line, or an honest independent choice of the same string by two different students — become, from the mechanism's point of view, *the same facet*. A ``query_facet()`` handling one of them will hand back a pointer, ``static_cast`` will "succeed" in the sense of not crashing, and the caller will silently operate on an object through the wrong type's vtable. Nothing in the type system catches this; it is a runtime, likely intermittent, memory-safety bug. Unlike COM's GUIDs (128 bits, generated to make an accidental collision practically impossible) or Rust's compiler-derived ``TypeId``, there is no mechanism in TeachOS enforcing that two ``facet_id`` values with the same name really do refer to the same facet, or catching it when they do not.
* **The delegation chain is manual and unenforced.** Every ``query_facet()`` override that does not recognize a requested id must remember to fall through to its base class's ``query_facet()``. Forgetting this (easy to do — it compiles cleanly either way) silently makes every facet contributed by the base class unreachable through that subtype, with no compiler diagnostic and no crash — only a ``has_facet()`` that quietly returns false where it should not, discovered (if it is discovered at all) as a device that mysteriously never matches a driver it should have.
* **No enumeration or reflection.** There is no way to ask a ``device`` or a ``facet_registry::entry`` "what facets do you support" in general — only "do you support *this specific* facet", one id at a time. A caller must already know which tag to ask for. This is the direct cost of the expression-problem trade-off described above: the operation "list every facet a device has" is not something the mechanism was designed to answer, and adding it would need either an explicit per-type registration list (defeating the "device layer knows nothing about facets" property) or a hand-maintained catalogue kept separately from every facet definition, with the drift risk that implies.
* **Dispatch cost is linear in the number of facets a concrete type supports**, not constant. Each ``query_facet()`` override is a manual if/else-if chain; a type supporting five facets does up to five string-view comparisons per query, whereas a real vtable slot is one indirect call regardless of how many other virtual functions the type has. For device counts and facet counts in a teaching kernel this is immaterial, but it is a genuine, quantifiable difference from the polymorphism this mechanism deliberately avoids, worth naming rather than glossing over.