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
//! Package dependencies

#[cfg(feature = "dependency-tree")]
pub mod graph;
#[cfg(feature = "dependency-tree")]
pub mod tree;

#[cfg(feature = "dependency-tree")]
pub use self::tree::Tree;

use crate::{
    error::{Error, ErrorKind},
    package::{Name, Package, Source},
};
use semver::Version;
use serde::{de, ser, Deserialize, Serialize};
use std::{fmt, str::FromStr};

/// Package dependencies
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct Dependency {
    /// Name of the dependency
    pub name: Name,

    /// Version of the dependency
    pub version: Option<Version>,

    /// Source for the dependency
    pub source: Option<Source>,
}

impl Dependency {
    /// Does the given [`Package`] exactly match this `Dependency`?
    pub fn matches(&self, package: &Package) -> bool {
        if self.name != package.name {
            return false;
        }

        if let Some(version) = &self.version {
            version == &package.version
        } else {
            true
        }
    }
}

impl fmt::Display for Dependency {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", &self.name)?;

        if let Some(version) = &self.version {
            write!(f, " {}", version)?;
        }

        if let Some(source) = &self.source {
            write!(f, " ({})", source)?;
        }

        Ok(())
    }
}

impl FromStr for Dependency {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self, Error> {
        let mut parts = s.split_whitespace();

        let name = parts
            .next()
            .ok_or_else(|| format_err!(ErrorKind::Parse, "empty dependency string"))?
            .parse()?;

        let version = parts.next().map(FromStr::from_str).transpose()?;

        let source = parts
            .next()
            .map(|s| {
                if s.len() < 2 || !s.starts_with('(') || !s.ends_with(')') {
                    Err(format_err!(
                        ErrorKind::Parse,
                        "malformed source in dependency: {}",
                        s
                    ))
                } else {
                    s[1..(s.len() - 1)].parse()
                }
            })
            .transpose()?;

        if parts.next().is_some() {
            fail!(ErrorKind::Parse, "malformed dependency: {}", s);
        }

        Ok(Self {
            name,
            version,
            source,
        })
    }
}

impl<'de> Deserialize<'de> for Dependency {
    fn deserialize<D: de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        use de::Error;
        String::deserialize(deserializer)
            .and_then(|ref s| Self::from_str(s).map_err(D::Error::custom))
    }
}

impl Serialize for Dependency {
    fn serialize<S: ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        self.to_string().serialize(serializer)
    }
}