aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/package/link.rs
blob: e41d4316acd4a4f3414b58d4fc26eee3a6ef2026 (plain)
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! ref: composer/src/Composer/Package/Link.php

use shirabe_php_shim::UnexpectedValueException;
use shirabe_semver::constraint::constraint_interface::ConstraintInterface;

use crate::package::package_interface::PackageInterface;

pub struct Link {
    pub(crate) source: String,
    pub(crate) target: String,
    pub(crate) constraint: Box<dyn ConstraintInterface>,
    pub(crate) description: String,
    pub(crate) pretty_constraint: Option<String>,
}

impl Clone for Link {
    fn clone(&self) -> Self {
        // TODO(phase-b): Link is a PHP class; this clone is a shallow placeholder until
        // Link is shared via Rc<Link>.
        Self {
            source: self.source.clone(),
            target: self.target.clone(),
            constraint: self.constraint.clone_box(),
            description: self.description.clone(),
            pretty_constraint: self.pretty_constraint.clone(),
        }
    }
}

impl std::fmt::Debug for Link {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Link")
            .field("source", &self.source)
            .field("target", &self.target)
            .field("description", &self.description)
            .field("pretty_constraint", &self.pretty_constraint)
            .finish()
    }
}

impl Link {
    pub const TYPE_REQUIRE: &'static str = "requires";
    pub const TYPE_DEV_REQUIRE: &'static str = "devRequires";
    pub const TYPE_PROVIDE: &'static str = "provides";
    pub const TYPE_CONFLICT: &'static str = "conflicts";
    pub const TYPE_REPLACE: &'static str = "replaces";

    /// Special type
    pub const TYPE_DOES_NOT_REQUIRE: &'static str = "does not require";

    const TYPE_UNKNOWN: &'static str = "relates to";

    pub fn types() -> Vec<&'static str> {
        vec![
            Self::TYPE_REQUIRE,
            Self::TYPE_DEV_REQUIRE,
            Self::TYPE_PROVIDE,
            Self::TYPE_CONFLICT,
            Self::TYPE_REPLACE,
        ]
    }

    pub fn new(
        source: String,
        target: String,
        constraint: Box<dyn ConstraintInterface>,
        description: Option<String>,
        pretty_constraint: Option<String>,
    ) -> Self {
        let description = description.unwrap_or_else(|| Self::TYPE_UNKNOWN.to_string());
        let description = if description == Self::TYPE_DEV_REQUIRE {
            "requires (for development)".to_string()
        } else {
            description
        };
        Self {
            source: source.to_lowercase(),
            target: target.to_lowercase(),
            constraint,
            description,
            pretty_constraint,
        }
    }

    pub fn get_description(&self) -> &str {
        &self.description
    }

    pub fn get_source(&self) -> &str {
        &self.source
    }

    pub fn get_target(&self) -> &str {
        &self.target
    }

    pub fn get_constraint(&self) -> &dyn ConstraintInterface {
        &*self.constraint
    }

    pub fn get_pretty_constraint(&self) -> anyhow::Result<&str> {
        match &self.pretty_constraint {
            None => Err(anyhow::anyhow!(UnexpectedValueException {
                message: format!(
                    "Link {} has been misconfigured and had no prettyConstraint given.",
                    self.to_string()
                ),
                code: 0,
            })),
            Some(s) => Ok(s.as_str()),
        }
    }

    pub fn to_string(&self) -> String {
        format!(
            "{} {} {} ({})",
            self.source, self.description, self.target, self.constraint
        )
    }

    pub fn get_pretty_string(&self, source_package: &dyn PackageInterface) -> String {
        format!(
            "{} {} {} {}",
            source_package.get_pretty_string(),
            self.description,
            self.target,
            self.constraint.get_pretty_string()
        )
    }
}