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
use ;
pub use ;
use ;
use ;
/// # Ditto Data Streams
/// Ditto Data Streams allow you to send datagrams accross a Ditto mesh.
///
/// This structure is the core accessor to the Ditto Data Streams, which may remind you of some TCP
/// APIs you've seen before (except this one can work without an IP connection too!).
///
/// While exploring the API from [`Bus::bind_topic`], [`Bus::connect`] and the examples their docs
/// contain is probably the easiest way to approach it, there are a few subjects that are global to
/// the API: giving them a look could be helpful.
///
/// The entire API is built around the builder pattern: a rather convenient way to explore it is to
/// simply let your code completion guide you around it.
///
/// ## Topics
/// Much like TCP and UDP have ports, Ditto Data Streams have `topic`s: instead of integers, you can
/// name your ports after anything you like!
///
/// The equivalent of binding a socket is to use [`Bus::bind_topic`], to which you'll provide a
/// topic (or name).
///
/// Any attempt to [`Bus::connect`] to your peer will have to specify on which topic the connection
/// should be made, the connection appearing as a new [`Stream`] for your [`Acceptor`].
///
/// ## [`Payload`] and [`IntoPayload`]
/// To carry data around, the Ditto Data Streams API uses [`Payload`]s, also known as
/// [`safer_ffi::bytes::Bytes`]: much like the wider known [`bytes::Bytes`](https://docs.rs/bytes/latest/bytes/struct.Bytes.html), it's a cheaply cloneable and sliceable chunk of contiguous memory... But it does have a few low-level tricks up its sleeve to be even more efficient.
///
/// And while it's easy enough to construct it from common owned slice types, [`IntoPayload`] is a
/// very friendly option to make serialization less verbose, yet explicit and flexible.
///
/// ## [`IntoChannel`]: We promise, it's not as scary as it looks
/// In this API, anytime we think you may want the choice between closures and channels to handle
/// certain events you could subscribe to, we've used the following signature pattern:
/// ```
/// # use dittolive_ditto::experimental::bus::{Channel, IntoChannel};
/// # struct Event; struct Subscriber<T>(T);
/// fn subscribe<OverloadId, Handler>(handler: Handler) -> Subscriber<Handler::Receiver>
/// where
/// Handler: IntoChannel<OverloadId, Event>,
/// Handler::Sender: Channel<OverloadId, Event>,
/// # {unimplemented!()}
/// ```
///
/// While this looks imposing, it's actually a very magic formula: it allows you to write little to
/// no boiler plate in 99% of cases, while giving you the flexibility to use any handler you please
/// and allowing us to find every trick possible to minimize the overhead of calling your handler.
///
/// In most cases, all you need to do to use such an API is to call it with
/// - a closure: `let handle = subscribe(|e: Event| println!("{e}"));` (you may want to keep
/// `handle` around, as dropping it will cancel that subscription).
/// - any channel implementation you like: `let handle = subscribe(std::sync::mpsc::channel())`
/// (here, `handle` will deref to the receiver half of the channel, letting you call
/// `handle.recv()` whenever you like).
///
/// `OverloadId` is actually a charm that tricks the compiler into letting you bypass the orphan
/// rule<sup>[(1)](https://doc.rust-lang.org/book/ch10-02-traits.html#:~:text=orphan%20rule)[(2)](https://github.com/Ixrec/rust-orphan-rules)</sub>, and is described in more detail in [`IntoChannel`]'s documentation, which also contains an
/// example of how to use that trick to add support for [`flume`](https://crates.io/crates/flume)'s excellent channel implementation
/// to Ditto's Data Streams API.
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;