assemble_core/task/
any_task.rs1use 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);