assemble_core/task/
any_task.rs

1use crate::__export::TaskId;
2
3use crate::project::error::ProjectResult;
4use crate::project::shared::SharedProject;
5use crate::task::{
6    BuildableTask, FullTask, HasTaskId, ResolveExecutable, TaskHandle, TaskOrdering,
7};
8use crate::{Project, Task};
9use std::any::{Any, TypeId};
10use std::fmt::{Debug, Formatter};
11use std::sync::{Arc, Mutex};
12
13#[derive(Clone)]
14pub struct AnyTaskHandle {
15    id: TaskId,
16    only_current: bool,
17    handle: Arc<Mutex<AnyTaskHandleInner>>,
18}
19
20impl Debug for AnyTaskHandle {
21    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
22        write!(f, "AnyTaskHandle {:?}", self.id)
23    }
24}
25
26impl HasTaskId for AnyTaskHandle {
27    fn task_id(&self) -> TaskId {
28        self.id.clone()
29    }
30}
31
32impl BuildableTask for AnyTaskHandle {
33    fn ordering(&self) -> Vec<TaskOrdering> {
34        self.with_inner(|inner| inner.buildable().ordering())
35    }
36}
37
38impl AnyTaskHandle {
39    pub fn new<T: Task + Send + Sync + 'static>(provider: TaskHandle<T>) -> Self {
40        Self {
41            id: provider.task_id(),
42            only_current: T::only_in_current(),
43            handle: Arc::new(Mutex::new(AnyTaskHandleInner::new(provider))),
44        }
45    }
46
47    fn with_inner<R, F: FnOnce(&mut AnyTaskHandleInner) -> R>(&self, func: F) -> R {
48        let mut guard = self.handle.lock().expect("couldn't get handle");
49        (func)(&mut *guard)
50    }
51
52    pub fn is<T: Task + Send + Sync + 'static>(&self) -> bool {
53        self.with_inner(|handle| handle.is::<T>())
54    }
55
56    pub fn as_type<T: Task + Send + Sync + 'static>(&self) -> Option<TaskHandle<T>> {
57        if !self.is::<T>() {
58            return None;
59        }
60        self.with_inner(|handle| handle.as_type::<T>())
61    }
62
63    fn executable(&mut self, project: &SharedProject) -> ProjectResult<Box<dyn FullTask>> {
64        self.with_inner(|p| p.resolvable().get_executable(project))
65    }
66
67    pub fn resolve(&mut self, project: &Project) -> ProjectResult<Box<dyn FullTask>> {
68        self.executable(&project.as_shared())
69    }
70
71    pub fn resolve_shared(&mut self, project: &SharedProject) -> ProjectResult<Box<dyn FullTask>> {
72        self.executable(project)
73    }
74
75    pub(crate) fn only_current(&self) -> bool {
76        self.only_current
77    }
78}
79
80struct AnyTaskHandleInner {
81    task_type: TypeId,
82    as_buildable: Box<dyn BuildableTask + Send>,
83    as_resolvable: Box<dyn ResolveExecutable + Send>,
84    as_any: Box<dyn Any + Send>,
85}
86
87impl Debug for AnyTaskHandleInner {
88    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
89        write!(f, "TaskConnection {{ ... }}")
90    }
91}
92
93impl AnyTaskHandleInner {
94    fn new<T: Task + Send + Sync + 'static>(provider: TaskHandle<T>) -> Self {
95        let task_type = TypeId::of::<T>();
96        let as_buildable: Box<dyn BuildableTask + Send> = Box::new(provider.clone());
97        let as_resolvable: Box<dyn ResolveExecutable + Send> = Box::new(provider.clone());
98        let as_any: Box<dyn Any + Send> = Box::new(provider);
99        Self {
100            task_type,
101            as_buildable,
102            as_resolvable,
103            as_any,
104        }
105    }
106
107    fn is<T: Task + Send + Sync + 'static>(&self) -> bool {
108        self.task_type == TypeId::of::<T>()
109    }
110
111    fn as_type<T: Task + Send + Sync + 'static>(&self) -> Option<TaskHandle<T>> {
112        if !self.is::<T>() {
113            return None;
114        }
115        self.as_any.downcast_ref::<TaskHandle<T>>().cloned()
116    }
117
118    fn buildable(&self) -> &dyn BuildableTask {
119        self.as_buildable.as_ref()
120    }
121
122    fn resolvable(&mut self) -> &mut dyn ResolveExecutable {
123        self.as_resolvable.as_mut()
124    }
125
126    fn executable(&mut self, project: &SharedProject) -> ProjectResult<Box<dyn FullTask>> {
127        self.resolvable().get_executable(project)
128    }
129}
130
131assert_impl_all!(AnyTaskHandleInner: Send);