1mod annotations;
4mod artifact;
5mod config;
6mod descriptor;
7mod digest;
8mod index;
9mod manifest;
10mod oci_layout;
11mod version;
12
13use std::fmt::Display;
14
15use serde::{Deserialize, Serialize};
16
17pub use annotations::*;
18pub use artifact::*;
19pub use config::*;
20pub use descriptor::*;
21pub use digest::*;
22pub use index::*;
23pub use manifest::*;
24pub use oci_layout::*;
25pub use version::*;
26
27#[derive(Clone, Debug, PartialEq, Eq)]
30pub enum MediaType {
31 Descriptor,
33 LayoutHeader,
35 ImageManifest,
37 ImageIndex,
39 ImageLayer,
42 ImageLayerGzip,
45 ImageLayerZstd,
48 ImageLayerNonDistributable,
51 ImageLayerNonDistributableGzip,
55 ImageLayerNonDistributableZstd,
59 ImageConfig,
62 ArtifactManifest,
65 EmptyJSON,
70 Other(String),
72}
73
74impl Display for MediaType {
75 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76 write!(f, "{}", self.as_ref())
77 }
78}
79
80impl From<&str> for MediaType {
81 fn from(media_type: &str) -> Self {
82 match media_type {
83 "application/vnd.oci.descriptor" => MediaType::Descriptor,
84 "application/vnd.oci.layout.header.v1+json" => MediaType::LayoutHeader,
85 "application/vnd.oci.image.manifest.v1+json" => MediaType::ImageManifest,
86 "application/vnd.oci.image.index.v1+json" => MediaType::ImageIndex,
87 "application/vnd.oci.image.layer.v1.tar" => MediaType::ImageLayer,
88 "application/vnd.oci.image.layer.v1.tar+gzip" => MediaType::ImageLayerGzip,
89 "application/vnd.oci.image.layer.v1.tar+zstd" => MediaType::ImageLayerZstd,
90 "application/vnd.oci.image.layer.nondistributable.v1.tar" => {
91 MediaType::ImageLayerNonDistributable
92 }
93 "application/vnd.oci.image.layer.nondistributable.v1.tar+gzip" => {
94 MediaType::ImageLayerNonDistributableGzip
95 }
96 "application/vnd.oci.image.layer.nondistributable.v1.tar+zstd" => {
97 MediaType::ImageLayerNonDistributableZstd
98 }
99 "application/vnd.oci.image.config.v1+json" => MediaType::ImageConfig,
100 "application/vnd.oci.artifact.manifest.v1+json" => MediaType::ArtifactManifest,
101 "application/vnd.oci.empty.v1+json" => MediaType::EmptyJSON,
102 media => MediaType::Other(media.to_owned()),
103 }
104 }
105}
106
107impl From<MediaType> for String {
108 fn from(media_type: MediaType) -> Self {
109 media_type.as_ref().to_owned()
110 }
111}
112
113impl AsRef<str> for MediaType {
114 fn as_ref(&self) -> &str {
115 match self {
116 Self::Descriptor => "application/vnd.oci.descriptor",
117 Self::LayoutHeader => "application/vnd.oci.layout.header.v1+json",
118 Self::ImageManifest => "application/vnd.oci.image.manifest.v1+json",
119 Self::ImageIndex => "application/vnd.oci.image.index.v1+json",
120 Self::ImageLayer => "application/vnd.oci.image.layer.v1.tar",
121 Self::ImageLayerGzip => "application/vnd.oci.image.layer.v1.tar+gzip",
122 Self::ImageLayerZstd => "application/vnd.oci.image.layer.v1.tar+zstd",
123 Self::ImageLayerNonDistributable => {
124 "application/vnd.oci.image.layer.nondistributable.v1.tar"
125 }
126 Self::ImageLayerNonDistributableGzip => {
127 "application/vnd.oci.image.layer.nondistributable.v1.tar+gzip"
128 }
129 Self::ImageLayerNonDistributableZstd => {
130 "application/vnd.oci.image.layer.nondistributable.v1.tar+zstd"
131 }
132 Self::ImageConfig => "application/vnd.oci.image.config.v1+json",
133 Self::ArtifactManifest => "application/vnd.oci.artifact.manifest.v1+json",
134 Self::EmptyJSON => "application/vnd.oci.empty.v1+json",
135 Self::Other(media_type) => media_type.as_str(),
136 }
137 }
138}
139
140pub trait ToDockerV2S2 {
148 fn to_docker_v2s2(&self) -> Result<&str, std::fmt::Error>;
151}
152
153impl ToDockerV2S2 for MediaType {
154 fn to_docker_v2s2(&self) -> Result<&str, std::fmt::Error> {
155 Ok(match self {
156 Self::ImageIndex => "application/vnd.docker.distribution.manifest.list.v2+json",
157 Self::ImageManifest => "application/vnd.docker.distribution.manifest.v2+json",
158 Self::ImageConfig => "application/vnd.docker.container.image.v1+json",
159 Self::ImageLayerGzip => "application/vnd.docker.image.rootfs.diff.tar.gzip",
160 _ => return Err(std::fmt::Error),
161 })
162 }
163}
164
165impl Serialize for MediaType {
166 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
167 where
168 S: serde::Serializer,
169 {
170 let media_type = format!("{self}");
171 media_type.serialize(serializer)
172 }
173}
174
175impl<'de> Deserialize<'de> for MediaType {
176 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
177 where
178 D: serde::Deserializer<'de>,
179 {
180 let media_type = String::deserialize(deserializer)?;
181 Ok(media_type.as_str().into())
182 }
183}
184
185#[allow(missing_docs)]
187#[derive(Clone, Debug, PartialEq, Eq)]
188pub enum Os {
189 AIX,
190 Android,
191 Darwin,
192 DragonFlyBSD,
193 FreeBSD,
194 Hurd,
195 Illumos,
196 #[allow(non_camel_case_types)]
197 iOS,
198 Js,
199 Linux,
200 Nacl,
201 NetBSD,
202 OpenBSD,
203 Plan9,
204 Solaris,
205 Windows,
206 #[allow(non_camel_case_types)]
207 zOS,
208 Other(String),
209}
210
211impl From<&str> for Os {
212 fn from(os: &str) -> Self {
213 match os {
214 "aix" => Os::AIX,
215 "android" => Os::Android,
216 "darwin" => Os::Darwin,
217 "dragonfly" => Os::DragonFlyBSD,
218 "freebsd" => Os::FreeBSD,
219 "hurd" => Os::Hurd,
220 "illumos" => Os::Illumos,
221 "ios" => Os::iOS,
222 "js" => Os::Js,
223 "linux" => Os::Linux,
224 "nacl" => Os::Nacl,
225 "netbsd" => Os::NetBSD,
226 "openbsd" => Os::OpenBSD,
227 "plan9" => Os::Plan9,
228 "solaris" => Os::Solaris,
229 "windows" => Os::Windows,
230 "zos" => Os::zOS,
231 name => Os::Other(name.to_owned()),
232 }
233 }
234}
235
236impl Display for Os {
237 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
238 let print = match self {
239 Os::AIX => "aix",
240 Os::Android => "android",
241 Os::Darwin => "darwin",
242 Os::DragonFlyBSD => "dragonfly",
243 Os::FreeBSD => "freebsd",
244 Os::Hurd => "hurd",
245 Os::Illumos => "illumos",
246 Os::iOS => "ios",
247 Os::Js => "js",
248 Os::Linux => "linux",
249 Os::Nacl => "nacl",
250 Os::NetBSD => "netbsd",
251 Os::OpenBSD => "openbsd",
252 Os::Plan9 => "plan9",
253 Os::Solaris => "solaris",
254 Os::Windows => "windows",
255 Os::zOS => "zos",
256 Os::Other(name) => name,
257 };
258
259 write!(f, "{print}")
260 }
261}
262
263impl Serialize for Os {
264 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
265 where
266 S: serde::Serializer,
267 {
268 let os = format!("{self}");
269 os.serialize(serializer)
270 }
271}
272
273impl<'de> Deserialize<'de> for Os {
274 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
275 where
276 D: serde::Deserializer<'de>,
277 {
278 let os = String::deserialize(deserializer)?;
279 Ok(os.as_str().into())
280 }
281}
282
283impl Default for Os {
284 fn default() -> Self {
285 Os::from(std::env::consts::OS)
286 }
287}
288
289#[derive(Clone, Debug, PartialEq, Eq)]
291pub enum Arch {
292 #[allow(non_camel_case_types)]
294 i386,
295 Amd64,
297 Amd64p32,
299 ARM,
301 ARMbe,
303 ARM64,
305 ARM64be,
307 LoongArch64,
309 Mips,
311 Mipsle,
313 Mips64,
315 Mips64le,
317 Mips64p32,
319 Mips64p32le,
321 PowerPC,
323 PowerPC64,
325 PowerPC64le,
327 RISCV,
329 RISCV64,
331 #[allow(non_camel_case_types)]
333 s390,
334 #[allow(non_camel_case_types)]
336 s390x,
337 SPARC,
339 SPARC64,
341 Wasm,
343 Other(String),
345}
346
347impl Display for Arch {
348 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
349 let print = match self {
350 Arch::i386 => "386",
351 Arch::Amd64 => "amd64",
352 Arch::Amd64p32 => "amd64p32",
353 Arch::ARM => "arm",
354 Arch::ARMbe => "armbe",
355 Arch::ARM64 => "arm64",
356 Arch::ARM64be => "arm64be",
357 Arch::LoongArch64 => "loong64",
358 Arch::Mips => "mips",
359 Arch::Mipsle => "mipsle",
360 Arch::Mips64 => "mips64",
361 Arch::Mips64le => "mips64le",
362 Arch::Mips64p32 => "mips64p32",
363 Arch::Mips64p32le => "mips64p32le",
364 Arch::PowerPC => "ppc",
365 Arch::PowerPC64 => "ppc64",
366 Arch::PowerPC64le => "ppc64le",
367 Arch::RISCV => "riscv",
368 Arch::RISCV64 => "riscv64",
369 Arch::s390 => "s390",
370 Arch::s390x => "s390x",
371 Arch::SPARC => "sparc",
372 Arch::SPARC64 => "sparc64",
373 Arch::Wasm => "wasm",
374 Arch::Other(arch) => arch,
375 };
376
377 write!(f, "{print}")
378 }
379}
380
381impl From<&str> for Arch {
382 fn from(arch: &str) -> Self {
383 match arch {
384 "386" => Arch::i386,
385 "amd64" => Arch::Amd64,
386 "amd64p32" => Arch::Amd64p32,
387 "arm" => Arch::ARM,
388 "armbe" => Arch::ARM64be,
389 "arm64" => Arch::ARM64,
390 "arm64be" => Arch::ARM64be,
391 "loong64" => Arch::LoongArch64,
392 "mips" => Arch::Mips,
393 "mipsle" => Arch::Mipsle,
394 "mips64" => Arch::Mips64,
395 "mips64le" => Arch::Mips64le,
396 "mips64p32" => Arch::Mips64p32,
397 "mips64p32le" => Arch::Mips64p32le,
398 "ppc" => Arch::PowerPC,
399 "ppc64" => Arch::PowerPC64,
400 "ppc64le" => Arch::PowerPC64le,
401 "riscv" => Arch::RISCV,
402 "riscv64" => Arch::RISCV64,
403 "s390" => Arch::s390,
404 "s390x" => Arch::s390x,
405 "sparc" => Arch::SPARC,
406 "sparc64" => Arch::SPARC64,
407 "wasm" => Arch::Wasm,
408 arch => Arch::Other(arch.to_owned()),
409 }
410 }
411}
412
413impl Serialize for Arch {
414 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
415 where
416 S: serde::Serializer,
417 {
418 let arch = format!("{self}");
419 arch.serialize(serializer)
420 }
421}
422
423impl<'de> Deserialize<'de> for Arch {
424 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
425 where
426 D: serde::Deserializer<'de>,
427 {
428 let arch = String::deserialize(deserializer)?;
429 Ok(arch.as_str().into())
430 }
431}
432
433impl Default for Arch {
434 fn default() -> Self {
435 let goarch = match std::env::consts::ARCH {
440 "x86_64" => "amd64",
441 "aarch64" => "arm64",
442 "powerpc64" if cfg!(target_endian = "big") => "ppc64",
443 "powerpc64" if cfg!(target_endian = "little") => "ppc64le",
444 o => o,
445 };
446 Arch::from(goarch)
447 }
448}
449
450#[cfg(test)]
451mod tests {
452 use super::*;
453
454 #[test]
455 fn test_arch_translation() {
456 let a = Arch::default();
457 if let Arch::Other(o) = a {
459 panic!("Architecture {o} not mapped between Rust and OCI")
460 }
461 }
462
463 #[test]
464 fn test_asref() {
465 assert_eq!(
467 MediaType::ImageConfig.as_ref(),
468 "application/vnd.oci.image.config.v1+json"
469 );
470 assert_eq!(
471 String::from(MediaType::ImageConfig).as_str(),
472 "application/vnd.oci.image.config.v1+json"
473 );
474 }
475}