use std::{fmt::Display, io};
use thiserror::Error;
macro_rules! impl_tryfrom_update {
(@generate, $split:expr) => {{
let mut iter = $split;
match (iter.next(), iter.next(), iter.next()) {
(Some(u), Some(b), None) => Ok(Update {
username: u.to_owned(),
branch: b.to_owned(),
}),
(Some(_), Some(_), Some(_)) => Err(UpdateParseError::MismatchLength(3)),
(Some(_), None, _) => Err(UpdateParseError::MismatchLength(1)),
(None, ..) => Err(UpdateParseError::MismatchLength(0)),
}
}};
(file: $($type:ty),+ $(,)?) => {
$(
impl TryFrom<$type> for Update {
type Error = UpdateParseError;
fn try_from(value: $type) -> Result<Self, Self::Error> {
let contents = std::fs::read_to_string(value)?;
impl_tryfrom_update!(@generate, contents.split(' '))
}
}
)*
};
(direct: $($type:ty),+ $(,)?) => {
$(
impl TryFrom<$type> for Update {
type Error = UpdateParseError;
fn try_from(value: $type) -> Result<Self, Self::Error> {
impl_tryfrom_update!(@generate, value.split(' '))
}
}
)*
};
}
#[derive(PartialEq, Eq)]
pub struct Update {
username: String,
branch: String,
}
#[derive(Error, Debug)]
pub enum UpdateParseError {
#[error("io error")]
Io(#[from] io::Error),
#[error("invalid length of split, expected `2`, got `{0}`")]
MismatchLength(usize),
#[error("empty string")]
EmptyString,
}
impl Default for Update {
fn default() -> Self {
Self {
username: String::from("pacstall"),
branch: String::from("master"),
}
}
}
impl Display for Update {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} {}", self.username, self.branch)
}
}
impl_tryfrom_update!(file: &std::path::Path, std::path::PathBuf);
impl_tryfrom_update!(direct: &str, String);
impl Update {
pub fn new<S: Into<String>>(username: S, branch: S) -> Result<Self, UpdateParseError> {
let username = username.into();
let branch = branch.into();
if username.is_empty() || branch.is_empty() {
Err(UpdateParseError::EmptyString)
} else {
Ok(Self { username, branch })
}
}
#[must_use]
pub fn username(&self) -> &str {
&self.username
}
#[must_use]
pub fn branch(&self) -> &str {
&self.branch
}
pub fn set_username<S: Into<String>>(&mut self, new_username: S) {
self.username = new_username.into();
}
pub fn set_branch<S: Into<String>>(&mut self, new_branch: S) {
self.username = new_branch.into();
}
#[must_use]
pub fn into_master(self) -> Self {
Self {
username: self.username,
branch: String::from("master"),
}
}
#[must_use]
pub fn into_develop(self) -> Self {
Self {
username: self.username,
branch: String::from("develop"),
}
}
}