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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
//! Efficient and seamless cross-process communication, providing semantics similar to
//! [`std::thread::spawn`] and alike, both synchronously and asynchronously (via tokio or smol).
//!
//! This crate allows you to easily perform computations in another process without creating a
//! separate executable or parsing command line arguments manually. For example, the simplest
//! example, computing a sum of several numbers in a one-shot subprocess, looks like this:
//!
//! ```rust
//! #[crossmist::main]
//! fn main() {
//!     println!("5 + 7 = {}", add.run(vec![5, 7]).unwrap());
//! }
//!
//! #[crossmist::func]
//! fn add(nums: Vec<i32>) -> i32 {
//!     nums.into_iter().sum()
//! }
//! ```
//!
//! This crate also supports long-lived tasks with constant cross-process communication:
//!
//! ```rust
//! #[crossmist::main]
//! fn main() {
//!     let (mut ours, theirs) = crossmist::duplex().unwrap();
//!     add.spawn(theirs).expect("Failed to spawn child");
//!     for i in 1..=5 {
//!         for j in 1..=5 {
//!             println!("{i} + {j} = {}", ours.request(&vec![i, j]).unwrap());
//!         }
//!     }
//! }
//!
//! #[crossmist::func]
//! fn add(mut chan: crossmist::Duplex<i32, Vec<i32>>) {
//!     while let Some(nums) = chan.recv().unwrap() {
//!         chan.send(&nums.into_iter().sum());
//!     }
//! }
//! ```
//!
//!
//! # Passing objects
//!
//! Almost arbitrary objects can be passed between processes and across channels, including file
//! handles, sockets, and other channels.
//!
//! For numeric types, strings, vectors, hashmaps, other common containers, and files/sockets, the
//! [`Object`] trait is implemented automatically. For user-defined structures and enums, use
//! `#[derive(Object)]`. You may use generics, but make sure to add `: Object` constraint to stored
//! types:
//!
//! ```rust
//! use crossmist::Object;
//!
//! #[derive(Object)]
//! struct MyPair<T: Object, U: Object> {
//!     first: T,
//!     second: U,
//! }
//! ```
//!
//! Occasionally, e.g. for custom hash tables or externally defined types, you might have to
//! implement [`Object`] manually. Check out the documentation for [`Object`] for more information.
//!
//!
//! # Channels
//!
//! As the second example demonstrates, cross-process communication may be achieved not only via
//! arguments and return values, but via long-lived channels. Channels may be unidirectional (one
//! process has a [`Sender`] instance and another process has a connected [`Receiver`] instance) or
//! bidirectional (both processes have [`Duplex`] instances). Channels are typed: you don't just
//! send byte streams à la TCP, you send objects of a well-defined type implementing the [`Object`]
//! trait, making channels type-safe.
//!
//! Channels implement [`Object`]. This means that not only can you pass channels to subprocesses
//! as arguments (they wouldn't be useful otherwise), but you can pass channels across other
//! channels, just like you can pass files across channels.
//!
//! Channels are trusted. This means that if one side reads from [`Receiver`] and another side
//! writes garbage to the corresponding file descriptor instead of using [`Sender`], the receiver
//! side may crash and burn, potentially leading to arbitrary code execution.
//!
//! The communication protocol is not fixed and may not only change in minor versions, but be
//! architecture- or build-dependent. This is done to both ensure performance optimizations can be
//! implemented and to let us fix bugs quickly when they arise. As channels may only be used between
//! two processes started from the same executable file, this does not violate semver.
//!
//!
//! # Aborting computations
//!
//! If, at any point, you determine that you are no longer interested in the output of a process,
//! you can kill it:
//!
//! ```rust
//! #[crossmist::main]
//! fn main() {
//!     let mut child = long_computation.spawn().expect("Failed to spawn child");
//!     let kill_handle = child.get_kill_handle();
//!     std::thread::spawn(move || {
//!         // Wait, I don't need this, actually!
//!         std::thread::sleep(std::time::Duration::from_millis(500));
//!         kill_handle.kill();
//!     });
//!     // This will fail in 0.5 seconds:
//!     child.join().unwrap_err();
//! }
//!
//! #[crossmist::func]
//! fn long_computation() {
//!     loop {}
//! }
//! ```
//!
//!
//! # Features
//!
//! This crate provides the following features:
//! - `tokio`: enable [Tokio](https://tokio.rs) async runtime support.
//! - `smol`: enable [smol](https://crates.io/crates/smol) async runtime support.
//! - `nightly`: make use of nightly features. This enables crossmist to be more performant and
//! provide better API, but requires a nightly compiler to be used.

#![cfg_attr(
    feature = "nightly",
    feature(
        arbitrary_self_types,
        doc_cfg,
        doc_auto_cfg,
        fn_traits,
        never_type,
        tuple_trait,
        unboxed_closures,
    )
)]
#![deny(missing_debug_implementations)]

extern crate self as crossmist;

