1use crate::__export::{ProjectError, ProjectResult, TaskId};
4use crate::dependencies::dependency_container::ConfigurationHandler;
5use crate::dependencies::RegistryContainer;
6use crate::error::PayloadError;
7use crate::identifier::{ProjectId, TaskIdFactory};
8use crate::plugins::PluginAware;
9use crate::project::finder::{TaskFinder, TaskPath};
10use crate::project::GetProjectId;
11use crate::task::task_container::TaskContainer;
12use crate::task::{AnyTaskHandle, TaskHandle};
13use crate::{project, Plugin, Project, Task, Workspace};
14use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
15use std::fmt::{Debug, Display, Formatter};
16use std::ops::{Deref, DerefMut};
17use std::sync::{Arc, Weak};
18
19#[derive(Debug, Clone)]
22pub struct SharedProject(Arc<(TrueSharableProject, ProjectId)>);
23
24pub(crate) type TrueSharableProject = RwLock<Project>;
25
26impl SharedProject {
27 pub(super) fn new_cyclic<F: FnOnce(&WeakSharedProject) -> Project>(func: F) -> Self {
28 let modified = |weak: &Weak<(TrueSharableProject, ProjectId)>| {
29 let weakened = WeakSharedProject(weak.clone());
30 let project = func(&weakened);
31 let id = project.id().clone();
32 (RwLock::new(project), id)
33 };
34 let arc = Arc::new_cyclic(modified);
35 Self(arc)
36 }
37
38 fn new(project: Project) -> Self {
39 let id = project.id().clone();
40 Self(Arc::new((RwLock::new(project), id)))
41 }
42
43 pub(crate) fn weak(&self) -> WeakSharedProject {
44 WeakSharedProject(Arc::downgrade(&self.0))
45 }
46
47 pub fn with<F, R>(&self, func: F) -> R
48 where
49 F: FnOnce(&Project) -> R,
50 {
51 let guard = self
52 .0
53 .0
54 .try_read()
55 .unwrap_or_else(|| panic!("Couldn't get read access to {}", self));
56 let r = (func)(&*guard);
57 r
58 }
59
60 pub fn with_mut<F, R>(&self, func: F) -> R
61 where
62 F: FnOnce(&mut Project) -> R,
63 {
64 let mut guard = self
65 .0
66 .0
67 .try_write()
68 .unwrap_or_else(|| panic!("Couldn't get read access to {}", self));
69 let r = (func)(&mut *guard);
70 r
71 }
72
73 pub fn guard<'g, T, F: Fn(&Project) -> &T + 'g>(&'g self, func: F) -> ProjectResult<Guard<T>> {
74 let guard = match self.0 .0.try_read() {
75 Some(guard) => guard,
76 None => {
77 panic!("Accessing this immutable guard would block for {}", self)
78 }
79 };
80 Ok(Guard::new(guard, func))
81 }
82
83 pub fn guard_mut<'g, T, F1, F2>(
84 &'g self,
85 ref_getter: F1,
86 mut_getter: F2,
87 ) -> ProjectResult<GuardMut<T>>
88 where
89 F1: Fn(&Project) -> &T + 'g,
90 F2: Fn(&mut Project) -> &mut T + 'g,
91 {
92 let guard = match self.0 .0.try_write() {
93 Some(guard) => guard,
94 None => {
95 panic!("Accessing this guard would block for {}", self)
96 }
97 };
98 Ok(GuardMut::new(guard, ref_getter, mut_getter))
99 }
100
101 pub fn tasks(&self) -> GuardMut<TaskContainer> {
102 self.guard_mut(
103 |project| project.task_container(),
104 |project| project.task_container_mut(),
105 )
106 .expect("couldn't safely get task container")
107 }
108
109 pub fn register_task<T: Task + Send + Sync + Debug + 'static>(
110 &self,
111 id: &str,
112 ) -> ProjectResult<TaskHandle<T>> {
113 self.tasks().with_mut(|t| t.register_task::<T>(id))
114 }
115
116 pub fn get_task(&self, id: &TaskId) -> ProjectResult<AnyTaskHandle> {
118 Ok(self.task_container().with(|t| {
119 t.get_task(id)
120 .cloned()
121 .ok_or(ProjectError::IdentifierMissing(id.clone()))
122 })?)
123 }
124
125 pub fn get_typed_task<T: Task + Send + Sync>(
127 &self,
128 id: &TaskId,
129 ) -> ProjectResult<TaskHandle<T>> {
130 self.get_task(id).and_then(|id| {
131 id.as_type::<T>()
132 .ok_or(ProjectError::custom("invalid task type").into())
133 })
134 }
135
136 pub fn find_task<P: AsRef<TaskPath>>(&self, path: P) -> ProjectResult<AnyTaskHandle> {
138 let finder = TaskFinder::new(self);
139 let path = path.as_ref();
140 let ids = finder
141 .find(path)?
142 .ok_or(ProjectError::TaskNotFound(path.to_owned()))?;
143
144 match &ids[..] {
145 [] => unreachable!(),
146 [task_id] => self.get_task(task_id),
147 [..] => Err(PayloadError::new(ProjectError::TooManyIdentifiersFound(
148 ids,
149 path.to_string(),
150 ))),
151 }
152 }
153
154 pub fn get_subproject<P>(&self, project: P) -> project::Result<SharedProject>
155 where
156 P: AsRef<str>,
157 {
158 self.with(|p| p.get_subproject(project).cloned())
159 }
160
161 pub fn allprojects<F: Fn(&Project) + Clone>(&self, callback: F) {
163 self.with(callback.clone());
164 self.with(|s| {
165 s.subprojects()
166 .iter()
167 .for_each(|&project| project.allprojects(callback.clone()))
168 })
169 }
170
171 pub fn allprojects_mut<F: Fn(&mut Project) + Clone>(&self, callback: F) {
173 self.with_mut(callback.clone());
174 self.with(|s| {
175 s.subprojects()
176 .iter()
177 .for_each(|&project| project.allprojects_mut(callback.clone()))
178 })
179 }
180
181 pub fn task_container(&self) -> Guard<TaskContainer> {
183 self.guard(|project| project.task_container())
184 .expect("couldn't safely get task container")
185 }
186
187 pub(crate) fn task_id_factory(&self) -> Guard<TaskIdFactory> {
188 self.guard(|project| project.task_id_factory())
189 .expect("couldn't safely get task id factory")
190 }
191
192 pub fn registries<F, R>(&self, func: F) -> R
194 where
195 F: FnOnce(&mut RegistryContainer) -> R,
196 {
197 self.with(|r| {
198 let mut registries_lock = r.registries.lock().unwrap();
199 let registries = &mut *registries_lock;
200 func(registries)
201 })
202 }
203
204 pub fn configurations_mut(&mut self) -> GuardMut<ConfigurationHandler> {
206 self.guard_mut(
207 |project| project.configurations(),
208 |project| project.configurations_mut(),
209 )
210 .expect("couldn't safely get dependencies container")
211 }
212
213 pub fn configurations(&self) -> Guard<ConfigurationHandler> {
215 self.guard(|project| project.configurations())
216 .expect("couldn't safely get dependencies container")
217 }
218
219 pub fn workspace(&self) -> Guard<Workspace> {
220 self.guard(|p| &p.workspace)
221 .expect("couldn't get workspace")
222 }
223
224 pub fn apply_plugin<P: Plugin<Project>>(&self) -> ProjectResult {
226 self.with_mut(|p| p.apply_plugin::<P>())
227 }
228}
229
230impl Display for SharedProject {
231 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
232 write!(f, "{}", self.0 .1)
233 }
234}
235
236impl Default for SharedProject {
237 fn default() -> Self {
238 Project::new().unwrap()
239 }
240}
241
242impl TryFrom<Weak<(TrueSharableProject, ProjectId)>> for SharedProject {
243 type Error = ();
244
245 fn try_from(
246 value: Weak<(TrueSharableProject, ProjectId)>,
247 ) -> std::result::Result<Self, Self::Error> {
248 let arc = value.upgrade().ok_or(())?;
249 Ok(SharedProject(arc))
250 }
251}
252
253impl TryFrom<WeakSharedProject> for SharedProject {
254 type Error = PayloadError<ProjectError>;
255
256 fn try_from(value: WeakSharedProject) -> std::result::Result<Self, Self::Error> {
257 value.upgrade()
258 }
259}
260
261impl From<Arc<(TrueSharableProject, ProjectId)>> for SharedProject {
262 fn from(arc: Arc<(TrueSharableProject, ProjectId)>) -> Self {
263 Self(arc)
264 }
265}
266
267pub struct Guard<'g, T> {
269 guard: RwLockReadGuard<'g, Project>,
270 getter: Box<dyn Fn(&Project) -> &T + 'g>,
271}
272
273impl<'g, T> Guard<'g, T> {
274 pub fn new<F>(guard: RwLockReadGuard<'g, Project>, getter: F) -> Self
275 where
276 F: Fn(&Project) -> &T + 'g,
277 {
278 Self {
279 guard,
280 getter: Box::new(getter),
281 }
282 }
283
284 pub fn with<R, F: FnOnce(&T) -> R>(&self, func: F) -> R {
285 let guard = &*self.guard;
286 let t = (self.getter)(guard);
287 let r = (func)(t);
288 r
289 }
290}
291
292impl<T> Deref for Guard<'_, T> {
293 type Target = T;
294
295 fn deref(&self) -> &Self::Target {
296 let guard = &*self.guard;
297 (self.getter)(guard)
298 }
299}
300
301pub struct GuardMut<'g, T> {
303 guard: RwLockWriteGuard<'g, Project>,
304 ref_getter: Box<dyn Fn(&Project) -> &T + 'g>,
305 mut_getter: Box<dyn Fn(&mut Project) -> &mut T + 'g>,
306}
307
308impl<'g, T> GuardMut<'g, T> {
309 pub fn new<F1, F2>(guard: RwLockWriteGuard<'g, Project>, ref_getter: F1, mut_getter: F2) -> Self
310 where
311 F1: Fn(&Project) -> &T + 'g,
312 F2: Fn(&mut Project) -> &mut T + 'g,
313 {
314 Self {
315 guard,
316 ref_getter: Box::new(ref_getter),
317 mut_getter: Box::new(mut_getter),
318 }
319 }
320
321 pub fn with<R, F: FnOnce(&T) -> R>(&self, func: F) -> R {
322 let guard = &*self.guard;
323 let t = (self.ref_getter)(guard);
324 let r = (func)(t);
325 r
326 }
327
328 pub fn with_mut<R, F: FnOnce(&mut T) -> R>(&mut self, func: F) -> R {
329 let guard = &mut *self.guard;
330 let t = (self.mut_getter)(guard);
331 let r = (func)(t);
332 r
333 }
334}
335
336impl<T> Deref for GuardMut<'_, T> {
337 type Target = T;
338
339 fn deref(&self) -> &Self::Target {
340 let guard = &*self.guard;
341 (self.ref_getter)(guard)
342 }
343}
344
345impl<T> DerefMut for GuardMut<'_, T> {
346 fn deref_mut(&mut self) -> &mut Self::Target {
347 let ref mut guard = *self.guard;
348 (self.mut_getter)(guard)
349 }
350}
351
352impl GetProjectId for SharedProject {
353 fn project_id(&self) -> ProjectId {
354 self.with(|p| p.project_id())
355 }
356
357 fn parent_id(&self) -> Option<ProjectId> {
358 self.with(GetProjectId::parent_id)
359 }
360
361 fn root_id(&self) -> ProjectId {
362 self.with(GetProjectId::root_id)
363 }
364}
365
366#[derive(Debug, Clone)]
367pub(crate) struct WeakSharedProject(Weak<(TrueSharableProject, ProjectId)>);
368
369impl WeakSharedProject {
370 pub fn upgrade(self) -> project::Result<SharedProject> {
372 self.0
373 .upgrade()
374 .map(SharedProject)
375 .ok_or(ProjectError::NoSharedProjectSet.into())
376 }
377}