Skip to main content

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}