samod_core/
loader.rs

1use std::sync::{Arc, Mutex};
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/// use rand::SeedableRng;
24///
25/// let rng = rand::rngs::StdRng::from_rng(&mut rand::rng());
26/// let mut loader = SamodLoader::new(rng, PeerId::from("test"), UnixTimestamp::now());
27///
28/// loop {
29///     match loader.step(UnixTimestamp::now()) {
30///         LoaderState::NeedIo(tasks) => {
31///             // Execute IO tasks and provide results
32///             for task in tasks {
33///                 // ... execute task ...
34///                 # let result: IoResult<StorageResult> = todo!();
35///                 loader.provide_io_result(UnixTimestamp::now(), result);
36///             }
37///         }
38///         LoaderState::Loaded(samod) => {
39///             // Repository is loaded and ready to use
40///             break;
41///         }
42///     }
43/// }
44/// ```
45pub struct SamodLoader<R> {
46    driver: Driver<Loading<R>>,
47}
48
49/// The current state of the loader.
50pub enum LoaderState {
51    /// The loader needs IO operations to be performed.
52    ///
53    /// The caller should execute all provided IO tasks and call
54    /// `provide_io_result` for each completed task, then call `step` again.
55    NeedIo(Vec<IoTask<StorageTask>>),
56
57    /// Loading is complete and the samod repository is ready to use.
58    Loaded(Hub),
59}
60
61impl<R: rand::Rng + Clone + Send + Sync + 'static> SamodLoader<R> {
62    /// Creates a new samod loader.
63    ///
64    /// # Arguments
65    ///
66    /// * `now` - The current timestamp for initialization
67    ///
68    /// # Returns
69    ///
70    /// A new `SamodLoader` ready to begin the loading process.
71    pub fn new(rng: R, local_peer_id: PeerId, now: UnixTimestamp) -> Self {
72        let driver = Driver::spawn(now, |args| loading::load(rng, local_peer_id, args));
73
74        Self { driver }
75    }
76
77    /// Advances the loader state machine.
78    ///
79    /// This method should be called repeatedly until `LoaderState::Loaded` is returned.
80    /// When `LoaderState::NeedIo` is returned, the caller must execute the provided
81    /// IO tasks and call `provide_io_result` for each one before calling `step` again.
82    ///
83    /// # Arguments
84    ///
85    /// * `now` - The current timestamp
86    ///
87    /// # Returns
88    ///
89    /// The current state of the loader.
90    pub fn step(&mut self, now: UnixTimestamp) -> LoaderState {
91        let new_tasks = match self.driver.step(now) {
92            StepResult::Suspend(tasks) => tasks,
93            StepResult::Complete {
94                results,
95                complete: (hub_state, rng),
96            } => {
97                assert!(results.is_empty());
98                let state = Arc::new(Mutex::new(hub_state));
99                let hub = Hub::new(rng, now, state);
100                return LoaderState::Loaded(hub);
101            }
102        };
103
104        LoaderState::NeedIo(new_tasks)
105    }
106
107    /// Provides the result of an IO operation.
108    ///
109    /// This method should be called for each IO task that was returned by `step`.
110    /// The loader passes the result directly to the driver for processing.
111    ///
112    /// # Arguments
113    ///
114    /// * `result` - The result of executing an IO task
115    pub fn provide_io_result(&mut self, now: UnixTimestamp, result: IoResult<StorageResult>) {
116        self.driver.handle_io_complete(now, result);
117    }
118}