1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use syn::Ident;

use crate::{
    analyze::Priority,
    ast::{Access, App, Local, TaskLocal},
};

impl App {
    pub(crate) fn shared_resource_accesses(
        &self,
    ) -> impl Iterator<Item = (Option<Priority>, &Ident, Access)> {
        self.idle
            .iter()
            .flat_map(|idle| {
                idle.args
                    .shared_resources
                    .iter()
                    .map(move |(name, access)| (Some(0), name, *access))
            })
            .chain(self.hardware_tasks.values().flat_map(|task| {
                task.args
                    .shared_resources
                    .iter()
                    .map(move |(name, access)| (Some(task.args.priority), name, *access))
            }))
            .chain(self.software_tasks.values().flat_map(|task| {
                task.args
                    .shared_resources
                    .iter()
                    .map(move |(name, access)| (Some(task.args.priority), name, *access))
            }))
    }

    fn is_external(task_local: &TaskLocal) -> bool {
        matches!(task_local, TaskLocal::External)
    }

    pub(crate) fn local_resource_accesses(&self) -> impl Iterator<Item = &Ident> {
        self.init
            .args
            .local_resources
            .iter()
            .filter(|(_, task_local)| Self::is_external(task_local)) // Only check the resources declared in `#[local]`
            .map(move |(name, _)| name)
            .chain(self.idle.iter().flat_map(|idle| {
                idle.args
                    .local_resources
                    .iter()
                    .filter(|(_, task_local)| Self::is_external(task_local)) // Only check the resources declared in `#[local]`
                    .map(move |(name, _)| name)
            }))
            .chain(self.hardware_tasks.values().flat_map(|task| {
                task.args
                    .local_resources
                    .iter()
                    .filter(|(_, task_local)| Self::is_external(task_local)) // Only check the resources declared in `#[local]`
                    .map(move |(name, _)| name)
            }))
            .chain(self.software_tasks.values().flat_map(|task| {
                task.args
                    .local_resources
                    .iter()
                    .filter(|(_, task_local)| Self::is_external(task_local)) // Only check the resources declared in `#[local]`
                    .map(move |(name, _)| name)
            }))
    }

    fn get_declared_local(tl: &TaskLocal) -> Option<&Local> {
        match tl {
            TaskLocal::External => None,
            TaskLocal::Declared(l) => Some(l),
        }
    }

    /// Get all declared local resources, i.e. `local = [NAME: TYPE = EXPR]`.
    ///
    /// Returns a vector of (task name, resource name, `Local` struct)
    pub fn declared_local_resources(&self) -> Vec<(&Ident, &Ident, &Local)> {
        self.init
            .args
            .local_resources
            .iter()
            .filter_map(move |(name, tl)| {
                Self::get_declared_local(tl).map(|l| (&self.init.name, name, l))
            })
            .chain(self.idle.iter().flat_map(|idle| {
                idle.args
                    .local_resources
                    .iter()
                    .filter_map(move |(name, tl)| {
                        Self::get_declared_local(tl)
                            .map(|l| (&self.idle.as_ref().unwrap().name, name, l))
                    })
            }))
            .chain(self.hardware_tasks.iter().flat_map(|(task_name, task)| {
                task.args
                    .local_resources
                    .iter()
                    .filter_map(move |(name, tl)| {
                        Self::get_declared_local(tl).map(|l| (task_name, name, l))
                    })
            }))
            .chain(self.software_tasks.iter().flat_map(|(task_name, task)| {
                task.args
                    .local_resources
                    .iter()
                    .filter_map(move |(name, tl)| {
                        Self::get_declared_local(tl).map(|l| (task_name, name, l))
                    })
            }))
            .collect()
    }
}