an http based roguelike rpg about jelqing
| 1 | use std::fmt; |
| 2 | |
| 3 | pub const REL_BASE: &str = "https://jelq.dev/rels/"; |
| 4 | |
| 5 | enum Rel<'a> { |
| 6 | Jelq(&'a str), |
| 7 | Registered(&'a str), |
| 8 | } |
| 9 | |
| 10 | /// One RFC 8288 link. `allow`, `lubricant` and `intensity` are extension attributes (§3), so a client never |
| 11 | /// has to guess what a target accepts. |
| 12 | pub struct Link<'a> { |
| 13 | href: &'a str, |
| 14 | rel: Rel<'a>, |
| 15 | title: Option<&'a str>, |
| 16 | allow: Option<&'a str>, |
| 17 | lubricant: Option<&'a str>, |
| 18 | intensity: Option<&'a str>, |
| 19 | } |
| 20 | |
| 21 | impl<'a> Link<'a> { |
| 22 | fn new(href: &'a str, rel: Rel<'a>) -> Self { |
| 23 | Self { |
| 24 | href, |
| 25 | rel, |
| 26 | title: None, |
| 27 | allow: None, |
| 28 | lubricant: None, |
| 29 | intensity: None, |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | /// A relation of this game's own, named under `REL_BASE`. |
| 34 | pub fn jelq(href: &'a str, rel: &'a str) -> Self { |
| 35 | Self::new(href, Rel::Jelq(rel)) |
| 36 | } |
| 37 | |
| 38 | /// A relation from the IANA registry, such as `next` or `alternate`. |
| 39 | pub fn registered(href: &'a str, rel: &'a str) -> Self { |
| 40 | Self::new(href, Rel::Registered(rel)) |
| 41 | } |
| 42 | |
| 43 | pub fn title(self, title: &'a str) -> Self { |
| 44 | Self { |
| 45 | title: Some(title), |
| 46 | ..self |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | pub fn allow(self, allow: &'a str) -> Self { |
| 51 | Self { |
| 52 | allow: Some(allow), |
| 53 | ..self |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | pub fn lubricant(self, lubricant: Option<&'a str>) -> Self { |
| 58 | Self { lubricant, ..self } |
| 59 | } |
| 60 | |
| 61 | pub fn intensity(self, intensity: Option<&'a str>) -> Self { |
| 62 | Self { intensity, ..self } |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | impl fmt::Display for Link<'_> { |
| 67 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 68 | write!(f, "<{}>; rel=\"", self.href)?; |
| 69 | match self.rel { |
| 70 | Rel::Jelq(rel) => write!(f, "{REL_BASE}{rel}\"")?, |
| 71 | Rel::Registered(rel) => write!(f, "{rel}\"")?, |
| 72 | } |
| 73 | for (name, value) in [ |
| 74 | ("title", self.title), |
| 75 | ("allow", self.allow), |
| 76 | ("lubricant", self.lubricant), |
| 77 | ("intensity", self.intensity), |
| 78 | ] { |
| 79 | if let Some(value) = value { |
| 80 | write!(f, "; {name}=\"{value}\"")?; |
| 81 | } |
| 82 | } |
| 83 | Ok(()) |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | /// A `Link` header value listing every link in order. |
| 88 | pub fn join<'a>(links: impl IntoIterator<Item = Link<'a>>) -> String { |
| 89 | links |
| 90 | .into_iter() |
| 91 | .map(|link| link.to_string()) |
| 92 | .collect::<Vec<_>>() |
| 93 | .join(", ") |
| 94 | } |