Skip to main content

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}