Skip to main content

lib_humus/templating/
media_type.rs

1// SPDX-FileCopyrightText: 2026 Slatian <baschdel@disroot.org>
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5use std::{
6	fmt::Display,
7	ops::{Deref, DerefMut},
8	str::FromStr,
9};
10
11use mime::Mime;
12use serde::{Deserialize, Serialize};
13
14/// Represents a parsed and valid media type, uses the [mime] crate under the hood.
15#[derive(Debug, Clone)]
16pub struct MediaType(Mime);
17
18impl From<Mime> for MediaType {
19	fn from(value: Mime) -> Self {
20		Self(value)
21	}
22}
23
24impl From<MediaType> for Mime {
25	fn from(value: MediaType) -> Self {
26		value.0
27	}
28}
29
30impl FromStr for MediaType {
31	type Err = mime::FromStrError;
32
33	fn from_str(s: &str) -> Result<Self, Self::Err> {
34		Ok(Self(Mime::from_str(s)?))
35	}
36}
37
38impl Display for MediaType {
39	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40		self.0.fmt(f)
41	}
42}
43
44impl Deref for MediaType {
45	type Target = Mime;
46
47	fn deref(&self) -> &Self::Target {
48		&self.0
49	}
50}
51
52impl DerefMut for MediaType {
53	fn deref_mut(&mut self) -> &mut Self::Target {
54		&mut self.0
55	}
56}
57
58impl Serialize for MediaType {
59	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
60	where
61		S: serde::Serializer,
62	{
63		serializer.serialize_str(self.0.as_ref())
64	}
65}
66
67struct MediaTypeVisitor;
68
69impl<'de> serde::de::Visitor<'de> for MediaTypeVisitor {
70	type Value = MediaType;
71
72	fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
73		write!(formatter, "A well formed media type/mimetype")
74	}
75
76	fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
77	where
78		E: serde::de::Error,
79	{
80		Mime::from_str(v)
81			.map(MediaType)
82			.map_err(|e| E::custom(format!("Problem parsing media type: {e}")))
83	}
84}
85
86impl<'de> Deserialize<'de> for MediaType {
87	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
88	where
89		D: serde::Deserializer<'de>,
90	{
91		deserializer.deserialize_string(MediaTypeVisitor)
92	}
93}