(index<- )        ./libsyntax/crateid.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   1  // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  use std::fmt;
  12  
  13  /// CrateIds identify crates and include the crate name and optionally a path
  14  /// and version. In the full form, they look like relative URLs. Example:
  15  /// `github.com/mozilla/rust#std:1.0` would be a package ID with a path of
  16  /// `gitub.com/mozilla/rust` and a crate name of `std` with a version of
  17  /// `1.0`. If no crate name is given after the hash, the name is inferred to
  18  /// be the last component of the path. If no version is given, it is inferred
  19  /// to be `0.0`.
  20  
  21  use std::from_str::FromStr;
  22  
  23  #[deriving(Clone, Eq)]
  24  pub struct CrateId {
  25      /// A path which represents the codes origin. By convention this is the
  26      /// URL, without `http://` or `https://` prefix, to the crate's repository
  27      pub path: StrBuf,
  28      /// The name of the crate.
  29      pub name: StrBuf,
  30      /// The version of the crate.
  31      pub version: Option<StrBuf>,
  32  }
  33  
  34  impl fmt::Show for CrateId {
  35      fn fmt(&self, f&mut fmt::Formatter) -> fmt::Result {
  36          try!(write!(f.buf, "{}", self.path));
  37          let version = match self.version {
  38              None => "0.0",
  39              Some(ref version) => version.as_slice(),
  40          };
  41          if self.path == self.name ||
  42                  self.path.as_slice().ends_with(format!("/{}", self.name)) {
  43              write!(f.buf, "\\#{}", version)
  44          } else {
  45              write!(f.buf, "\\#{}:{}", self.name, version)
  46          }
  47      }
  48  }
  49  
  50  impl FromStr for CrateId {
  51      fn from_str(s&str) -> Option<CrateId> {
  52          let piecesVec<&str> = s.splitn('#', 1).collect();
  53          let path = pieces.get(0).to_owned();
  54  
  55          if path.starts_with("/") || path.ends_with("/") ||
  56              path.starts_with(".") || path.is_empty() {
  57              return None;
  58          }
  59  
  60          let path_piecesVec<&str> = path.rsplitn('/', 1).collect();
  61          let inferred_name = *path_pieces.get(0);
  62  
  63          let (name, version) = if pieces.len() == 1 {
  64              (inferred_name.to_strbuf(), None)
  65          } else {
  66              let hash_piecesVec<&str> = pieces.get(1)
  67                                                 .splitn(':', 1)
  68                                                 .collect();
  69              let (hash_name, hash_version) = if hash_pieces.len() == 1 {
  70                  ("", *hash_pieces.get(0))
  71              } else {
  72                  (*hash_pieces.get(0), *hash_pieces.get(1))
  73              };
  74  
  75              let name = if !hash_name.is_empty() {
  76                  hash_name.to_strbuf()
  77              } else {
  78                  inferred_name.to_strbuf()
  79              };
  80  
  81              let version = if !hash_version.is_empty() {
  82                  if hash_version == "0.0" {
  83                      None
  84                  } else {
  85                      Some(hash_version.to_strbuf())
  86                  }
  87              } else {
  88                  None
  89              };
  90  
  91              (name, version)
  92          };
  93  
  94          Some(CrateId {
  95              path: path.to_strbuf(),
  96              name: name,
  97              version: version,
  98          })
  99      }
 100  }
 101  
 102  impl CrateId {
 103      pub fn version_or_default<'a>(&'a self) -> &'a str {
 104          match self.version {
 105              None => "0.0",
 106              Some(ref version) => version.as_slice(),
 107          }
 108      }
 109  
 110      pub fn short_name_with_version(&self) -> StrBuf {
 111          (format!("{}-{}", self.name, self.version_or_default())).to_strbuf()
 112      }
 113  
 114      pub fn matches(&self, other&CrateId) -> bool {
 115          // FIXME: why does this not match on `path`?
 116          if self.name != other.name { return false }
 117          match (&self.version, &other.version) {
 118              (&Some(ref v1), &Some(ref v2)) => v1 == v2,
 119              _ => true,
 120          }
 121      }
 122  }
 123  
 124  #[test]
 125  fn bare_name() {
 126      let crateid: CrateId = from_str("foo").expect("valid crateid");
 127      assert_eq!(crateid.name, "foo".to_strbuf());
 128      assert_eq!(crateid.version, None);
 129      assert_eq!(crateid.path, "foo".to_strbuf());
 130  }
 131  
 132  #[test]
 133  fn bare_name_single_char() {
 134      let crateid: CrateId = from_str("f").expect("valid crateid");
 135      assert_eq!(crateid.name, "f".to_strbuf());
 136      assert_eq!(crateid.version, None);
 137      assert_eq!(crateid.path, "f".to_strbuf());
 138  }
 139  
 140  #[test]
 141  fn empty_crateid() {
 142      let crateid: Option<CrateId> = from_str("");
 143      assert!(crateid.is_none());
 144  }
 145  
 146  #[test]
 147  fn simple_path() {
 148      let crateid: CrateId = from_str("example.com/foo/bar").expect("valid crateid");
 149      assert_eq!(crateid.name, "bar".to_strbuf());
 150      assert_eq!(crateid.version, None);
 151      assert_eq!(crateid.path, "example.com/foo/bar".to_strbuf());
 152  }
 153  
 154  #[test]
 155  fn simple_version() {
 156      let crateid: CrateId = from_str("foo#1.0").expect("valid crateid");
 157      assert_eq!(crateid.name, "foo".to_strbuf());
 158      assert_eq!(crateid.version, Some("1.0".to_strbuf()));
 159      assert_eq!(crateid.path, "foo".to_strbuf());
 160  }
 161  
 162  #[test]
 163  fn absolute_path() {
 164      let crateid: Option<CrateId> = from_str("/foo/bar");
 165      assert!(crateid.is_none());
 166  }
 167  
 168  #[test]
 169  fn path_ends_with_slash() {
 170      let crateid: Option<CrateId> = from_str("foo/bar/");
 171      assert!(crateid.is_none());
 172  }
 173  
 174  #[test]
 175  fn path_and_version() {
 176      let crateid: CrateId = from_str("example.com/foo/bar#1.0").expect("valid crateid");
 177      assert_eq!(crateid.name, "bar".to_strbuf());
 178      assert_eq!(crateid.version, Some("1.0".to_strbuf()));
 179      assert_eq!(crateid.path, "example.com/foo/bar".to_strbuf());
 180  }
 181  
 182  #[test]
 183  fn single_chars() {
 184      let crateid: CrateId = from_str("a/b#1").expect("valid crateid");
 185      assert_eq!(crateid.name, "b".to_strbuf());
 186      assert_eq!(crateid.version, Some("1".to_strbuf()));
 187      assert_eq!(crateid.path, "a/b".to_strbuf());
 188  }
 189  
 190  #[test]
 191  fn missing_version() {
 192      let crateid: CrateId = from_str("foo#").expect("valid crateid");
 193      assert_eq!(crateid.name, "foo".to_strbuf());
 194      assert_eq!(crateid.version, None);
 195      assert_eq!(crateid.path, "foo".to_strbuf());
 196  }
 197  
 198  #[test]
 199  fn path_and_name() {
 200      let crateid: CrateId = from_str("foo/rust-bar#bar:1.0").expect("valid crateid");
 201      assert_eq!(crateid.name, "bar".to_strbuf());
 202      assert_eq!(crateid.version, Some("1.0".to_strbuf()));
 203      assert_eq!(crateid.path, "foo/rust-bar".to_strbuf());
 204  }
 205  
 206  #[test]
 207  fn empty_name() {
 208      let crateid: CrateId = from_str("foo/bar#:1.0").expect("valid crateid");
 209      assert_eq!(crateid.name, "bar".to_strbuf());
 210      assert_eq!(crateid.version, Some("1.0".to_strbuf()));
 211      assert_eq!(crateid.path, "foo/bar".to_strbuf());
 212  }