1mod codec;
13mod owned;
14#[cfg(feature = "grpc")]
15mod protobuf;
16#[cfg(feature = "streaming")]
17mod streams;
18
19pub use codec::WireCodecError;
22#[cfg(feature = "streaming")]
23pub use streams::{WireEndpoints, WireStreamLimits, WireStreams};
24
25use std::collections::BTreeMap;
29use std::future::Future;
30use std::marker::PhantomData;
31use std::num::NonZeroUsize;
32use std::pin::Pin;
33use std::sync::{Arc, Mutex, Weak};
34use std::task::{Poll, Waker};
35use serde::{Deserialize, Serialize};
37use super::{AuthoredDeclarations, Contract, ContractError, Definition, FailureKind, Operation};
39use crate::catalog::{Catalog, Member, Projection, Visitor};
40
41pub const WIRE_METHOD: &str = "harmos.operation.v2";
44
45pub const CHILD_METHOD: &str = "harmos.operation.child.v2";
46
47type Answer<'a> = Pin<Box<dyn Future<Output = Result<Vec<u8>, ServingError>> + Send + 'a>>;
52type Finished<'a> = Pin<Box<dyn Future<Output = Result<(), ServingError>> + Send + 'a>>;
53type Finalization<S> = Pin<Box<dyn Future<Output = (S, Result<(), ServingError>)> + Send + 'static>>;
54type Prepare<C> = Box<dyn Fn(Vec<u8>, bool) -> Result<Box<dyn Prepared<C>>, ServingError> + Send + Sync>;
55type Install<H, C> = fn(&mut WireTable<C>, Arc<H>) -> Result<(), ServingError>;
56
57#[derive(Debug, Serialize, Deserialize)]
60#[serde(deny_unknown_fields)]
61pub struct WireChildCall {
62 pub context: [u8; 32],
63
64 #[serde(default, skip_serializing_if = "Option::is_none")]
65 pub generation_context: Option<[u8; 32]>,
66
67 #[serde(default, skip_serializing_if = "Vec::is_empty")]
68 pub values: Vec<super::CallValue>,
69
70 pub operation: String,
71 pub payload: Vec<u8>,
72
73 #[serde(default)]
76 pub submit: bool,
77}
78
79#[derive(Debug, Serialize, Deserialize)]
82#[serde(deny_unknown_fields)]
83pub struct WireChildControl {
84 pub context: [u8; 32],
85 pub instance: u64,
86 pub action: WireChildAction,
87}
88
89pub struct WireTable<C> {
90 handlers: BTreeMap<String, Handler<C>>,
91 prepared: BTreeMap<u64, Arc<Slot<C>>>,
92 capacity: NonZeroUsize,
93 closed: bool,
94 ordinary_closed: bool,
95
96 #[cfg(feature = "streaming")]
97 stream_limits: Option<WireStreamLimits>,
98}
99
100struct Slot<C> {
101 lifecycle: bool,
102 resident: bool,
103
104 #[cfg(feature = "streaming")]
105 streams: Option<WireStreams>,
106
107 state: Mutex<SlotState<C>>,
108}
109
110struct SlotState<C> {
111 prepared: Option<Box<dyn Prepared<C>>>,
112 finished: bool,
113 waiters: Vec<Weak<Mutex<Option<Waker>>>>,
114}
115
116struct Loan<C> {
117 slot: Arc<Slot<C>>,
118 prepared: Option<Box<dyn Prepared<C>>>,
119 finished: bool,
120}
121
122struct Handler<C> {
123 lifecycle: bool,
124 builtin: bool,
127 resident: bool,
130 definition: Definition,
131 contract: Option<Contract>,
132 prepare: Prepare<C>,
133}
134
135pub struct Serves<H, C>(PhantomData<fn() -> (H, C)>);
136
137pub struct WireBinding<H, C> {
138 install: Install<H, C>,
139}
140
141#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
147#[serde(rename_all = "snake_case")]
148pub enum WireChildAction {
149 Join,
150 Status,
151 Cancel,
152 Release,
153 Detach,
154}
155
156#[derive(Debug)]
157pub enum WireChild {
158 Call(WireChildCall),
159 Control(WireChildControl),
160}
161
162#[derive(Debug, Serialize, Deserialize)]
163#[serde(tag = "phase", rename_all = "snake_case", deny_unknown_fields)]
164pub enum WireCommand {
165 Prepare { invocation: u64, operation: String, payload: Vec<u8> },
166 Initialize { invocation: u64, context: [u8; 32] },
167 Attempt { invocation: u64, context: [u8; 32], values: Vec<super::CallValue> },
168 Finalize { invocation: u64 },
169 StreamAttempt { invocation: u64, epoch: u64, context: [u8; 32], values: Vec<super::CallValue> },
170 StreamSend { invocation: u64, epoch: u64, payload: Vec<u8> },
171 StreamFinish { invocation: u64, epoch: u64 },
172 StreamReceive { invocation: u64, epoch: u64 },
173 PrepareGrpc { invocation: u64, operation: String, payload: Vec<u8> },
174}
175
176#[derive(Debug, Serialize, Deserialize)]
177#[serde(tag = "status", rename_all = "snake_case", deny_unknown_fields)]
178pub enum WireAnswer {
179 Stream { epoch: u64, transferred: bool, payload: Option<Vec<u8>> },
180 Ready { payload: Vec<u8> },
181 Failed { failure: crate::Failure },
182}
183
184#[derive(Debug, thiserror::Error)]
185pub enum ServingError {
186 #[error("carrier invocation does not support stream commands")]
187 StreamUnsupported,
188
189 #[cfg(feature = "streaming")]
190 #[error("streaming catalog requires explicit provider stream limits")]
191 StreamLimits,
192
193 #[cfg(feature = "streaming")]
194 #[error("carrier stream failed: {0}")]
195 Stream(#[source] super::streaming::Error),
196
197 #[cfg(feature = "streaming")]
198 #[error("carrier stream direction already has an outstanding request")]
199 StreamBusy,
200
201 #[cfg(feature = "streaming")]
202 #[error("carrier stream direction or attempt is not available")]
203 StreamPhase,
204
205 #[error(transparent)]
206 Lifecycle(#[from] crate::operations::lifecycle::Error),
207
208 #[error(transparent)]
209 Contract(#[from] ContractError),
210
211 #[error(transparent)]
212 Declaration(#[from] crate::Error),
213
214 #[error("operation `{operation}` has no bound carrier handler")]
215 Unknown { operation: String },
216
217 #[error("operation `{operation}` requires streaming endpoints unsupported by this carrier binding")]
218 Streaming { operation: String },
219
220 #[error("carrier invocation `{invocation}` is already prepared")]
221 Duplicate { invocation: u64 },
222
223 #[error("carrier invocation `{invocation}` has not been prepared")]
224 Missing { invocation: u64 },
225
226 #[error("carrier operation has not completed initialization")]
227 Uninitialized,
228
229 #[error("carrier operation initialization already started and cannot be replayed")]
230 InitializationStarted,
231
232 #[error("carrier invocation capacity is exhausted")]
233 Capacity,
234
235 #[error("carrier ordinary invocations have not finished settlement")]
236 Unsettled,
237
238 #[error("carrier operation admission is closing")]
239 Closing,
240
241 #[error("carrier handler definitions differ from the selected operation catalog")]
242 Catalog,
243
244 #[error("operation payload codec failed")]
245 Codec(#[source] crate::MessageError),
246
247 #[error("carrier handler panicked")]
248 Panicked,
249
250 #[error(transparent)]
252 Handler(crate::Failure),
253}
254
255trait Prepared<C>: Send {
258 #[cfg(feature = "streaming")]
259 fn streams(&self) -> Option<WireStreams> {
260 None
261 }
262
263 fn grant(&self) -> Option<crate::plugin::Grant> {
265 None
266 }
267 fn initialize<'a>(&'a mut self, context: &'a C) -> Finished<'a>;
268 fn attempt<'a>(&'a mut self, context: &'a C) -> Answer<'a>;
269 fn finalize(&mut self) -> Finished<'_>;
270}
271
272impl<C: Send + Sync + 'static> WireTable<C> {
275 pub fn new(capacity: NonZeroUsize) -> Self {
276 Self {
277 handlers: BTreeMap::new(),
278 prepared: BTreeMap::new(),
279 capacity,
280 closed: false,
281 ordinary_closed: false,
282 #[cfg(feature = "streaming")]
283 stream_limits: None,
284 }
285 }
286
287 pub fn of<T, R>(resources: Arc<R>, capacity: NonZeroUsize) -> Result<Self, ServingError>
288 where
289 T: Catalog<AuthoredDeclarations> + Catalog<Serves<R, C>>,
290 R: Send + Sync + 'static,
291 {
292 Self::project::<T, R>(Self::new(capacity), resources)
293 }
294
295 fn project<T, R>(mut table: Self, resources: Arc<R>) -> Result<Self, ServingError>
296 where
297 T: Catalog<AuthoredDeclarations> + Catalog<Serves<R, C>>,
298 R: Send + Sync + 'static,
299 {
300 let definitions = AuthoredDeclarations::of::<T>()?;
301 <T as Catalog<Serves<R, C>>>::ENTRIES.try_for_each(|binding| (binding.install)(&mut table, Arc::clone(&resources)))?;
302 table.validate(&definitions)?;
303 Ok(table)
304 }
305
306 pub fn bind_operations<T, R>(&mut self, resources: Arc<R>) -> Result<(), ServingError>
307 where
308 T: Catalog<AuthoredDeclarations> + Catalog<Serves<R, C>>,
309 R: Send + Sync + 'static,
310 {
311 if self.closed || self.ordinary_closed {
312 return Err(ServingError::Closing);
313 }
314 let staged = Self::of::<T, R>(resources, self.capacity)?;
315 self.extend(staged)
316 }
317
318 #[cfg(feature = "streaming")]
319 pub fn bind_streaming_operations<T, R>(&mut self, resources: Arc<R>, limits: WireStreamLimits) -> Result<(), ServingError>
320 where
321 T: Catalog<AuthoredDeclarations> + Catalog<Serves<R, C>>,
322 R: Send + Sync + 'static,
323 {
324 if self.closed || self.ordinary_closed {
325 return Err(ServingError::Closing);
326 }
327 limits.validate()?;
328 let mut staged = Self::new(self.capacity);
329 staged.stream_limits = Some(limits);
330 let staged = Self::project::<T, R>(staged, resources)?;
331 self.extend(staged)
332 }
333
334 fn extend(&mut self, mut staged: Self) -> Result<(), ServingError> {
335 for id in staged.handlers.keys() {
336 if self.handlers.contains_key(id) {
337 return Err(crate::Error::DuplicateOperation { id: id.clone() }.into());
338 }
339 }
340 self.handlers.append(&mut staged.handlers);
341 Ok(())
342 }
343
344 pub fn definitions(&self) -> Vec<Definition> {
345 self.handlers.values().filter(|handler| !handler.builtin).map(|handler| handler.definition.clone()).collect()
346 }
347
348 pub fn validate(&self, definitions: &[Definition]) -> Result<(), ServingError> {
349 if definitions.len() != self.handlers.values().filter(|handler| !handler.builtin).count() {
350 return Err(ServingError::Catalog);
351 }
352 for definition in definitions {
353 if self.handlers.get(definition.id.as_str()).is_none_or(|bound| bound.builtin || bound.definition != *definition) {
354 return Err(ServingError::Catalog);
355 }
356 }
357 let unique: std::collections::BTreeSet<_> = definitions.iter().map(|definition| &definition.id).collect();
358 if unique.len() != definitions.len() {
359 return Err(ServingError::Catalog);
360 }
361 Ok(())
362 }
363
364 pub fn validate_contracts(&self, contracts: &[Contract]) -> Result<(), ServingError> {
365 if contracts.len() != self.handlers.values().filter(|handler| !handler.builtin).count() {
366 return Err(ServingError::Catalog);
367 }
368 let mut unique = std::collections::BTreeSet::new();
369 for contract in contracts {
370 let id = &contract.operation().id;
371 if !unique.insert(id)
372 || self.handlers.get(id.as_str()).is_none_or(|bound| bound.builtin || bound.contract.as_ref() != Some(contract))
373 {
374 return Err(ServingError::Catalog);
375 }
376 }
377 Ok(())
378 }
379
380 pub fn prepare(&mut self, invocation: u64, operation: &str, payload: Vec<u8>) -> Result<Vec<u8>, ServingError> {
382 self.prepare_codec(invocation, operation, payload, false)
383 }
384
385 fn prepare_codec(&mut self, invocation: u64, operation: &str, payload: Vec<u8>, grpc: bool) -> Result<Vec<u8>, ServingError> {
386 if self.closed {
387 return Err(ServingError::Closing);
388 }
389 self.prepared.retain(|_, slot| !slot.is_finished());
390 if self.prepared.contains_key(&invocation) {
391 return Err(ServingError::Duplicate { invocation });
392 }
393 let handler = self.handlers.get(operation).ok_or_else(|| ServingError::Unknown { operation: operation.to_owned() })?;
394 if self.ordinary_closed && !handler.lifecycle {
395 return Err(ServingError::Closing);
396 }
397 let occupied = self.prepared.values().filter(|slot| slot.lifecycle == handler.lifecycle && !slot.resident).count();
398 let capacity = if handler.lifecycle { 1 } else { self.capacity.get() };
401 if occupied >= capacity && !handler.resident {
402 return Err(ServingError::Capacity);
403 }
404 let prepared = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| (handler.prepare)(payload, grpc)))
405 .map_err(|_| ServingError::Panicked)??;
406 let answer = encode_prepared_grant(prepared.grant().as_ref());
407 let slot = Slot {
408 lifecycle: handler.lifecycle,
409 resident: handler.resident,
410 #[cfg(feature = "streaming")]
411 streams: prepared.streams(),
412 state: Mutex::new(SlotState { prepared: Some(prepared), finished: false, waiters: Vec::new() }),
413 };
414 self.prepared.insert(invocation, Arc::new(slot));
415 Ok(answer)
416 }
417
418 #[cfg(feature = "streaming")]
419 pub fn streams(&self, invocation: u64) -> Result<WireStreams, ServingError> {
420 let slot = self.prepared.get(&invocation).ok_or(ServingError::Missing { invocation })?;
421 if self.closed || (self.ordinary_closed && !slot.lifecycle) || slot.is_finished() {
422 return Err(ServingError::Closing);
423 }
424 slot.streams.clone().ok_or(ServingError::StreamPhase)
425 }
426
427 pub async fn initialize(&mut self, invocation: u64, context: &C) -> Result<(), ServingError> {
428 if self.closed {
429 return Err(ServingError::Closing);
430 }
431 let slot = self.prepared.get(&invocation).ok_or(ServingError::Missing { invocation })?;
432 if self.ordinary_closed && !slot.lifecycle {
433 return Err(ServingError::Closing);
434 }
435 slot.initialize(invocation, context).await
436 }
437
438 pub async fn attempt(&mut self, invocation: u64, context: &C) -> Result<Vec<u8>, ServingError> {
439 if self.closed {
440 return Err(ServingError::Closing);
441 }
442 let slot = self.prepared.get(&invocation).ok_or(ServingError::Missing { invocation })?;
443 if self.ordinary_closed && !slot.lifecycle {
444 return Err(ServingError::Closing);
445 }
446 slot.attempt(invocation, context, None).await
447 }
448
449 pub async fn finalize(&mut self, invocation: u64) -> Result<(), ServingError> {
450 if let Some(slot) = self.prepared.get(&invocation) {
451 slot.finalize().await?;
452 }
453 self.prepared.remove(&invocation);
454 Ok(())
455 }
456
457 fn traffic(&self, command: WireCommand) -> Pin<Box<dyn Future<Output = WireAnswer> + Send + 'static>> {
458 #[cfg(not(feature = "streaming"))]
459 {
460 let _ = command;
461 Box::pin(async { wire_answer(Err(ServingError::StreamUnsupported)) })
462 }
463 #[cfg(feature = "streaming")]
464 {
465 let invocation = match &command {
466 WireCommand::StreamSend { invocation, .. }
467 | WireCommand::StreamFinish { invocation, .. }
468 | WireCommand::StreamReceive { invocation, .. } => *invocation,
469 _ => unreachable!("only stream traffic bypasses the phase loan"),
470 };
471 let streams = self.streams(invocation);
472 Box::pin(async move {
473 let streams = match streams {
474 Ok(streams) => streams,
475 Err(error) => return wire_answer(Err(error)),
476 };
477 match command {
478 WireCommand::StreamSend { epoch, payload, .. } => {
479 wire_answer(guarded(async { streams.send(epoch, &payload).await.map(|()| Vec::new()) }).await)
480 }
481 WireCommand::StreamFinish { epoch, .. } => wire_answer(streams.finish_input(epoch).map(|()| Vec::new())),
482 WireCommand::StreamReceive { epoch, .. } => match guarded(streams.receive(epoch)).await {
483 Ok(payload) => WireAnswer::Stream { epoch, transferred: streams.transferred(), payload },
484 Err(error) => wire_answer(Err(error)),
485 },
486 _ => unreachable!("only stream traffic bypasses the phase loan"),
487 }
488 })
489 }
490 }
491
492 pub fn begin(&mut self, command: WireCommand, context: Arc<C>) -> Pin<Box<dyn Future<Output = WireAnswer> + Send + 'static>> {
493 if command.is_stream_traffic() {
494 return self.traffic(command);
495 }
496 let slot = match &command {
497 WireCommand::Initialize { invocation, .. }
498 | WireCommand::Attempt { invocation, .. }
499 | WireCommand::StreamAttempt { invocation, .. }
500 | WireCommand::Finalize { invocation } => self.prepared.get(invocation).cloned(),
501 WireCommand::Prepare { .. } | WireCommand::PrepareGrpc { .. } => None,
502 WireCommand::StreamSend { .. } | WireCommand::StreamFinish { .. } | WireCommand::StreamReceive { .. } => {
503 unreachable!("stream traffic already dispatched")
504 }
505 };
506 let command = match command {
507 WireCommand::PrepareGrpc { invocation, operation, payload } => {
508 let result = self.prepare_codec(invocation, &operation, payload, true);
509 return Box::pin(async move { wire_answer(result) });
510 }
511 WireCommand::Prepare { invocation, operation, payload } => {
512 let result = self.prepare(invocation, &operation, payload);
513 return Box::pin(async move { wire_answer(result) });
514 }
515 command => command,
516 };
517 let refused = self.closed || (self.ordinary_closed && slot.as_ref().is_some_and(|slot| !slot.lifecycle));
518 if refused && matches!(command, WireCommand::Initialize { .. } | WireCommand::Attempt { .. } | WireCommand::StreamAttempt { .. }) {
519 return Box::pin(async { wire_answer(Err(ServingError::Closing)) });
520 }
521 Box::pin(async move {
522 let result = match command {
523 WireCommand::Initialize { invocation, .. } => match slot {
524 Some(slot) => slot.initialize(invocation, &context).await.map(|()| Vec::new()),
525 None => Err(ServingError::Missing { invocation }),
526 },
527 WireCommand::Attempt { invocation, .. } => match slot {
528 Some(slot) => slot.attempt(invocation, &context, None).await,
529 None => Err(ServingError::Missing { invocation }),
530 },
531 WireCommand::StreamAttempt { invocation, epoch, .. } => match slot {
532 Some(slot) => slot.attempt(invocation, &context, Some(epoch)).await,
533 None => Err(ServingError::Missing { invocation }),
534 },
535 WireCommand::StreamSend { .. } | WireCommand::StreamFinish { .. } | WireCommand::StreamReceive { .. } => {
536 unreachable!("stream traffic already dispatched")
537 }
538 WireCommand::Finalize { .. } => match slot {
539 Some(slot) => slot.finalize().await.map(|()| Vec::new()),
540 None => Ok(Vec::new()),
541 },
542 WireCommand::Prepare { .. } | WireCommand::PrepareGrpc { .. } => {
543 unreachable!("preparation is synchronous")
544 }
545 };
546 wire_answer(result)
547 })
548 }
549
550 pub fn close_ordinary(&mut self) -> Pin<Box<dyn Future<Output = Result<(), ServingError>> + Send + 'static>> {
551 self.ordinary_closed = true;
552 let slots: Vec<_> = self.prepared.values().filter(|slot| !slot.lifecycle).cloned().collect();
553 #[cfg(feature = "streaming")]
554 for slot in &slots {
555 if let Some(streams) = &slot.streams {
556 streams.close();
557 }
558 }
559 Box::pin(async move {
560 for slot in slots {
561 slot.finalize().await?;
562 }
563 Ok(())
564 })
565 }
566
567 pub fn release_ordinary(&mut self) -> Result<impl Send + use<C>, ServingError> {
568 if !self.ordinary_closed || self.prepared.values().any(|slot| !slot.lifecycle && !slot.is_finished()) {
569 return Err(ServingError::Unsettled);
570 }
571 let retired_slots = self.prepared.extract_if(.., |_, slot| !slot.lifecycle).collect::<Vec<_>>();
573 let retired_handlers = self.handlers.extract_if(.., |_, handler| !handler.lifecycle).collect::<Vec<_>>();
574 Ok((retired_slots, retired_handlers))
575 }
576
577 pub async fn settle_ordinary(&mut self) -> Result<(), ServingError> {
578 self.close_ordinary().await?;
579 let retired = self.release_ordinary()?;
580 drop(retired);
581 Ok(())
582 }
583
584 pub fn close(&mut self) -> Pin<Box<dyn Future<Output = Result<(), ServingError>> + Send + 'static>> {
585 self.closed = true;
586 let slots: Vec<_> = self.prepared.values().cloned().collect();
587 #[cfg(feature = "streaming")]
588 for slot in &slots {
589 if let Some(streams) = &slot.streams {
590 streams.close();
591 }
592 }
593 Box::pin(async move {
594 for slot in slots {
595 slot.finalize().await?;
596 }
597 Ok(())
598 })
599 }
600
601 pub fn release(&mut self) -> Result<impl Send + use<C>, ServingError> {
602 if !self.closed || self.prepared.values().any(|slot| !slot.is_finished()) {
603 return Err(ServingError::Unsettled);
604 }
605 Ok((std::mem::take(&mut self.prepared), std::mem::take(&mut self.handlers)))
606 }
607
608 pub async fn settle(&mut self) -> Result<(), ServingError> {
609 self.close().await?;
610 let retired = self.release()?;
611 drop(retired);
612 Ok(())
613 }
614
615 pub fn is_settled(&self) -> bool {
616 self.closed && self.prepared.values().all(|slot| slot.is_finished())
617 }
618
619 pub fn is_closed(&self) -> bool {
620 self.closed
621 }
622
623 pub async fn answer(&mut self, command: WireCommand, context: &C) -> WireAnswer {
624 if command.is_stream_traffic() {
625 return self.traffic(command).await;
626 }
627 if let WireCommand::StreamAttempt { invocation, epoch, .. } = command {
628 if self.closed || (self.ordinary_closed && self.prepared.get(&invocation).is_some_and(|slot| !slot.lifecycle)) {
629 return wire_answer(Err(ServingError::Closing));
630 }
631 let Some(slot) = self.prepared.get(&invocation) else {
632 return wire_answer(Err(ServingError::Missing { invocation }));
633 };
634 return wire_answer(slot.attempt(invocation, context, Some(epoch)).await);
635 }
636 let result = match command {
637 WireCommand::PrepareGrpc { invocation, operation, payload } => self.prepare_codec(invocation, &operation, payload, true),
638 WireCommand::Prepare { invocation, operation, payload } => self.prepare(invocation, &operation, payload),
639 WireCommand::Initialize { invocation, .. } => self.initialize(invocation, context).await.map(|()| Vec::new()),
640 WireCommand::Attempt { invocation, .. } => self.attempt(invocation, context).await,
641 WireCommand::StreamAttempt { .. }
642 | WireCommand::StreamSend { .. }
643 | WireCommand::StreamFinish { .. }
644 | WireCommand::StreamReceive { .. } => {
645 unreachable!("stream command already dispatched")
646 }
647 WireCommand::Finalize { invocation } => self.finalize(invocation).await.map(|()| Vec::new()),
648 };
649 wire_answer(result)
650 }
651}
652
653impl<C> Slot<C> {
654 fn is_finished(&self) -> bool {
655 self.state.lock().expect("invocation state lock").finished
656 }
657
658 async fn borrow(self: &Arc<Self>) -> Option<Loan<C>> {
659 let waiter = Arc::new(Mutex::new(None));
660 std::future::poll_fn(|context| {
661 let mut state = self.state.lock().expect("invocation state lock");
662 if state.finished {
663 return Poll::Ready(None);
664 }
665 if let Some(prepared) = state.prepared.take() {
666 return Poll::Ready(Some(Loan { slot: Arc::clone(self), prepared: Some(prepared), finished: false }));
667 }
668 *waiter.lock().expect("invocation waiter lock") = Some(context.waker().clone());
669 state.waiters.retain(|entry| entry.strong_count() != 0);
670 if !state.waiters.iter().any(|entry| entry.ptr_eq(&Arc::downgrade(&waiter))) {
671 state.waiters.push(Arc::downgrade(&waiter));
672 }
673 Poll::Pending
674 })
675 .await
676 }
677}
678
679impl<C: Send + Sync + 'static> Slot<C> {
680 async fn initialize(self: &Arc<Self>, invocation: u64, context: &C) -> Result<(), ServingError> {
681 let mut loan = self.borrow().await.ok_or(ServingError::Missing { invocation })?;
682 loan.prepared.as_mut().expect("loaned invocation state").initialize(context).await
683 }
684
685 async fn attempt(self: &Arc<Self>, invocation: u64, context: &C, epoch: Option<u64>) -> Result<Vec<u8>, ServingError> {
686 let mut loan = self.borrow().await.ok_or(ServingError::Missing { invocation })?;
687 #[cfg(feature = "streaming")]
688 let attempt = match (&self.streams, epoch) {
689 (Some(streams), Some(epoch)) => Some(streams.start(epoch)?),
690 (None, None) => None,
691 _ => return Err(ServingError::StreamUnsupported),
692 };
693 #[cfg(not(feature = "streaming"))]
694 if epoch.is_some() {
695 return Err(ServingError::StreamUnsupported);
696 }
697 let result = loan.prepared.as_mut().expect("loaned invocation state").attempt(context).await;
698 #[cfg(feature = "streaming")]
699 if let Some(attempt) = attempt {
700 attempt.end();
701 }
702 result
703 }
704
705 async fn finalize(self: &Arc<Self>) -> Result<(), ServingError> {
706 #[cfg(feature = "streaming")]
707 if let Some(streams) = &self.streams {
708 streams.close();
709 }
710 let Some(mut loan) = self.borrow().await else {
711 return Ok(());
712 };
713 loan.prepared.as_mut().expect("loaned invocation state").finalize().await?;
714 loan.finished = true;
716 let prepared = loan.prepared.take();
717 drop(prepared);
718 Ok(())
719 }
720}
721
722impl<C> Drop for Loan<C> {
723 fn drop(&mut self) {
724 let waiters = {
725 let mut state = self.slot.state.lock().expect("invocation state lock");
726 state.prepared = self.prepared.take();
727 state.finished = self.finished;
728 std::mem::take(&mut state.waiters)
729 };
730 for waiter in waiters {
731 if let Some(waiter) = waiter.upgrade() {
732 let wake = waiter.lock().expect("invocation waiter lock").take();
733 if let Some(wake) = wake {
734 wake.wake();
735 }
736 }
737 }
738 }
739}
740
741impl WireCommand {
742 pub const LIMIT: usize = codec::LIMIT;
743 fn is_stream_traffic(&self) -> bool {
744 matches!(self, Self::StreamSend { .. } | Self::StreamFinish { .. } | Self::StreamReceive { .. })
745 }
746}
747
748impl ServingError {
749 pub fn classification(&self) -> FailureKind {
750 match self {
751 Self::Handler(failure) => failure.code(),
752 Self::Panicked => FailureKind::Ambiguous,
753 Self::Codec(_) | Self::Declaration(_) | Self::Lifecycle(_) | Self::Contract(_) | Self::Catalog | Self::Streaming { .. } => {
754 FailureKind::Invalid
755 }
756 _ => FailureKind::Permanent,
757 }
758 }
759}
760
761impl<C: Send + Sync + 'static, H: Send + Sync + 'static> Visitor for Serves<H, C> {
762 type Entry = WireBinding<H, C>;
763}
764
765#[cfg(not(feature = "streaming"))]
766impl<T, R, C> Member<T> for Serves<R, C>
767where
768 C: Send + Sync + 'static,
769 R: Send + Sync + 'static,
770 T: for<'a> Operation<Resources = R, Context<'a> = &'a C, Endpoints = ()>,
771{
772 const ENTRY: WireBinding<R, C> = WireBinding { install: WireTable::<C>::bind_operation::<T> };
773}
774
775#[cfg(feature = "streaming")]
776impl<T, R, C> Member<T> for Serves<R, C>
777where
778 C: Send + Sync + 'static,
779 R: Send + Sync + 'static,
780 T: for<'a> Operation<Resources = R, Context<'a> = &'a C>,
781 T::Endpoints: WireEndpoints,
782{
783 const ENTRY: WireBinding<R, C> = WireBinding { install: WireTable::<C>::bind_catalog_operation::<T> };
784}
785
786pub fn encode_prepared_grant(grant: Option<&crate::plugin::Grant>) -> Vec<u8> {
790 grant.map_or_else(Vec::new, |grant| serde_json::to_vec(grant).expect("a grant serializes to JSON"))
791}
792
793pub fn decode_prepared_grant(payload: &[u8]) -> Result<Option<crate::plugin::Grant>, serde_json::Error> {
794 if payload.is_empty() {
795 return Ok(None);
796 }
797 serde_json::from_slice(payload).map(Some)
798}
799
800fn wire_answer(result: Result<Vec<u8>, ServingError>) -> WireAnswer {
803 match result {
804 Ok(payload) => WireAnswer::Ready { payload },
805 Err(ServingError::Handler(failure)) => WireAnswer::Failed { failure },
806 Err(error) => {
807 WireAnswer::Failed { failure: crate::Failure::originate(error.classification(), &error, crate::failure::Origin::Plugin) }
808 }
809 }
810}
811
812async fn guarded<T>(future: impl Future<Output = Result<T, ServingError>>) -> Result<T, ServingError> {
813 let mut future = std::pin::pin!(future);
814 std::future::poll_fn(|context| match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| future.as_mut().poll(context))) {
815 Ok(result) => result,
816 Err(_) => std::task::Poll::Ready(Err(ServingError::Panicked)),
817 })
818 .await
819}
820
821