lenso-app-plan 0.4.1

Immutable Lenso application plans with versioned dependency routing.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
//! Consumer declarations and exact Plugin execution and binding metadata.

use super::{
    CapabilityCardinality, CapabilityEndpointPlan, EventAdmissionPlan, ExecutionClassId,
    ExecutionLaneId, PluginCriticality, RequestAdmissionPlan, RestartPolicy, schema,
};
use serde::{Deserialize, Serialize};

/// One Capability required by a Plugin Instance.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(from = "schema::RequirementWire")]
pub struct CapabilityRequirementPlan {
    #[serde(default)]
    pub(super) requirement_id: String,
    pub(super) capability_id: String,
    pub(super) descriptor_version: String,
    pub(super) cardinality: CapabilityCardinality,
}

impl CapabilityRequirementPlan {
    /// Declares one exact Capability Descriptor and its binding cardinality.
    pub fn new(
        capability_id: impl Into<String>,
        descriptor_version: impl Into<String>,
        cardinality: CapabilityCardinality,
    ) -> Self {
        let capability_id = capability_id.into();
        Self {
            requirement_id: format!("~{capability_id}"),
            capability_id,
            descriptor_version: descriptor_version.into(),
            cardinality,
        }
    }

    /// Declares a required one-provider Capability.
    pub fn one(capability_id: impl Into<String>, descriptor_version: impl Into<String>) -> Self {
        Self::new(
            capability_id,
            descriptor_version,
            CapabilityCardinality::One,
        )
    }

    /// Declares an optional zero-or-one-provider Capability.
    pub fn optional(
        capability_id: impl Into<String>,
        descriptor_version: impl Into<String>,
    ) -> Self {
        Self::new(
            capability_id,
            descriptor_version,
            CapabilityCardinality::Optional,
        )
    }

    /// Declares a many-provider Capability.
    pub fn many(capability_id: impl Into<String>, descriptor_version: impl Into<String>) -> Self {
        Self::new(
            capability_id,
            descriptor_version,
            CapabilityCardinality::Many,
        )
    }

    /// Names this dependency within its consumer's version 2 contract.
    #[must_use]
    pub fn with_requirement_id(mut self, requirement_id: impl Into<String>) -> Self {
        self.requirement_id = requirement_id.into();
        self
    }

    /// Returns the consumer-local identity, including normalized old declarations.
    pub fn requirement_id(&self) -> &str {
        &self.requirement_id
    }

    /// Returns the Capability series identity.
    pub fn capability_id(&self) -> &str {
        &self.capability_id
    }

    /// Returns the exact Descriptor version selected by Composition.
    pub fn descriptor_version(&self) -> &str {
        &self.descriptor_version
    }

    /// Returns the requirement cardinality.
    pub const fn cardinality(&self) -> CapabilityCardinality {
        self.cardinality
    }
}

/// One exact App-local Plugin Instance selected by the resolved Plan.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct PluginInstancePlan {
    #[serde(default = "schema::old_authoring_version")]
    pub(super) authoring_version: u32,
    #[serde(default)]
    pub(super) runtime_profile: String,
    pub(super) instance_key: String,
    pub(super) package_id: String,
    pub(super) entrypoint: String,
    pub(super) configuration: String,
    pub(super) provided_capabilities: Vec<CapabilityEndpointPlan>,
    pub(super) required_capabilities: Vec<CapabilityRequirementPlan>,
    pub(super) execution_class: ExecutionClassId,
    pub(super) package_revision: String,
    pub(super) restart_policy: RestartPolicy,
    pub(super) criticality: PluginCriticality,
    #[serde(default)]
    pub(super) execution_lane: ExecutionLaneId,
}

impl PluginInstancePlan {
    /// Selects one statically linked package under an App-local Instance key.
    pub fn new(instance_key: impl Into<String>, package_id: impl Into<String>) -> Self {
        Self {
            authoring_version: 1,
            runtime_profile: "lenso.native-authoring@1".to_owned(),
            instance_key: instance_key.into(),
            package_id: package_id.into(),
            entrypoint: "default".to_owned(),
            configuration: "{}".to_owned(),
            provided_capabilities: Vec::new(),
            required_capabilities: Vec::new(),
            execution_class: ExecutionClassId::native_rust(),
            package_revision: String::new(),
            restart_policy: RestartPolicy::default(),
            criticality: PluginCriticality::default(),
            execution_lane: ExecutionLaneId::default(),
        }
    }

