1use std::fmt;
2
3pub trait AsTarg {
5 fn as_targ(&self) -> Targ;
7}
8
9impl<T> AsTarg for T
10where
11 T: AsRef<str>,
12{
13 fn as_targ(&self) -> Targ {
14 Targ::from(self.as_ref())
15 }
16}
17
18#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Debug)]
20pub struct Target {
21 pub repo: Option<String>,
23 pub pkg: String,
25}
26
27impl AsTarg for Target {
28 fn as_targ(&self) -> Targ {
29 Targ::new(self.repo.as_deref(), &self.pkg)
30 }
31}
32
33impl Target {
34 pub fn new<S: Into<String>>(repo: Option<S>, pkg: S) -> Target {
36 Target {
37 repo: repo.map(Into::into),
38 pkg: pkg.into(),
39 }
40 }
41}
42
43#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug)]
45pub struct Targ<'a> {
46 pub repo: Option<&'a str>,
48 pub pkg: &'a str,
50}
51
52impl<'a> Targ<'a> {
53 pub fn new(repo: Option<&'a str>, pkg: &'a str) -> Targ<'a> {
55 Targ { repo, pkg }
56 }
57}
58
59impl<'a> AsTarg for Targ<'a> {
60 fn as_targ(&self) -> Targ {
61 *self
62 }
63}
64
65impl<'a, S: AsRef<str> + ?Sized> From<&'a S> for Targ<'a> {
66 fn from(s: &'a S) -> Self {
67 let mut split = s.as_ref().split('/');
68 let first = split.next().unwrap();
69 let repo;
70 let pkg;
71
72 if let Some(p) = split.next() {
73 repo = Some(first);
74 pkg = p;
75 } else {
76 repo = None;
77 pkg = first;
78 }
79
80 Targ { repo, pkg }
81 }
82}
83
84impl<'a> fmt::Display for Targ<'a> {
85 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
86 if let Some(repo) = self.repo {
87 write!(fmt, "{}/{}", repo, self.pkg)
88 } else {
89 write!(fmt, "{}", self.pkg)
90 }
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn test_target() {
100 let pkg = "repo/pkg";
101 let pkg2 = String::from("pkg2");
102
103 let target = Targ::from(pkg);
104 let target2 = Targ::from(pkg2.as_str());
105
106 assert_eq!(target.repo, Some("repo"));
107 assert_eq!(target.pkg, "pkg");
108 assert_eq!(target2.repo, None);
109 assert_eq!(target2.pkg, "pkg2");
110 }
111}