iyzipay-rust 0.1.2

iyzipay rust client
Documentation
use std::ops::Deref;
use std::str;

use bigdecimal::BigDecimal;

const DOT: &'static str = ".";
const ZERO: &'static str = "0";
const COMMA: &'static str = ",";

pub trait PKISerialize {
    fn serialize(&self) -> Option<String>;
}

impl<T> PKISerialize for Vec<T>
where
    T: PKISerialize,
{
    fn serialize(&self) -> Option<String> {
        let mut ser = RequestStringBuilder::new();
        for val in self {
            let serialized: Option<String> = val.serialize();
            if serialized.is_some() {
                ser.append_raw(format!("{}, ", serialized.unwrap()));
            }
        }
        Option::from(ser.build(true))
    }
}

impl PKISerialize for Vec<u8> {
    fn serialize(&self) -> Option<String> {
        let mut ser = RequestStringBuilder::new();
        for val in self {
            ser.append_raw(format!("{}, ", val.to_string()));
        }
        Option::from(ser.build(true))
    }
}

impl<T> PKISerialize for Option<T>
where
    T: PKISerialize,
{
    fn serialize(&self) -> Option<String> {
        match self.as_ref() {
            Some(val) => val.serialize(),
            None => None,
        }
    }
}

pub trait RequestQueryParams {
    fn get_query_params(&self) -> String;
}

#[derive(Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Request {
    locale: Option<String>,

    conversation_id: Option<String>,
}

impl Request {
    pub fn new<T: Into<String>>(conversation_id: T, locale: T) -> Self {
        Request {
            conversation_id: Some(conversation_id.into()),
            locale: Some(locale.into()),
        }
    }

    pub fn set_conversation_id<T: Into<String>>(&mut self, conversation_id: T) {
        self.conversation_id = Some(conversation_id.into());
    }

    pub fn conversation_id(&self) -> Option<&String> {
        self.conversation_id.as_ref()
    }

    pub fn set_locale<T: Into<String>>(&mut self, locale: T) {
        self.locale = Some(locale.into());
    }

    pub fn locale(&self) -> Option<&String> {
        self.locale.as_ref()
    }
}

impl PKISerialize for Request {
    fn serialize(&self) -> Option<String> {
        let mut ser = RequestStringBuilder::new();
        ser.append_option("locale", self.locale.as_ref());
        ser.append_option("conversationId", self.conversation_id.as_ref());
        Option::from(ser.build(false))
    }
}

impl RequestQueryParams for Request {
    fn get_query_params(&self) -> String {
        let mut str = String::new();

        if self.conversation_id().is_some() {
            let val = self.conversation_id().unwrap();
            if !val.is_empty() {
                str.push_str(format!("{}={}", "?conversationId", val.as_str()).as_str());
            }
        }

        if self.conversation_id().is_some() {
            let val = self.locale().unwrap();
            if !val.is_empty() {
                str.push_str(format!("{}={}", "&locale", val.as_str()).as_str());
            }
        }
        str
    }
}

#[derive(Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PagingRequest {
    page: Option<u8>,

    count: Option<u8>,

    #[serde(flatten)]
    request: Request,
}

impl PagingRequest {
    pub fn new() -> Self {
        PagingRequest::default()
    }

    pub fn set_page<S: Into<Option<u8>>>(&mut self, page: S) {
        self.page = page.into();
    }

    pub fn page(&self) -> &Option<u8> {
        &self.page
    }

    pub fn set_count<S: Into<Option<u8>>>(&mut self, count: S) {
        self.count = count.into();
    }

    pub fn count(&self) -> &Option<u8> {
        &self.count
    }
}

impl PKISerialize for PagingRequest {
    fn serialize(&self) -> Option<String> {
        let mut ser = RequestStringBuilder::new();
        ser.append_option_val(self.request.serialize());
        ser.append(
            "page",
            str::from_utf8(&[self.page.unwrap_or_default()]).unwrap(),
        );
        ser.append(
            "count",
            str::from_utf8(&[self.count.unwrap_or_default()]).unwrap(),
        );
        Option::from(ser.build(true))
    }
}

