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
use super::{
    error::VersionParseError,
    version::{Op, Version, VersionReq, VersionSpec},
};

impl From<semver::Version> for Version {
    fn from(value: semver::Version) -> Self {
        Self {
            major: value.major,
            minor: value.minor,
            patch: value.patch,
        }
    }
}

impl From<Version> for semver::Version {
    fn from(value: Version) -> Self {
        Self::new(value.major, value.minor, value.patch)
    }
}

impl TryFrom<semver::Op> for Op {
    type Error = VersionParseError;

    fn try_from(value: semver::Op) -> Result<Self, Self::Error> {
        match value {
            semver::Op::Exact => Ok(Op::Exact),
            semver::Op::Greater => Ok(Op::Greater),
            semver::Op::GreaterEq => Ok(Op::GreaterEq),
            semver::Op::Less => Ok(Op::Less),
            semver::Op::LessEq => Ok(Op::LessEq),
            _ => Err(VersionParseError::InvalidOp),
        }
    }
}

impl From<Op> for semver::Op {
    fn from(value: Op) -> Self {
        match value {
            Op::Exact => semver::Op::Exact,
            Op::Greater => semver::Op::Greater,
            Op::GreaterEq => semver::Op::GreaterEq,
            Op::Less => semver::Op::Less,
            Op::LessEq => semver::Op::LessEq,
        }
    }
}

impl TryFrom<semver::VersionReq> for VersionReq {
    type Error = VersionParseError;

    fn try_from(value: semver::VersionReq) -> Result<Self, Self::Error> {
        if value == semver::VersionReq::STAR {
            return Ok(VersionReq::Latest);
        }
        if value.comparators.is_empty() {
            return Ok(VersionReq::Latest);
        }

        let spec = value.try_into()?;

        Ok(VersionReq::Spec(spec))
    }
}

impl From<VersionReq> for semver::VersionReq {
    fn from(value: VersionReq) -> Self {
        match value {
            VersionReq::Latest => semver::VersionReq::STAR,
            VersionReq::Spec(spec) => spec.into(),
        }
    }
}

impl TryFrom<semver::VersionReq> for VersionSpec {
    type Error = VersionParseError;

    fn try_from(value: semver::VersionReq) -> Result<Self, Self::Error> {
        if value.comparators.is_empty() {
            return Err(VersionParseError::IncompatibleSemverReq);
        }

        if value.comparators.len() > 1 {
            return Err(VersionParseError::IncompatibleSemverReq);
        }

        let comp = &value.comparators[0];
        let op = comp.op.try_into()?;
        let major = comp.major;
        let minor = comp.minor.ok_or(VersionParseError::IncompatibleSemverReq)?;
        let patch = comp.patch.ok_or(VersionParseError::IncompatibleSemverReq)?;
        let version = Version::new(major, minor, patch);
        Ok(VersionSpec { op, version })
    }
}

impl From<VersionSpec> for semver::VersionReq {
    fn from(value: VersionSpec) -> Self {
        semver::VersionReq {
            comparators: vec![semver::Comparator {
                op: value.op.into(),
                major: value.version.major,
                minor: Some(value.version.minor),
                patch: Some(value.version.patch),
                pre: semver::Prerelease::EMPTY,
            }],
        }
    }
}