/// Enable a function to be used as an entrypoint of a child process, and turn it into an
/// [`Object`].
///
/// This macro applies to `fn` functions, including generic ones. It adds various methods for
/// spawning a child process from this function.
///
/// For a function declared as
///
/// ```ignore
/// #[func]
/// fn example(arg1: Type1, ...) -> Output;
/// ```
///
/// ...the methods are:
///
/// ```ignore
/// pub fn spawn(&self, arg1: Type1, ...) -> std::io::Result<crossmist::Child<Output>>;
/// pub fn run(&self, arg1: Type1, ...) -> std::io::Result<Output>;
/// ```
///
/// `spawn` runs the function in a subprocess and returns a [`Child`] instance which can be used to
/// monitor the process and retrieve its return value when it finishes via [`Child::join`]. `run`
/// combines the two operations into one, which may be useful if a new process is needed for a
/// reason other than parallel execution.
///
/// For example:
///
/// ```rust
/// use crossmist::{func, main};
///
/// #[func]
/// fn example(a: i32, b: i32) -> i32 {
///     a + b
/// }
///
/// #[main]
/// fn main() {
///     assert_eq!(example.spawn(5, 7).unwrap().join().unwrap(), 12);
///     assert_eq!(example.run(5, 7).unwrap(), 12);
/// }
/// ```
///
/// The function can also be invoked in *the same* process via the [`FnOnceObject`],
/// [`FnMutObject`], and [`FnObject`] traits, which are similar to [`std::ops::FnOnce`],
/// [`std::ops::FnMut`], and [`std::ops::Fn`], respectively:
///
/// ```rust
/// use crossmist::{FnObject, func, main};
///
/// #[func]
/// fn example(a: i32, b: i32) -> i32 {
///     a + b
/// }
///
/// #[main]
/// fn main() {
///     assert_eq!(example.call_object((5, 7)), 12);
/// }
/// ```
///
/// If the `nightly` feature is enabled, the function can also directly be called, providing the
/// same behavior as if `#[func]` was not used:
///
/// ```ignore
/// use crossmist::{FnObject, func, main};
///
/// #[func]
/// fn example(a: i32, b: i32) -> i32 {
///     a + b
/// }
///
/// #[main]
/// fn main() {
///     assert_eq!(example(5, 7), 12);
/// }
/// ```
///
/// `spawn` and `run` return an error if spawning the child process failed (e.g. the process limit
/// is exceeded or the system lacks memory). `run` also returns an error if the process panics,
/// calls [`std::process::exit`] or alike instead of returning a value, or is terminated (as does
/// [`Child::join`]).
///
/// The child process relays its return value to the parent via an implicit channel. Therefore, it
/// is important to keep the [`Child`] instance around until the child process terminates and never
/// drop it before joining, or the child process will panic.
///
/// Do:
///
/// ```rust
/// #[crossmist::main]
/// fn main() {
///     let child = long_running_task.spawn().expect("Failed to spawn child");
///     // ...
///     let need_child_result = false;  // assume this is computed from some external data
///     // ...
///     let return_value = child.join().expect("Child died");
///     if need_child_result {
///         eprintln!("{return_value}");
///     }
/// }
///
/// #[crossmist::func]
/// fn long_running_task() -> u32 {
///     std::thread::sleep(std::time::Duration::from_secs(1));
///     123
/// }
/// ```
///
/// Don't:
///
/// ```no_run
/// #[crossmist::main]
/// fn main() {
///     let child = long_running_task.spawn().expect("Failed to spawn child");
///     // ...
///     let need_child_result = false;  // assume this is computed from some external data
///     // ...
///     if need_child_result {
///         eprintln!("{}", child.join().expect("Child died"));
///     }
/// }
///
/// #[crossmist::func]
/// fn long_running_task() -> u32 {
///     std::thread::sleep(std::time::Duration::from_secs(1));
///     123
/// }
/// ```
///
/// The void return type (`()`) is an exception to this rule: such return values are not delivered,
/// and thus [`Child`] may be safely dropped at any point, and the child process is allowed to use
/// [`std::process::exit`] instead of explicitly returning `()`.
///
/// Do:
///
/// ```rust
/// #[crossmist::main]
/// fn main() {
///     long_running_task.spawn().expect("Failed to spawn child");
/// }
///
/// #[crossmist::func]
/// fn long_running_task() {
///     std::thread::sleep(std::time::Duration::from_secs(1));
/// }
/// ```
///
/// Do:
///
/// ```rust
/// #[crossmist::main]
/// fn main() {
///     let child = long_running_task.spawn().expect("Failed to spawn child");
///     // ...
///     child.join().expect("Child died");
/// }
///
/// #[crossmist::func]
/// fn long_running_task() {
///     std::thread::sleep(std::time::Duration::from_secs(1));
///     std::process::exit(0);
/// }
/// ```
///
///
/// ## Asynchronous case
///
/// If the `tokio` feature is enabled, the following methods are also made available:
///
/// ```ignore
/// pub async fn spawn_tokio(&self, arg1: Type1, ...) ->
///     std::io::Result<crossmist::tokio::Child<Output>>;
/// pub async fn run_tokio(&self, arg1: Type1, ...) -> std::io::Result<Output>;
/// ```
///
/// If `smol` is enabled, the functions `spawn_smol` and `run_smol` with matching signatures are
/// generated.
///
/// Additionally, the function may be `async`. In this case, you have to indicate which runtime to
/// use as follows:
///
/// ```ignore
/// #[crossmist::func(tokio)]
/// async fn example_tokio() {}
///
/// #[crossmist::func(smol)]
/// async fn example_smol() {}
/// ```
///
/// You may pass operands to forward to `tokio::main` like this:
///
/// ```rust
/// #[crossmist::func(tokio(flavor = "current_thread"))]
/// async fn example() {}
/// ```
///
/// Notice that the use of `spawn` vs `spawn_tokio`/`spawn_smol` is orthogonal to whether the
/// function is `async`: you can start a synchronous function in a child process asynchronously, or
/// vice versa:
///
/// ```rust
/// use crossmist::{func, main};
///
/// #[func]
/// fn example(a: i32, b: i32) -> i32 {
///     a + b
/// }
///
/// #[main]
/// #[tokio::main(flavor = "current_thread")]
/// async fn main() {
///     assert_eq!(example.run_tokio(5, 7).await.unwrap(), 12);
/// }
/// ```
///
/// ```rust
/// use crossmist::{func, main};
///
/// #[func(tokio(flavor = "current_thread"))]
/// async fn example(a: i32, b: i32) -> i32 {
///     a + b
/// }
///
/// #[main]
/// fn main() {
///     assert_eq!(example.run(5, 7).unwrap(), 12);
/// }
/// ```
pub use crossmist_derive::func;