impl RequestQueryParams for PagingRequest {
    fn get_query_params(&self) -> String {
        let parent_query_params = &self.deref().get_query_params();
        let mut str = String::new();

        if !parent_query_params.is_empty() {
            str.push_str(parent_query_params);
        }

        if self.page().is_some() {
            str.push_str(format!("{}={}", "&page", format!("{}", self.page.unwrap())).as_str());
        }

        if self.count().is_some() {
            str.push_str(format!("{}={}", "&count", format!("{}", self.count.unwrap())).as_str());
        }

        str
    }
}

impl std::ops::Deref for PagingRequest {
    type Target = Request;
    fn deref(&self) -> &Self::Target {
        &self.request
    }
}

impl std::ops::DerefMut for PagingRequest {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.request
    }
}

#[derive(Debug, Default)]
pub struct RequestStringBuilder(String);

impl RequestStringBuilder {
    pub fn new() -> Self {
        RequestStringBuilder::default()
    }

    pub fn append_raw<T: Into<String>>(&mut self, value: T) -> &mut Self {
        &mut self.0.push_str(value.into().as_str());
        self
    }

    pub fn append_raw_option<T: ::std::string::ToString>(&mut self, value: Option<T>) -> &mut Self {
        let val: Option<T> = value.into();
        if val.is_some() {
            self.append_raw(val.unwrap().to_string());
        }
        self
    }

    pub fn append_option_val<T: ::std::string::ToString>(&mut self, value: Option<T>) -> &mut Self {
        let val: Option<T> = value.into();
        if val.is_some() {
            self.append_raw(format!("{},", val.unwrap().to_string()).as_str());
        }
        self
    }

    pub fn append<T: Into<String>>(&mut self, key: T, value: T) -> &mut Self {
        let val = value.into();
        if !val.is_empty() {
            self.append_raw(format!("{}={},", key.into(), val).as_str());
        }
        self
    }

    pub fn append_option<T: Into<String>, S: ::std::string::ToString>(
        &mut self,
        key: T,
        value: Option<S>,
    ) -> &mut Self {
        let val: Option<S> = value.into();
        if val.is_some() {
            self.append_raw(format!("{}={},", key.into(), val.unwrap().to_string()).as_str());
        }
        self
    }

    pub fn append_price_option<T: Into<String>>(
        &mut self,
        key: T,
        value: Option<&BigDecimal>,
    ) -> &mut Self {
        let val: Option<&BigDecimal> = value.into();
        if val.is_some() {
            self.append_raw(
                format!(
                    "{}={},",
                    key.into(),
                    RequestFormatter::format_price(val.unwrap())
                )
                .as_str(),
            );
        }
        self
    }

    pub fn build(&mut self, prefix: bool) -> String {
        self.0 = self.0.trim().to_string();
        self.remove_prefix_comma();
        self.remove_trailing_comma();
        if prefix {
            self.append_prefix();
        }
        self.0.to_owned()
    }

    fn append_prefix(&mut self) {
        self.0 = format!("[{}]", self.0);
    }

    fn remove_trailing_comma(&mut self) {
        if self.0.ends_with(COMMA) {
            self.0.truncate(self.0.len() - 1);
        }
    }

    fn remove_prefix_comma(&mut self) {
        if self.0.starts_with(COMMA) {
            self.0.remove(0);
        }
    }
}

pub struct RequestFormatter;

impl RequestFormatter {
    pub fn format_price(price: &BigDecimal) -> String {
        let price_str = price.to_string();
        let mut formatted_price = String::from(price_str);

        if !formatted_price.contains(DOT) {
            formatted_price = format!("{}{}{}", formatted_price, DOT, 0);
        }

        formatted_price = String::from(formatted_price.trim_end_matches(ZERO));
        if formatted_price.ends_with(DOT) {
            formatted_price = format!("{}{}", formatted_price, 0);
        }

        formatted_price
    }
}