sps_common/dependency/
definition.rs

1// **File:** sps-core/src/dependency/dependency.rs // Should be in the model module
2use std::fmt;
3
4use bitflags::bitflags;
5use serde::{Deserialize, Serialize};
6
7bitflags! {
8    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
9    pub struct DependencyTag: u8 {
10        const RUNTIME     = 0b00000001;
11        const BUILD       = 0b00000010;
12        const TEST        = 0b00000100;
13        const OPTIONAL    = 0b00001000;
14        const RECOMMENDED = 0b00010000;
15    }
16}
17
18impl Default for DependencyTag {
19    fn default() -> Self {
20        Self::RUNTIME
21    }
22}
23
24impl fmt::Display for DependencyTag {
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        write!(f, "{self:?}")
27    }
28}
29
30#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
31pub struct Dependency {
32    pub name: String,
33    #[serde(default)]
34    pub tags: DependencyTag,
35}
36
37impl Dependency {
38    pub fn new_runtime(name: impl Into<String>) -> Self {
39        Self {
40            name: name.into(),
41            tags: DependencyTag::RUNTIME,
42        }
43    }
44
45    pub fn new_with_tags(name: impl Into<String>, tags: DependencyTag) -> Self {
46        Self {
47            name: name.into(),
48            tags,
49        }
50    }
51}
52
53pub trait DependencyExt {
54    fn filter_by_tags(&self, include: DependencyTag, exclude: DependencyTag) -> Vec<&Dependency>;
55    fn runtime(&self) -> Vec<&Dependency>;
56    fn build_time(&self) -> Vec<&Dependency>;
57}
58
59impl DependencyExt for Vec<Dependency> {
60    fn filter_by_tags(&self, include: DependencyTag, exclude: DependencyTag) -> Vec<&Dependency> {
61        self.iter()
62            .filter(|dep| dep.tags.contains(include) && !dep.tags.intersects(exclude))
63            .collect()
64    }
65
66    fn runtime(&self) -> Vec<&Dependency> {
67        // A dependency is runtime if its tags indicate it's needed at runtime.
68        // This includes standard runtime, recommended, or optional dependencies.
69        // Build-only or Test-only dependencies (without other runtime flags) are excluded.
70        self.iter()
71            .filter(|dep| {
72                dep.tags.intersects(
73                    DependencyTag::RUNTIME | DependencyTag::RECOMMENDED | DependencyTag::OPTIONAL,
74                )
75            })
76            .collect()
77    }
78
79    fn build_time(&self) -> Vec<&Dependency> {
80        self.filter_by_tags(DependencyTag::BUILD, DependencyTag::empty())
81    }
82}