git-gemini-forge 0.5.2

A simple Gemini server that serves a read-only view of public repositories from a Git forge.
use serde::Deserialize;
use url::Url;

#[derive(Deserialize, Debug)]
pub struct ServerVersion {
	pub version: String,
}

#[derive(Deserialize, Debug)]
pub struct User {
	pub login: String,
}

#[cfg(test)]
impl User {
	/// Constructs a new [`User`] value.
	pub fn new<S: ToString>(login: S) -> Self {
		User {
			login: login.to_string(),
		}
	}
}

#[derive(Deserialize, Debug)]
pub struct UsersSearch {
	pub data: Vec<User>,
}

/// A [Newtype](https://rust-unofficial.github.io/patterns/patterns/behavioural/newtype.html) over `url::Url` that implements `serde::Deserialize`.
#[derive(Clone, Debug)]
pub struct JsonUrl(pub Url);

impl<'de> Deserialize<'de> for JsonUrl {
	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
	where
		D: serde::Deserializer<'de>,
	{
		// Based on https://amish.naidu.dev/blog/serde-deserialize/
		let url_string = String::deserialize(deserializer)?;
		return match Url::parse(&url_string) {
			Err(parse_error) => Err(serde::de::Error::invalid_value(
				serde::de::Unexpected::Str(&url_string),
				&format!("{parse_error}").as_str(),
			)),
			Ok(url) => Ok(JsonUrl(url)),
		};
	}
}

#[derive(Deserialize, Debug)]
pub struct Repo {
	pub default_branch: String,
	pub html_url: JsonUrl,
	pub name: String,
	pub owner: User,
	pub updated_at: String,
}

#[derive(Deserialize, Debug)]
pub struct RepoSearch {
	pub data: Vec<Repo>,
}

#[derive(Deserialize, Debug)]
pub struct Branch {
	pub name: String,
}

#[cfg(test)]
impl Branch {
	/// Constructs a new [`Branch`] value.
	pub fn new<S: ToString>(name: S) -> Self {
		Branch {
			name: name.to_string(),
		}
	}
}

#[derive(Deserialize, Debug)]
#[serde(rename_all = "lowercase")]
pub enum ContentsType {
	File,
	Dir,
	Symlink,
	Submodule,
}

#[derive(Deserialize, Debug)]
pub struct RepoContents {
	#[serde(rename = "type")]
	pub kind: ContentsType,
	pub content: Option<String>,
	pub name: String,
	pub path: String,
}