samod_core/
loader.rs

1use std::{cell::RefCell, rc::Rc};
2
3use crate::{
4    PeerId, UnixTimestamp,
5    actors::{
6        driver::{Driver, StepResult},
7        hub::Hub,
8        loading::{self, Loading},
9    },
10    io::{IoResult, IoTask, StorageResult, StorageTask},
11};
12
13/// A state machine for loading a samod repository.
14///
15/// `SamodLoader` handles the initialization phase of a samod repository,
16/// coordinating between the user and the driver to load or generate the storage ID
17/// and perform any other setup operations required before the repository can be used.
18///
19/// ## Usage
20///
21/// ```rust,no_run
22/// use samod_core::{PeerId, SamodLoader, LoaderState, UnixTimestamp, io::{StorageResult, IoResult}};
23///
24/// let mut loader = SamodLoader::new(rand::rng(), PeerId::from("test"), UnixTimestamp::now());
25///
26/// loop {
27///     match loader.step(UnixTimestamp::now()) {
28///         LoaderState::NeedIo(tasks) => {
29///             // Execute IO tasks and provide results
30///             for task in tasks {
31///                 // ... execute task ...
32///                 # let result: IoResult<StorageResult> = todo!();
33///                 loader.provide_io_result(UnixTimestamp::now(), result);
34///             }
35///         }
36///         LoaderState::Loaded(samod) => {
37///             // Repository is loaded and ready to use
38///             break;
39///         }
40///     }
41/// }
42/// ```
43pub struct SamodLoader<R> {
44    driver: Driver<Loading<R>>,
45}
46
47/// The current state of the loader.
48pub enum LoaderState {
49    /// The loader needs IO operations to be performed.
50    ///
51    /// The caller should execute all provided IO tasks and call
52    /// `provide_io_result` for each completed task, then call `step` again.
53    NeedIo(Vec<IoTask<StorageTask>>),
54
55    /// Loading is complete and the samod repository is ready to use.
56    Loaded(Hub),
57}
58
59impl<R: rand::Rng + Clone + 'static> SamodLoader<R> {
60    /// Creates a new samod loader.
61    ///
62    /// # Arguments
63    ///
64    /// * `now` - The current timestamp for initialization
65    ///
66    /// # Returns
67    ///
68    /// A new `SamodLoader` ready to begin the loading process.
69    pub fn new(rng: R, local_peer_id: PeerId, now: UnixTimestamp) -> Self {
70        let driver = Driver::spawn(now, |args| loading::load(rng, local_peer_id, args));
71
72        Self { driver }
73    }
74
75    /// Advances the loader state machine.
76    ///
77    /// This method should be called repeatedly until `LoaderState::Loaded` is returned.
78    /// When `LoaderState::NeedIo` is returned, the caller must execute the provided
79    /// IO tasks and call `provide_io_result` for each one before calling `step` again.
80    ///
81    /// # Arguments
82    ///
83    /// * `now` - The current timestamp
84    ///
85    /// # Returns
86    ///
87    /// The current state of the loader.
88    pub fn step(&mut self, now: UnixTimestamp) -> LoaderState {
89        let new_tasks = match self.driver.step(now) {
90            StepResult::Suspend(tasks) => tasks,
91            StepResult::Complete {
92                results,
93                complete: (hub_state, rng),
94            } => {
95                assert!(results.is_empty());
96                let state = Rc::new(RefCell::new(hub_state));
97                let hub = Hub::new(rng, now, state);
98                return LoaderState::Loaded(hub);
99            }
100        };
101
102        LoaderState::NeedIo(new_tasks)
103    }
104
105    /// Provides the result of an IO operation.
106    ///
107    /// This method should be called for each IO task that was returned by `step`.
108    /// The loader passes the result directly to the driver for processing.
109    ///
110    /// # Arguments
111    ///
112    /// * `result` - The result of executing an IO task
113    pub fn provide_io_result(&mut self, now: UnixTimestamp, result: IoResult<StorageResult>) {
114        self.driver.handle_io_complete(now, result);
115    }
116}