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
//! Streams: server output over time that isn't a query over rows, such as a
//! job's progress, a model's tokens, or a log tail.
//!
//! ```ignore
//! /// A model's answer, a token at a time.
//! #[rpc::stream]
//! pub async fn answer(cx: &rpc::QueryCx, prompt: String) -> rpc::Result<impl Stream<Item = String>> {
//! Ok(my_llm::tokens(prompt))
//! }
//!
//! // Any client:
//! let answer = rpc::use_stream(move || Answer { prompt: prompt.get() });
//! let text = move || answer.items().get().concat();
//! ```
//!
//! A stream travels on the live connection, beside the app's queries, and
//! the server reads the next item only once the client has room for it, so
//! a slow phone never makes the server hold more than it asked for. It ends
//! as [`EndReason`](crate::live::EndReason) says: done, failed, or
//! interrupted by a reconnect. `#[rpc::stream(resumable)]` takes a `cursor`
//! argument, and its items say where they reached through [`Resumable`], so
//! the client opens it again from the last item it received.
//!
//! When the state could be a row, such as an import's progress, prefer a
//! live query: it survives reconnects and server restarts for free.
use Serialize;
use DeserializeOwned;
/// A stream's arguments, as one value: the struct `#[rpc::stream]`
/// generates from the function's arguments.
///
/// The struct exists on every target, so any client can open it with
/// [`use_stream`](crate::client::use_stream). Only a server build knows
/// how to run it.
/// An item of a resumable stream: where the stream reached with it.
///
/// A reconnecting client opens the stream again with its `cursor` argument
/// set to the last item's cursor, so the body carries on from there.
///
/// ```ignore
/// #[derive(Clone, Serialize, Deserialize)]
/// pub struct LogLine { pub offset: u64, pub text: String }
///
/// impl rpc::Resumable for LogLine {
/// type Cursor = u64;
/// fn cursor(&self) -> u64 { self.offset }
/// }
///
/// #[rpc::stream(resumable)]
/// pub async fn tail(cx: &rpc::QueryCx, file: String, cursor: Option<u64>) -> rpc::Result<impl Stream<Item = LogLine>> { … }
/// ```
/// Checks a stream's item type, where the macro names it.
pub const
/// Checks a resumable stream's `cursor` argument takes its items' cursor.
pub const