rig_core/wire/document.rs
1//! The reply document a reply's events rebuild. Every [`Wire`](super::Wire)
2//! names one [`Reassemble`] type. The driver hands it each event its decoder
3//! classifies as known, of a reply whose transport reported no whole
4//! document, before the decoder decodes the event, and records what it
5//! finishes with as the reply's `raw`. A
6//! completion decoder cannot write `raw` itself, so a streamed reply's
7//! `raw` has one owner per wire. A wire names a reassembler only for an
8//! operation it [`Serves`], and [`Unreassembled`], which records nothing,
9//! serves no completion.
10//!
11//! ```
12//! use rig_core::wire::document::{Reassemble, Unreassembled};
13//!
14//! let mut document = Unreassembled;
15//! Reassemble::<String>::absorb(&mut document, &"event".to_owned());
16//! assert!(Reassemble::<String>::finish(document).is_null());
17//! ```
18
19use crate::wasm_compat::WasmCompatSend;
20use crate::wire::{Free, Operation};
21
22/// Rebuilds one reply's provider document from its decoder's events.
23///
24/// A fresh value per reply. `absorb` sees every known event of the reply,
25/// in arrival order, before the decoder decodes it; unknown and corrupt
26/// frames never reach it. `finish` runs once, when the reply ends, fails or
27/// is cut short; a reply that did not end yields the document so far.
28pub trait Reassemble<Event>: Default + WasmCompatSend + 'static {
29 /// Absorb one known event of the reply.
30 fn absorb(&mut self, event: &Event);
31
32 /// The document the absorbed events add up to. `Null` records none.
33 fn finish(self) -> serde_json::Value;
34}
35
36/// Keep `value` at `key` of a document being rebuilt: a non-null value
37/// replaces, and `null` only fills an absent field. A value equal to the
38/// one held, as most fields restate in every event, is not copied again.
39pub(crate) fn keep(
40 map: &mut serde_json::Map<String, serde_json::Value>,
41 key: &str,
42 value: &serde_json::Value,
43) {
44 match map.get_mut(key) {
45 Some(held) if !value.is_null() && held != value => *held = value.clone(),
46 Some(_) => {}
47 None => {
48 map.insert(key.to_owned(), value.clone());
49 }
50 }
51}
52
53/// The value at `key`, made an empty `kind` (a list or an object) when it is
54/// absent or of another type.
55pub(crate) fn slot<'a, T: Default>(
56 map: &'a mut serde_json::Map<String, serde_json::Value>,
57 key: &str,
58 kind: fn(T) -> serde_json::Value,
59) -> &'a mut serde_json::Value {
60 let slot = map.entry(key).or_insert(serde_json::Value::Null);
61 if std::mem::discriminant(slot) != std::mem::discriminant(&kind(T::default())) {
62 *slot = kind(T::default());
63 }
64 slot
65}
66
67/// The reassembler of a wire whose decoders record `raw` themselves, which
68/// only an operation with [`Free`] events can: it records
69/// nothing.
70#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
71pub struct Unreassembled;
72
73impl<Event> Reassemble<Event> for Unreassembled {
74 fn absorb(&mut self, _event: &Event) {}
75
76 fn finish(self) -> serde_json::Value {
77 serde_json::Value::Null
78 }
79}
80
81/// The operations whose wires may name a reassembler: a wire's
82/// [`Reassembler`](super::Wire::Reassembler) must serve its operation.
83///
84/// [`Unreassembled`] serves only an operation whose decoders record `raw`
85/// themselves ([`Free`] events), so a completion wire cannot name it and
86/// must name a reassembler that rebuilds its document:
87///
88/// ```compile_fail,E0271
89/// use rig_core::operation::Completion;
90/// use rig_core::wire::document::{Serves, Unreassembled};
91///
92/// fn completion_reassembler<R: Serves<Completion>>() {}
93/// completion_reassembler::<Unreassembled>();
94/// ```
95pub trait Serves<Op: Operation> {}
96
97impl<Op: Operation<Emit = Free>> Serves<Op> for Unreassembled {}
98
99/// The document `frames` rebuild: each frame `decoder` classifies as known
100/// is handed to `reassembler`, as the driver hands it.
101#[cfg(test)]
102pub(crate) fn rebuild<'id, Op, F, D, R>(
103 decoder: &D,
104 mut reassembler: R,
105 frames: impl IntoIterator<Item = F>,
106) -> serde_json::Value
107where
108 Op: Operation,
109 D: super::Decoder<'id, Op, F>,
110 R: Reassemble<D::Event>,
111{
112 for frame in frames {
113 if let super::WireEvent::Known(event) = decoder.classify(frame) {
114 reassembler.absorb(&event);
115 }
116 }
117 reassembler.finish()
118}