spin_serde/
dependencies.rs1use crate::KebabId;
4use anyhow::anyhow;
5use schemars::JsonSchema;
6use serde::{Deserialize, Serialize};
7use std::str::FromStr;
8use wasm_pkg_common::package::PackageRef;
9
10#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
14#[serde(into = "String", try_from = "String")]
15pub struct DependencyPackageName {
16 pub package: PackageRef,
18 pub version: Option<semver::Version>,
20 pub interface: Option<KebabId>,
22}
23
24impl std::fmt::Display for DependencyPackageName {
25 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
26 write!(f, "{}", self.package)?;
27 if let Some(interface) = &self.interface {
28 write!(f, "/{interface}")?;
29 }
30 if let Some(version) = &self.version {
31 write!(f, "@{version}")?;
32 }
33 Ok(())
34 }
35}
36
37impl TryFrom<String> for DependencyPackageName {
38 type Error = anyhow::Error;
39
40 fn try_from(s: String) -> Result<Self, Self::Error> {
41 s.parse()
42 }
43}
44
45impl From<DependencyPackageName> for String {
46 fn from(value: DependencyPackageName) -> Self {
47 value.to_string()
48 }
49}
50
51impl FromStr for DependencyPackageName {
52 type Err = anyhow::Error;
53
54 fn from_str(s: &str) -> Result<Self, Self::Err> {
55 let (name, version) = match s.split_once('@') {
56 Some((name, version)) => (name, Some(version.parse()?)),
57 None => (s, None),
58 };
59
60 let (package, interface) = match name.split_once('/') {
61 Some((package, interface)) => (
62 package.parse()?,
63 Some(
64 interface
65 .to_string()
66 .try_into()
67 .map_err(|e| anyhow::anyhow!("{e}"))?,
68 ),
69 ),
70 None => (name.parse()?, None),
71 };
72
73 Ok(DependencyPackageName {
74 package,
75 version,
76 interface,
77 })
78 }
79}
80
81#[derive(
85 Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Hash, JsonSchema,
86)]
87#[serde(into = "String", try_from = "String")]
88#[schemars(with = "String")]
89pub enum DependencyName {
90 Plain(KebabId),
92 Package(DependencyPackageName),
94}
95
96impl std::fmt::Display for DependencyName {
97 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
98 match self {
99 DependencyName::Plain(plain) => write!(f, "{plain}"),
100 DependencyName::Package(name) => {
101 write!(f, "{}", name.package)?;
102 if let Some(interface) = &name.interface {
103 write!(f, "/{interface}")?;
104 }
105 if let Some(version) = &name.version {
106 write!(f, "@{version}")?;
107 }
108 Ok(())
109 }
110 }
111 }
112}
113
114impl TryFrom<String> for DependencyName {
115 type Error = anyhow::Error;
116
117 fn try_from(s: String) -> Result<Self, Self::Error> {
118 s.parse()
119 }
120}
121
122impl From<DependencyName> for String {
123 fn from(value: DependencyName) -> Self {
124 value.to_string()
125 }
126}
127
128impl FromStr for DependencyName {
129 type Err = anyhow::Error;
130
131 fn from_str(s: &str) -> Result<Self, Self::Err> {
132 if s.contains([':', '/']) {
133 Ok(Self::Package(s.parse()?))
134 } else {
135 Ok(Self::Plain(
136 s.to_string().try_into().map_err(|e| anyhow!("{e}"))?,
137 ))
138 }
139 }
140}
141
142impl DependencyName {
143 pub fn package(&self) -> Option<&PackageRef> {
145 match self {
146 DependencyName::Package(name) => Some(&name.package),
147 DependencyName::Plain(_) => None,
148 }
149 }
150}