oci_unpack/reference/
mediatype.rs1use std::{fmt, str::FromStr};
2
3macro_rules! media_types {
7 ($($variant:ident = $mediatype:expr,)*) => {
8 #[non_exhaustive]
10 #[derive(Copy, Clone, PartialEq, Debug)]
11 pub enum MediaType {
12 $(
13 #[doc = concat!("Variant for `", $mediatype, "`.")]
14 $variant,
15 )*
16 }
17
18 impl MediaType {
19 pub(crate) const ALL: &[&str] = &[ $($mediatype),* ];
21
22 pub fn as_str(&self) -> &'static str {
23 match self {
24 $(MediaType::$variant => $mediatype,)*
25 }
26 }
27 }
28
29 impl FromStr for MediaType {
30 type Err = InvalidMediaType;
31
32 fn from_str(s: &str) -> Result<Self, Self::Err> {
33 match s {
34 $($mediatype => Ok(MediaType::$variant),)*
35 _ => Err(InvalidMediaType),
36 }
37 }
38 }
39
40 impl fmt::Display for MediaType {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 f.write_str(self.as_str())
43 }
44 }
45 }
46}
47
48media_types!(
49 DockerFsTarGzip = "application/vnd.docker.image.rootfs.diff.tar.gzip",
50 DockerImageV1 = "application/vnd.docker.container.image.v1+json",
51 DockerManifestList = "application/vnd.docker.distribution.manifest.list.v2+json",
52 DockerManifestV2 = "application/vnd.docker.distribution.manifest.v2+json",
53 OciConfig = "application/vnd.oci.image.config.v1+json",
54 OciFsTar = "application/vnd.oci.image.layer.v1.tar",
55 OciFsTarGzip = "application/vnd.oci.image.layer.v1.tar+gzip",
56 OciFsTarZstd = "application/vnd.oci.image.layer.v1.tar+zstd",
57 OciImageIndex = "application/vnd.oci.image.index.v1+json",
58 OciManifestV1 = "application/vnd.oci.image.manifest.v1+json",
59);
60
61pub struct InvalidMediaType;
62
63struct MediaTypeVisitor;
64
65impl serde::de::Visitor<'_> for MediaTypeVisitor {
66 type Value = MediaType;
67
68 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
69 formatter.write_str("Media type for OCI/Docker objects.")
70 }
71
72 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
73 where
74 E: serde::de::Error,
75 {
76 MediaType::from_str(v).map_err(|_| E::custom(format!("Unknown type: {v}")))
77 }
78}
79
80impl<'de> serde::Deserialize<'de> for MediaType {
81 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
82 where
83 D: serde::Deserializer<'de>,
84 {
85 deserializer.deserialize_str(MediaTypeVisitor)
86 }
87}
88
89#[test]
90fn media_type_in_json() {
91 #[derive(serde::Deserialize, Debug)]
92 struct Example {
93 mt: MediaType,
94 }
95
96 assert!(matches!(
97 serde_json::from_str(r#"{"mt": "application/vnd.oci.image.index.v1+json"}"#),
98 Ok(Example {
99 mt: MediaType::OciImageIndex
100 })
101 ));
102}