    /// Selects the exact package entrypoint executed for this Instance.
    #[must_use]
    pub fn with_authoring(mut self, version: u32, runtime_profile: impl Into<String>) -> Self {
        self.authoring_version = version;
        self.runtime_profile = runtime_profile.into();
        self
    }

    /// Returns the selected Plugin contract version.
    pub const fn authoring_version(&self) -> u32 {
        self.authoring_version
    }

    /// Returns the exact opaque execution profile, independently of execution class.
    pub fn runtime_profile(&self) -> &str {
        &self.runtime_profile
    }

    /// Selects the exact package entrypoint executed for this Instance.
    #[must_use]
    pub fn with_entrypoint(mut self, entrypoint: impl Into<String>) -> Self {
        self.entrypoint = entrypoint.into();
        self
    }

    /// Supplies opaque, non-secret configuration owned and decoded by the Plugin.
    #[must_use]
    pub fn with_configuration(mut self, configuration: impl Into<String>) -> Self {
        self.configuration = configuration.into();
        self
    }

    /// Declares one exact endpoint this Instance must prepare.
    #[must_use]
    pub fn with_capability(mut self, capability: CapabilityEndpointPlan) -> Self {
        self.provided_capabilities.push(capability);
        self
    }

    /// Declares one Capability dependency for this Instance.
    #[must_use]
    pub fn with_requirement(mut self, requirement: CapabilityRequirementPlan) -> Self {
        self.required_capabilities.push(requirement);
        self
    }

    /// Alias that makes the authoring direction explicit at the call site.
    #[must_use]
    pub fn with_required_capability(self, requirement: CapabilityRequirementPlan) -> Self {
        self.with_requirement(requirement)
    }

    /// Selects the host execution class for this Plugin Instance.
    #[must_use]
    pub fn with_execution_class(mut self, execution_class: ExecutionClassId) -> Self {
        if self.authoring_version == 1
            && self.runtime_profile == schema::old_runtime_profile(&self.execution_class)
        {
            self.runtime_profile = schema::old_runtime_profile(&execution_class);
        }
        self.execution_class = execution_class;
        self
    }

    /// Places this Plugin Instance on one Plan-declared Execution Lane.
    #[must_use]
    pub fn with_execution_lane(mut self, execution_lane: ExecutionLaneId) -> Self {
        self.execution_lane = execution_lane;
        self
    }

    /// Records the exact opaque package-manager lock selection before boot.
    #[must_use]
    pub fn with_package_revision(mut self, revision: impl Into<String>) -> Self {
        self.package_revision = revision.into();
        self
    }

    /// Selects the finite supervision policy for this Plugin Instance.
    #[must_use]
    pub fn with_restart_policy(mut self, restart_policy: RestartPolicy) -> Self {
        self.restart_policy = restart_policy;
        self
    }

    /// Marks this Plugin Instance critical for supervision exhaustion outcomes.
    #[must_use]
    pub fn with_criticality(mut self, criticality: PluginCriticality) -> Self {
        self.criticality = criticality;
        self
    }

    /// Returns the App-local Instance key.
    pub fn instance_key(&self) -> &str {
        &self.instance_key
    }

    /// Returns the selected package identity.
    pub fn package_id(&self) -> &str {
        &self.package_id
    }

    /// Returns the exact package entrypoint selected before boot.
    pub fn entrypoint(&self) -> &str {
        &self.entrypoint
    }

    /// Returns the Plugin-owned opaque configuration selected before boot.
    pub fn configuration(&self) -> &str {
        &self.configuration
    }

    /// Returns the exact endpoint set this Instance must prepare.
    pub fn provided_capabilities(&self) -> &[CapabilityEndpointPlan] {
        &self.provided_capabilities
    }

    /// Returns the exact Capability requirements this Instance receives.
    pub fn required_capabilities(&self) -> &[CapabilityRequirementPlan] {
        &self.required_capabilities
    }

    /// Returns the host execution class selected for this Instance.
    pub fn execution_class(&self) -> &ExecutionClassId {
        &self.execution_class
    }

    /// Returns the Plan-declared Execution Lane for this Instance.
    pub const fn execution_lane(&self) -> &ExecutionLaneId {
        &self.execution_lane
    }

    /// Returns the exact opaque package-manager lock selection.
    pub fn package_revision(&self) -> &str {
        &self.package_revision
    }

