6#include <unordered_map>
16 std::shared_ptr<IEditingExtensionProvider>
provider;
19 std::unordered_map<std::string, Entry>
entries;
26 std::vector<std::shared_ptr<IEditingExtensionProvider>> providers;
28 std::scoped_lock lock(impl_->mutex);
29 for (
auto& [
id, entry] : impl_->entries) providers.push_back(entry.provider);
30 impl_->entries.clear();
32 for (
auto& provider : providers) {
33 provider->beginUnload().ignore(
"editing extension registry teardown");
34 provider->deactivate();
41 return eve::editing::failed<ProviderHandle>(
42 Status::Rejected,
RuleId(
"editing.extension.invalid-provider"),
43 "Extension provider requires id, schema version and implementation");
45 std::scoped_lock lock(impl_->mutex);
47 return eve::editing::failed<ProviderHandle>(Status::Conflict,
48 RuleId(
"editing.extension.duplicate-provider"),
49 "Extension provider id is already published");
51 auto activated = provider->activate();
53 return eve::editing::failed<ProviderHandle>(Status::Failed,
RuleId(
"editing.extension.activation-failed"),
54 "Extension provider activation failed");
56 bool duplicate =
false;
58 std::scoped_lock lock(impl_->mutex);
63 handle = {providerId, ++impl_->generations[providerId]};
68 provider->deactivate();
69 return eve::editing::failed<ProviderHandle>(Status::Conflict,
RuleId(
"editing.extension.duplicate-provider"),
70 "Extension provider id was concurrently published");
72 return eve::editing::applied<ProviderHandle>(
handle);
76 std::scoped_lock lock(impl_->mutex);
78 if (
found == impl_->entries.end()) {
80 return eve::editing::failed<ProviderLease>(
81 generation == impl_->generations.end() ? Status::Unsupported : Status::Conflict,
82 RuleId(
generation == impl_->generations.end() ?
"editing.extension.provider-absent"
83 :
"editing.extension.stale-handle"),
84 generation == impl_->generations.end() ?
"Editing extension provider is not available"
85 :
"Editing extension handle is stale");
88 return eve::editing::failed<ProviderLease>(Status::Conflict,
RuleId(
"editing.extension.stale-handle"),
89 "Editing extension handle is stale");
94 std::scoped_lock lock(impl_->mutex);
95 const auto found = impl_->entries.find(
id);
96 if (
found == impl_->entries.end())
97 return eve::editing::failed<ProviderLease>(Status::Unsupported,
RuleId(
"editing.extension.provider-absent"),
98 "Editing extension provider is not available");
103 std::shared_ptr<IEditingExtensionProvider> provider;
105 std::scoped_lock lock(impl_->mutex);
108 return eve::editing::failed<void>(Status::Conflict,
RuleId(
"editing.extension.stale-handle"),
109 "Editing extension handle is stale");
110 provider =
found->second.provider;
112 auto stopping = provider->beginUnload();
114 return eve::editing::failed<void>(Status::Failed,
RuleId(
"editing.extension.unload-rejected"),
115 "Editing extension refused to stop accepting work");
117 std::scoped_lock lock(impl_->mutex);
120 return eve::editing::failed<void>(Status::Conflict,
RuleId(
"editing.extension.stale-handle"),
121 "Editing extension handle is stale");
122 impl_->entries.erase(
found);
124 provider->deactivate();
125 return eve::editing::applied<void>();
129 std::vector<ExtensionDescriptor> result;
130 std::scoped_lock lock(impl_->mutex);
131 for (
const auto& [
id, entry] : impl_->entries) result.push_back(entry.descriptor);
132 std::sort(result.begin(), result.end(), [](
const auto&
a,
const auto&
b) { return a.id < b.id; });
139 StaticProvider(
CapabilityId capability, std::shared_ptr<void> implementation)
140 : capability_(
std::move(capability)), implementation_(
std::move(implementation)) {}
143 accepting_.store(
true, std::memory_order_release);
144 return eve::editing::applied<void>();
146 Result<void> beginUnload()
override {
147 accepting_.store(
false, std::memory_order_release);
148 return eve::editing::applied<void>();
150 void deactivate() noexcept
override { accepting_.store(
false, std::memory_order_release); }
152 return accepting_.load(std::memory_order_acquire) && capability == capability_
153 ? implementation_.get()
159 std::shared_ptr<void> implementation_;
160 std::atomic_bool accepting_{
false};
167 std::shared_ptr<void> implementation) {
169 return eve::editing::failed<ProviderHandle>(Status::Rejected,
RuleId(
"editing.extension.null-capability"),
170 "Static editing provider requires an owned capability");
173 descriptor.capabilities.push_back(capability);
176 std::make_shared<StaticProvider>(std::move(capability), std::move(implementation)));
Move-only operation result carrying either a value or Status.
UUID-backed identifier adapter for legacy textual boundaries.
Thread-safe generation-qualified registry for editing extension providers.
Result< ProviderHandle > registerProvider(ExtensionDescriptor descriptor, std::shared_ptr< IEditingExtensionProvider > provider)
Publish and activate a provider atomically from the caller's perspective.
~ExtensionProviderRegistry()
Extension provider registry.
Result< ProviderLease > acquire(const ProviderHandle &handle) const
Acquire an owning lease or return Unsupported/StaleHandle diagnostics.
Result< void > unload(const ProviderHandle &handle)
Stop, unpublish and deactivate the exact provider generation.
std::vector< ExtensionDescriptor > descriptors() const
Return owning copies of current descriptors.
ExtensionProviderRegistry()
Extension provider registry.
IEditingExtensionProvider public API.
ProviderLease public API.
StrongId< RuleIdTag > RuleId
StrongId< CapabilityIdTag > CapabilityId
Result< ProviderHandle > registerStaticProvider(ExtensionProviderRegistry ®istry, ExtensionDescriptor descriptor, CapabilityId capability, std::shared_ptr< void > implementation)
Register one owned capability behind the standard provider lifecycle.
ExtensionDescriptor public API.
ExtensionDescriptor descriptor
std::shared_ptr< IEditingExtensionProvider > provider
std::unordered_map< std::string, std::uint64_t > generations
std::unordered_map< std::string, Entry > entries
ProviderHandle public API.