io_m2dir/coroutine.rs
1//! # Generator-shape coroutine driver
2//!
3//! Mirrors the shape of `core::ops::Coroutine`: a `Yield` associated type for
4//! intermediate progress, a `Return` associated type for terminal output, and a
5//! two-variant [`M2dirCoroutineState`] (`Yielded` / `Complete`).
6//!
7//! io-m2dir is filesystem-flavoured, so every coroutine in the crate picks the
8//! standard [`M2dirYield`] directly: it gathers every filesystem (and
9//! environmental) primitive the crate emits, namely directory create / remove /
10//! read, file create / read / exists / remove, path rename, and the process id
11//! / random bytes inputs needed to mint m2dir entry identifiers.
12//!
13//! [`M2dirClient::run`] drives any standard-Yield coroutine to completion
14//! against the local filesystem.
15//!
16//! [`M2dirClient::run`]: crate::client::M2dirClient::run
17
18use alloc::{
19 collections::{BTreeMap, BTreeSet},
20 vec::Vec,
21};
22
23use crate::path::M2dirPath;
24
25/// State yielded by an [`M2dirCoroutine::resume`] step.
26///
27/// Two-variant by design (matches std's `core::ops::CoroutineState`): any
28/// further variation lives inside the per-coroutine `Yield` type.
29#[derive(Debug)]
30pub enum M2dirCoroutineState<Y, R> {
31 /// Intermediate yield. The driver reacts to `Y` (do filesystem I/O, supply
32 /// pid / random bytes…) and resumes the coroutine again.
33 Yielded(Y),
34 /// Terminal yield. By convention `R = Result<Output, Error>`.
35 Complete(R),
36}
37
38/// Standard-shape m2dir coroutine.
39///
40/// Implementors own their internal state machine and declare their per-step
41/// `Yield` plus a terminal `Return`. The driver reacts to each `Yield` variant
42/// and resumes until `Complete`.
43pub trait M2dirCoroutine {
44 /// Intermediate value handed back on every step. Per-coroutine: each
45 /// implementor picks exactly the variants it needs. In io-m2dir every
46 /// coroutine picks [`M2dirYield`].
47 type Yield;
48 /// Terminal value. By convention `Result<Output, Error>`; the "ok" arm
49 /// carries the operation's final output, the "error" arm carries the cause.
50 type Return;
51
52 /// Advances the coroutine one step.
53 ///
54 /// Pass [`None`] on the initial call. Pass `Some(arg)` carrying the value
55 /// matching the previous `Yielded` variant.
56 fn resume(&mut self, arg: Option<M2dirArg>) -> M2dirCoroutineState<Self::Yield, Self::Return>;
57}
58
59/// Standard filesystem-only Yield. Every io-m2dir coroutine picks `type Yield =
60/// M2dirYield`.
61///
62/// Each variant is paired with the matching [`M2dirArg`] variant the driver
63/// feeds back on the next `resume`.
64#[derive(Debug)]
65pub enum M2dirYield {
66 /// Driver must supply the current process id and feed back
67 /// [`M2dirArg::Pid`].
68 WantsPid,
69
70 /// Driver must supply `len` random bytes and feed back
71 /// [`M2dirArg::Random`].
72 WantsRandom { len: usize },
73
74 /// Driver must check each path for existence as a regular file and feed
75 /// back [`M2dirArg::FileExists`].
76 WantsFileExists(BTreeSet<M2dirPath>),
77
78 /// Driver must list each directory's entries and feed back
79 /// [`M2dirArg::DirRead`].
80 WantsDirRead(BTreeSet<M2dirPath>),
81
82 /// Driver must create each directory (with parents) and feed back
83 /// [`M2dirArg::DirCreate`].
84 WantsDirCreate(BTreeSet<M2dirPath>),
85
86 /// Driver must recursively remove each directory and feed back
87 /// [`M2dirArg::DirRemove`].
88 WantsDirRemove(BTreeSet<M2dirPath>),
89
90 /// Driver must read each file's bytes and feed back [`M2dirArg::FileRead`].
91 WantsFileRead(BTreeSet<M2dirPath>),
92
93 /// Driver must write each `(path, bytes)` pair and feed back
94 /// [`M2dirArg::FileCreate`].
95 WantsFileCreate(BTreeMap<M2dirPath, Vec<u8>>),
96
97 /// Driver must remove each file and feed back [`M2dirArg::FileRemove`].
98 WantsFileRemove(BTreeSet<M2dirPath>),
99
100 /// Driver must rename each `(from, to)` pair and feed back
101 /// [`M2dirArg::Rename`].
102 WantsRename(Vec<(M2dirPath, M2dirPath)>),
103}
104
105/// Reply fed back into [`M2dirCoroutine::resume`] by the driver.
106///
107/// Each variant matches the corresponding [`M2dirYield`] request and carries
108/// the value the driver gathered while servicing it.
109#[derive(Clone, Debug)]
110pub enum M2dirArg {
111 /// Reply to [`M2dirYield::WantsPid`].
112 Pid(u32),
113 /// Reply to [`M2dirYield::WantsRandom`].
114 Random(Vec<u8>),
115 /// Reply to [`M2dirYield::WantsFileExists`]: probed path to whether it
116 /// exists as a regular file.
117 FileExists(BTreeMap<M2dirPath, bool>),
118 /// Reply to [`M2dirYield::WantsDirRead`]: probed directory to the set of
119 /// paths found inside.
120 DirRead(BTreeMap<M2dirPath, BTreeSet<M2dirPath>>),
121 /// Reply to [`M2dirYield::WantsDirCreate`].
122 DirCreate,
123 /// Reply to [`M2dirYield::WantsDirRemove`].
124 DirRemove,
125 /// Reply to [`M2dirYield::WantsFileRead`]: probed file to its bytes (or an
126 /// empty buffer when the file is missing).
127 FileRead(BTreeMap<M2dirPath, Vec<u8>>),
128 /// Reply to [`M2dirYield::WantsFileCreate`].
129 FileCreate,
130 /// Reply to [`M2dirYield::WantsFileRemove`].
131 FileRemove,
132 /// Reply to [`M2dirYield::WantsRename`].
133 Rename,
134}