Skip to main content

taskgraph/storage/
static_store.rs

1//! Static storage implementation for taskgraph-rs.
2//! Uses a fixed-size array with constant generics.
3
4use crate::error::{Result, TaskError};
5use crate::core::task::{Task, TaskStore, TaskStatus};
6
7/// Storage backed by a fixed-size array.
8pub struct StaticStore<const N: usize> {
9    tasks: [Option<Task>; N],
10    edges: [u64; N],
11    count: usize,
12}
13
14impl<const N: usize> StaticStore<N> {
15    /// Create a new static store.
16    pub const fn new() -> Result<Self> {
17        if N > 64 {
18            return Err(TaskError::CapacityExceeded);
19        }
20        const NONE_TASK: Option<Task> = None;
21        Ok(Self {
22            tasks: [NONE_TASK; N],
23            edges: [0; N],
24            count: 0,
25        })
26    }
27}
28
29use core::sync::atomic::Ordering;
30
31impl<const N: usize> TaskStore for StaticStore<N> {
32    fn add_task(&mut self, mut task: Task, deps: &[usize]) -> Result<usize> {
33        if self.count >= N {
34            return Err(TaskError::CapacityExceeded);
35        }
36
37        let id = self.count;
38        task.remaining_deps.store(deps.len(), Ordering::SeqCst);
39        task.initial_deps = deps.len();
40        
41        // Populate adjacency list (backwards for incoming, but we want outgoing)
42        // Wait, deps are incoming. We want to know WHO depends on id.
43        // So for each d in deps, we add id to edges[d].
44        for &d in deps {
45            if d >= self.count {
46                return Err(TaskError::InvalidState);
47            }
48            // completed task 'd' unlocks 'id'
49            self.edges[d] |= 1 << id;
50        }
51
52        self.tasks[id] = Some(task);
53        self.count += 1;
54        Ok(id)
55    }
56
57    fn get_successors(&self, id: usize) -> u64 {
58        if id < N {
59            self.edges[id]
60        } else {
61            0
62        }
63    }
64
65    fn get_task(&self, id: usize) -> Option<&Task> {
66        if id < self.count {
67            self.tasks[id].as_ref()
68        } else {
69            None
70        }
71    }
72
73    fn get_task_mut(&mut self, id: usize) -> Option<&mut Task> {
74        if id < self.count {
75            self.tasks[id].as_mut()
76        } else {
77            None
78        }
79    }
80
81    fn update_status(&mut self, id: usize, status: TaskStatus) -> Result<()> {
82        let task = self.get_task_mut(id).ok_or(TaskError::InvalidState)?;
83        task.status = status;
84        Ok(())
85    }
86
87    fn task_count(&self) -> usize {
88        self.count
89    }
90}
91
92impl<const N: usize> Default for StaticStore<N> {
93    fn default() -> Self {
94        Self::new().expect("StaticStore capacity exceeded limit (64)")
95    }
96}