    /// Returns the supervision policy selected for this Instance.
    pub const fn restart_policy(&self) -> RestartPolicy {
        self.restart_policy
    }

    /// Returns the criticality selected for this Instance.
    pub const fn criticality(&self) -> PluginCriticality {
        self.criticality
    }
}

/// One exact consumer-to-provider Capability binding.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(from = "schema::BindingWire")]
pub struct CapabilityBinding {
    #[serde(default)]
    pub(super) requirement_id: String,
    pub(super) consumer_instance: String,
    pub(super) capability_id: String,
    pub(super) descriptor_version: String,
    pub(super) provider_instance: String,
    pub(super) provider_order: usize,
    pub(super) admission: RequestAdmissionPlan,
    pub(super) admission_explicit: bool,
    pub(super) event_admission: EventAdmissionPlan,
    pub(super) event_admission_explicit: bool,
}

impl CapabilityBinding {
    /// Binds one consumer to one provider at an exact Descriptor version.
    pub fn new(
        consumer_instance: impl Into<String>,
        capability_id: impl Into<String>,
        descriptor_version: impl Into<String>,
        provider_instance: impl Into<String>,
    ) -> Self {
        let capability_id = capability_id.into();
        Self {
            requirement_id: format!("~{capability_id}"),
            consumer_instance: consumer_instance.into(),
            capability_id,
            descriptor_version: descriptor_version.into(),
            provider_instance: provider_instance.into(),
            provider_order: 0,
            admission: RequestAdmissionPlan::default(),
            admission_explicit: false,
            event_admission: EventAdmissionPlan::default(),
            event_admission_explicit: false,
        }
    }

    /// Selects the consumer-local named requirement.
    #[must_use]
    pub fn with_requirement_id(mut self, requirement_id: impl Into<String>) -> Self {
        self.requirement_id = requirement_id.into();
        self
    }

    /// Returns the consumer-local requirement selected by this binding.
    pub fn requirement_id(&self) -> &str {
        &self.requirement_id
    }

    /// Overrides the provider Operation admission policy for this binding.
    #[must_use]
    pub fn with_admission(mut self, admission: RequestAdmissionPlan) -> Self {
        self.admission = admission;
        self.admission_explicit = true;
        self
    }

    /// Overrides queue and concurrency limits for this binding.
    #[must_use]
    pub fn with_limits(self, queue_capacity: usize, max_concurrency: usize) -> Self {
        self.with_admission(RequestAdmissionPlan::new(queue_capacity, max_concurrency))
    }

    /// Overrides the Event mailbox policy for this binding.
    #[must_use]
    pub fn with_event_admission(mut self, admission: EventAdmissionPlan) -> Self {
        self.event_admission = admission;
        self.event_admission_explicit = true;
        self
    }

    /// Overrides the Event mailbox capacity for this binding.
    #[must_use]
    pub fn with_event_capacity(self, capacity: usize) -> Self {
        self.with_event_admission(EventAdmissionPlan::new(capacity))
    }

    pub(super) fn with_provider_order(mut self, provider_order: usize) -> Self {
        self.provider_order = provider_order;
        self
    }

    /// Returns the consumer Instance key.
    pub fn consumer_instance(&self) -> &str {
        &self.consumer_instance
    }

    /// Returns the Capability series identity.
    pub fn capability_id(&self) -> &str {
        &self.capability_id
    }

    /// Returns the exact Descriptor version.
    pub fn descriptor_version(&self) -> &str {
        &self.descriptor_version
    }

    /// Returns the provider Instance key.
    pub fn provider_instance(&self) -> &str {
        &self.provider_instance
    }

    /// Returns the deterministic zero-based order within a `many` requirement.
    pub const fn provider_order(&self) -> usize {
        self.provider_order
    }

    /// Returns the binding's effective fallback admission policy.
    pub const fn admission(&self) -> RequestAdmissionPlan {
        self.admission
    }

    /// Returns whether this binding explicitly overrides the provider policy.
    pub const fn has_explicit_admission(&self) -> bool {
        self.admission_explicit
    }

    /// Returns the binding's effective fallback Event mailbox policy.
    pub const fn event_admission(&self) -> EventAdmissionPlan {
        self.event_admission
    }

    /// Returns whether this binding explicitly overrides the provider Event policy.
    pub const fn has_explicit_event_admission(&self) -> bool {
        self.event_admission_explicit
    }
}