use crate::errors::ParserError;
use crate::parsed::Parsed;
use crate::Message;
use std::collections::HashMap;
use std::convert::TryFrom;
use std::str::FromStr;
#[derive(Debug, Clone, Eq, PartialEq, Default)]
pub struct Builder {
tags: HashMap<String, String>,
prefix_name: Option<String>,
prefix_user: Option<String>,
prefix_host: Option<String>,
command: String,
params: Vec<String>,
trailing: Option<String>,
}
impl Builder {
pub fn new<S: ToString>(command: S) -> Self {
Builder {
tags: HashMap::new(),
prefix_name: None,
prefix_user: None,
prefix_host: None,
command: "".to_string(),
params: Vec::new(),
trailing: None,
}
.command(command.to_string())
}
pub fn command<S: ToString>(mut self, cmd: S) -> Builder {
let cmd = cmd.to_string();
if cmd.is_empty() {
panic!("tried to set empty command");
}
self.command = cmd;
self
}
pub fn tag<SK: ToString, SV: ToString>(mut self, key: SK, value: SV) -> Builder {
let key = key.to_string();
if key.is_empty() {
panic!("tried to set tag with empty key");
}
self.tags.insert(key, value.to_string());
self
}
pub fn prefix<SN, SU, SH>(mut self, name: SN, user: Option<SU>, host: Option<SH>) -> Builder
where
SN: ToString,
SU: ToString,
SH: ToString,
{
let name = name.to_string();
if name.is_empty() {
panic!("tried to set empty prefix name");
}
let user = user.map(|user| user.to_string());
if user.is_some() && user.as_ref().unwrap().is_empty() {
panic!("tried to set empty prefix user");
}
let host = host.map(|host| host.to_string());
if host.is_some() && host.as_ref().unwrap().is_empty() {
panic!("tried to set empty prefix host");
}
if user.is_some() && host.is_none() {
panic!("tried to set prefix user without host");
}
self.prefix_name = Some(name);
self.prefix_user = user;
self.prefix_host = host;
self
}
pub fn param<S: ToString>(mut self, param: S) -> Builder {
let param = param.to_string();
if param.is_empty() {
panic!("tried to add empty param");
}
self.params.push(param);
self
}
pub fn set_param<S: ToString>(mut self, index: usize, param: S) -> Builder {
let param = param.to_string();
if param.is_empty() {
panic!("tried to set empty param");
}
if index >= self.params.len() {
self.params.push(param);
} else {
self.params[index] = param;
}
self
}
pub fn remove_param(mut self, index: usize) -> Builder {
if index < self.params.len() {
self.params.remove(index);
}
self
}
pub fn trailing<S: ToString>(mut self, trailing: S) -> Builder {
self.trailing = Some(trailing.to_string());
self
}
pub fn build(self) -> crate::message::Message {
let mut str = String::new();
if !self.tags.is_empty() {
str.push('@');
for (key, val) in self.tags {
str.push_str(key.as_str());
str.push('=');
str.push_str(val.as_str());
str.push(';')
}
str.pop();
str.push(' ');
}
if let Some(prefix_name) = self.prefix_name {
str.push(':');
str.push_str(prefix_name.as_str());
assert!(self.prefix_user.is_none() || self.prefix_host.is_some());
if let Some(user) = self.prefix_user {
str.push('!');
str.push_str(user.as_str());
}
if let Some(host) = self.prefix_host {
str.push('@');
str.push_str(host.as_str());
}
str.push(' ')
}
str.push_str(self.command.as_str());
if !self.params.is_empty() {
str.push(' ');
str.push_str(&self.params.join(" "));
}
if let Some(trailing) = self.trailing {
str.push_str(" :");
str.push_str(trailing.as_str());
}
crate::message::Message::from(str)
}
}
impl FromStr for Builder {
type Err = ParserError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parsed = Parsed::try_from(s)?;
let mut builder = Builder::new(parsed.command().ok_or(ParserError::NoCommand)?);
for (key, value) in parsed.tags() {
builder = builder.tag(key, value)
}
if let Some(&(name, user, host)) = parsed.prefix() {
builder = builder.prefix(name, user, host);
}
for param in parsed.params().flatten() {
builder = builder.param(param);
}
if let Some(trailing) = parsed.trailing() {
builder = builder.trailing(trailing);
}
Ok(builder)
}
}
impl TryFrom<Message> for Builder {
type Error = ParserError;
fn try_from(value: Message) -> Result<Self, Self::Error> {
value.to_builder()
}
}