/// Setup an entrypoint.
///
/// This attribute must always be added to `fn main`:
///
/// ```rust
/// #[crossmist::main]
/// fn main() {
///     // ...
/// }
/// ```
///
/// Without it, starting child processes will panic.
///
/// This attribute may be mixed with other attributes, e.g. `#[tokio::main]`. In this case, this
/// attribute should be the first in the list:
///
/// ```rust
/// #[crossmist::main]
/// #[tokio::main(flavor = "current_thread")]
/// async fn main() {
///     // ...
/// }
/// ```
///
/// If applying the attribute to `main` is not an option, consider [`init`] instead.
pub use crossmist_derive::main;

/// Make a structure or a enum serializable.
///
/// This derive macro enables the corresponding type to be passed via channels and to and from child
/// processes. [`Object`] can be implemented for a struct/enum if all of its fields implement
/// [`Object`]:
///
/// This is okay:
///
/// ```rust
/// # use crossmist::Object;
/// #[derive(Object)]
/// struct Test(String, i32);
/// ```
///
/// This is not okay:
///
/// ```compile_fail
/// # use crossmist::Object;
/// struct NotObject;
///
/// #[derive(Object)]
/// struct Test(String, i32, NotObject);
/// ```
///
/// Generics are supported. In this case, to ensure that all fields implement [`Object`],
/// constraints might be necessary:
///
/// This is okay:
///
/// ```rust
/// # use crossmist::Object;
/// #[derive(Object)]
/// struct MyPair<T: Object>(T, T);
/// ```
///
/// This is not okay:
///
/// ```compile_fail
/// # use crossmist::Object;
/// #[derive(Object)]
/// struct MyPair<T>(T, T);
/// ```
pub use crossmist_derive::Object;

#[doc(hidden)]
pub mod imp;
pub use imp::init;

pub mod serde;
pub use serde::*;

mod platform {
    #[cfg_attr(feature = "nightly", doc(cfg(all())))]
    #[cfg(unix)]
    pub mod unix {
        pub(crate) mod entry;
        pub mod handles;
        pub(crate) mod internals;
        pub(crate) mod subprocess;
    }
    #[cfg(windows)]
    pub mod windows {
        pub(crate) mod entry;
        pub mod handles;
        pub(crate) mod internals;
        pub(crate) mod subprocess;
    }
}

#[cfg(unix)]
pub use crate::platform::unix::*;
#[cfg(windows)]
pub use crate::platform::windows::*;

pub mod asynchronous;
pub mod blocking;
#[cfg(feature = "smol")]
pub mod smol;
#[cfg(feature = "tokio")]
pub mod tokio;

#[doc(inline)]
pub use asynchronous::KillHandle;
pub use blocking::{channel, duplex, Child, Duplex, Receiver, Sender};

pub(crate) mod relocation;

mod builtins;
mod unsized_builtins;

pub mod delayed;
pub use delayed::Delayed;

pub mod fns;
pub use fns::*;

pub mod static_ref;
pub use static_ref::StaticRef;

mod pod;
pub use pod::Object;