spin_serde/
dependencies.rs1use crate::KebabId;
4use anyhow::anyhow;
5use serde::{Deserialize, Serialize};
6use std::str::FromStr;
7use wasm_pkg_common::package::PackageRef;
8
9#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)]
13#[serde(into = "String", try_from = "String")]
14pub struct DependencyPackageName {
15 pub package: PackageRef,
17 pub version: Option<semver::Version>,
19 pub interface: Option<KebabId>,
21}
22
23impl std::fmt::Display for DependencyPackageName {
24 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
25 write!(f, "{}", self.package)?;
26 if let Some(interface) = &self.interface {
27 write!(f, "/{interface}")?;
28 }
29 if let Some(version) = &self.version {
30 write!(f, "@{version}")?;
31 }
32 Ok(())
33 }
34}
35
36impl TryFrom<String> for DependencyPackageName {
37 type Error = anyhow::Error;
38
39 fn try_from(s: String) -> Result<Self, Self::Error> {
40 s.parse()
41 }
42}
43
44impl From<DependencyPackageName> for String {
45 fn from(value: DependencyPackageName) -> Self {
46 value.to_string()
47 }
48}
49
50impl FromStr for DependencyPackageName {
51 type Err = anyhow::Error;
52
53 fn from_str(s: &str) -> Result<Self, Self::Err> {
54 let (name, version) = match s.split_once('@') {
55 Some((name, version)) => (name, Some(version.parse()?)),
56 None => (s, None),
57 };
58
59 let (package, interface) = match name.split_once('/') {
60 Some((package, interface)) => (
61 package.parse()?,
62 Some(
63 interface
64 .to_string()
65 .try_into()
66 .map_err(|e| anyhow::anyhow!("{e}"))?,
67 ),
68 ),
69 None => (name.parse()?, None),
70 };
71
72 Ok(DependencyPackageName {
73 package,
74 version,
75 interface,
76 })
77 }
78}
79
80#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)]
84#[serde(into = "String", try_from = "String")]
85pub enum DependencyName {
86 Plain(KebabId),
88 Package(DependencyPackageName),
90}
91
92impl PartialOrd for DependencyName {
94 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
95 Some(self.cmp(other))
96 }
97}
98
99impl Ord for DependencyName {
101 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
102 match (self, other) {
103 (DependencyName::Plain(a), DependencyName::Plain(b)) => a.cmp(b),
104 (DependencyName::Package(a), DependencyName::Package(b)) => {
105 let big_ole_tup = (
106 a.package.namespace().as_ref(),
107 a.package.name().as_ref(),
108 a.interface.as_ref(),
109 a.version.as_ref(),
110 );
111 let other_big_ole_tup = (
112 b.package.namespace().as_ref(),
113 b.package.name().as_ref(),
114 b.interface.as_ref(),
115 b.version.as_ref(),
116 );
117 big_ole_tup.cmp(&other_big_ole_tup)
118 }
119 (DependencyName::Plain(_), DependencyName::Package(_)) => std::cmp::Ordering::Less,
120 (DependencyName::Package(_), DependencyName::Plain(_)) => std::cmp::Ordering::Greater,
121 }
122 }
123}
124
125impl std::fmt::Display for DependencyName {
126 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
127 match self {
128 DependencyName::Plain(plain) => write!(f, "{plain}"),
129 DependencyName::Package(name) => {
130 write!(f, "{}", name.package)?;
131 if let Some(interface) = &name.interface {
132 write!(f, "/{interface}")?;
133 }
134 if let Some(version) = &name.version {
135 write!(f, "@{version}")?;
136 }
137 Ok(())
138 }
139 }
140 }
141}
142
143impl TryFrom<String> for DependencyName {
144 type Error = anyhow::Error;
145
146 fn try_from(s: String) -> Result<Self, Self::Error> {
147 s.parse()
148 }
149}
150
151impl From<DependencyName> for String {
152 fn from(value: DependencyName) -> Self {
153 value.to_string()
154 }
155}
156
157impl FromStr for DependencyName {
158 type Err = anyhow::Error;
159
160 fn from_str(s: &str) -> Result<Self, Self::Err> {
161 if s.contains([':', '/']) {
162 Ok(Self::Package(s.parse()?))
163 } else {
164 Ok(Self::Plain(
165 s.to_string().try_into().map_err(|e| anyhow!("{e}"))?,
166 ))
167 }
168 }
169}
170
171impl DependencyName {
172 pub fn package(&self) -> Option<&PackageRef> {
174 match self {
175 DependencyName::Package(name) => Some(&name.package),
176 DependencyName::Plain(_) => None,
177 }
178 }
179}