breb 0.5.0

the blog/reblog library and command-line tool
Documentation
use std::borrow::Cow;

/// the mime type of a file (i.e. at a [`Url`][crate::serve::Url])
#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
pub struct Mime(pub Cow<'static, str>);

impl Mime {
	/// arbitrary mime type from a fixed string
	///
	/// this exists just to give the const-initialization a shorthand;
	/// if you need to create a `Mime` at runtime, you can use its `From<impl Into<Cow<'static, str>>>` impl.
	pub const fn of(s: &'static str) -> Self {
		Self(Cow::Borrowed(s))
	}
}

macro_rules! define_mime {
	($($name:ident = $mime:literal $(($($ext:literal),+ $(,)?))?: $desc:literal),* $(,)?) => {
		impl Mime {
			$(
				#[doc = concat!("`", $mime, "`: ", $desc)]
				pub const $name: Self = Self::of($mime);
			)*

			/// guess the mime type based on a file extension
			///
			/// this is a generally unreliable way to do things.
			/// ideally, we would be introspecting the first few bytes of the file,
			/// and making an educated decision based on the magic bytes.
			/// but that's *far* more complex than this approach,
			/// and browsers will generally adapt *anyway*, so w/e.
			pub fn from_ext(ext: &str) -> Option<Self> {
				match ext {
					$( $( $(
						$ext => Some(Self::$name),
					)+ )? )*
					_ => None,
				}
			}
		}
	}
}
define_mime! {
	HTML = "text/html" ("html", "htm")       : "[hypertext markup language](https://html.spec.whatwg.org/multipage/)",
	CSS = "text/css" ("css")                 : "[cascading style sheets](https://www.w3.org/Style/CSS/)",
	JAVASCRIPT = "text/javascript" ("js")    : "[ecmascript (née javascript)](https://tc39.es/ecma262/)",
	XML = "application/xml" ("xml")          : "[extensible markup language](https://www.w3.org/TR/xml/)",
	RSS = "application/rss+xml" ("rss")      : "unofficially standardized 'real simple syndication'",
	ATOM = "application/atom+xml" ("atom")   : "[atom syndication format](https://datatracker.ietf.org/doc/html/rfc4287)",
	JSON = "application/json" ("json")       : "[javascript object notation](https://datatracker.ietf.org/doc/html/rfc8259)",
	PNG = "image/png" ("png")                : "[portable network graphics](https://www.w3.org/TR/png/)",
	JPEG = "image/jpeg" ("jpeg")             : "[jpeg file interchange format](file:///home/user/Downloads/T-REC-T.871-201105-I!!PDF-E.pdf)",
	GIF = "image/gif" ("gif")                : "[graphics interchange format](https://www.w3.org/Graphics/GIF/spec-gif89a.txt)",
	SVG = "image/svg" ("svg")                : "[scalable vector graphics](https://www.w3.org/TR/SVG/)",
	ICO = "image/vnd.microsoft.icon" ("ico") : "corporate icon format",
	WOFF = "font/woff" ("woff")              : "[web open format font v1.0](https://www.w3.org/TR/WOFF/)",
	WOFF2 = "font/woff2" ("woff2")           : "[web open format font v2.0](https://www.w3.org/TR/WOFF2/)",
	TTF = "font/ttf" ("ttf")                 : "corporate font format",
	OTF = "font/otf" ("otf")                 : "corporate font format",
	BYTES = "application/octet-stream"       : "Arbitrary bytes, and the default for unknown data",
}

impl From<String> for Mime {
	fn from(value: String) -> Self {
		Self(value.into())
	}
}
impl From<&'static str> for Mime {
	fn from(value: &'static str) -> Self {
		Self(value.into())
	}
}

impl From<Mime> for Cow<'static, str> {
	fn from(val: Mime) -> Self {
		val.0
	}
}
impl From<&Mime> for Cow<'static, str> {
	fn from(val: &Mime) -> Self {
		val.0.clone()
	}
}