use std::{borrow::Cow, marker::PhantomData};
use serde::{Deserialize, Serialize};
#[cfg(feature = "validation")]
use validator::Validate;
use super::text;
#[cfg(feature = "validation")]
use crate::val_helpr::ValidationResult;
use crate::{build::*, convert};
#[derive(Copy, Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
#[cfg_attr(feature = "validation", derive(Validate))]
pub struct AnyText;
#[derive(Copy, Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
#[cfg_attr(feature = "validation", derive(Validate))]
pub struct NoUrl;
#[derive(Copy, Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
#[cfg_attr(feature = "validation", derive(Validate))]
pub struct AllowUrl;
convert!(impl From<NoUrl> for AllowUrl => |_| AllowUrl);
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
#[cfg_attr(feature = "validation", derive(Validate))]
pub struct Opt<'a, T = AnyText, U = NoUrl> {
#[cfg_attr(feature = "validation", validate(custom = "validate::text"))]
text: text::Text,
#[cfg_attr(feature = "validation", validate(length(max = 75)))]
value: Cow<'a, str>,
#[cfg_attr(feature = "validation", validate(custom = "validate::desc"))]
#[serde(skip_serializing_if = "Option::is_none")]
description: Option<text::Text>,
#[cfg_attr(feature = "validation", validate(custom = "validate::url"))]
#[serde(skip_serializing_if = "Option::is_none")]
url: Option<Cow<'a, str>>,
#[serde(skip)]
marker: PhantomData<(T, U)>,
}
impl<'a, T: Into<text::Text>, U> From<Opt<'a, T, U>> for Opt<'a, AnyText, U> {
fn from(o: Opt<'a, T, U>) -> Self {
Opt { text: o.text,
value: o.value,
description: o.description,
url: o.url,
marker: PhantomData::<(AnyText, U)> }
}
}
impl<'a> Opt<'a> {
pub fn builder() -> build::OptBuilderInit<'a> {
build::OptBuilderInit::new()
}
}
impl<'a, U> Opt<'a, text::Plain, U> {
pub(crate) fn as_allow_url(self) -> Opt<'a, text::Plain, AllowUrl> {
Opt { text: self.text,
value: self.value,
description: self.description,
url: self.url,
marker: PhantomData::<(text::Plain, AllowUrl)> }
}
}
impl<'a, T, U> Opt<'a, T, U> {
#[cfg(feature = "validation")]
#[cfg_attr(docsrs, doc(cfg(feature = "validation")))]
pub fn validate(&self) -> ValidationResult {
Validate::validate(self)
}
}
pub mod build {
use std::marker::PhantomData;
use super::*;
#[allow(non_camel_case_types)]
pub mod method {
#[derive(Copy, Clone, Debug)]
pub struct value;
#[derive(Copy, Clone, Debug)]
pub struct text;
#[derive(Copy, Clone, Debug)]
pub struct url;
}
pub type OptBuilderInit<'a> =
OptBuilder<'a,
RequiredMethodNotCalled<method::text>,
RequiredMethodNotCalled<method::value>,
OptionalMethodNotCalled<method::url>>;
#[derive(Debug)]
pub struct OptBuilder<'a, Text, Value, Url> {
text: Option<text::Text>,
value: Option<Cow<'a, str>>,
description: Option<text::Text>,
url: Option<Cow<'a, str>>,
state: PhantomData<(Text, Value, Url)>,
}
impl<T, V, U> OptBuilder<'static, T, V, U> {
pub fn new() -> OptBuilderInit<'static> {
OptBuilderInit { text: None,
value: None,
description: None,
url: None,
state: PhantomData::<_> }
}
}
impl<'a, T, V, U> OptBuilder<'a, T, V, U> {
fn cast_state<T2, V2, U2>(self) -> OptBuilder<'a, T2, V2, U2> {
OptBuilder { text: self.text,
value: self.value,
description: self.description,
url: self.url,
state: PhantomData::<_> }
}
pub fn value<S>(mut self,
value: S)
-> OptBuilder<'a, T, Set<method::value>, U>
where S: Into<Cow<'a, str>>
{
self.value = Some(value.into());
self.cast_state()
}
pub fn desc<S>(mut self, desc: S) -> OptBuilder<'a, T, V, U>
where S: Into<text::Plain>
{
self.description = Some(desc.into().into());
self.cast_state()
}
}
impl<'a, V, U> OptBuilder<'a, RequiredMethodNotCalled<method::text>, V, U> {
#[cfg(feature = "blox")]
#[cfg_attr(docsrs, doc(cfg(feature = "blox")))]
pub fn child<T: Into<text::Text>>(
self,
text: T)
-> OptBuilder<'a, Set<(method::text, T)>, V, U> {
self.text(text)
}
pub fn text<Txt>(mut self,
text: Txt)
-> OptBuilder<'a, Set<(method::text, Txt)>, V, U>
where Txt: Into<text::Text>
{
self.text = Some(text.into());
self.cast_state()
}
pub fn text_plain<Txt>(
self,
text: Txt)
-> OptBuilder<'a, Set<(method::text, text::Plain)>, V, U>
where Txt: Into<text::Plain>
{
self.text(text.into())
}
pub fn text_md<Txt>(
self,
text: Txt)
-> OptBuilder<'a, Set<(method::text, text::Mrkdwn)>, V, U>
where Txt: Into<text::Mrkdwn>
{
self.text(text.into())
}
}
impl<'a, V, U> OptBuilder<'a, Set<(method::text, text::Plain)>, V, U> {
pub fn url<S>(
mut self,
url: S)
-> OptBuilder<'a, Set<(method::text, text::Plain)>, V, Set<method::url>>
where S: Into<Cow<'a, str>>
{
self.url = Some(url.into());
self.cast_state()
}
pub fn no_url(
self)
-> OptBuilder<'a, Set<(method::text, text::Plain)>, V, Set<method::url>>
{
self.cast_state()
}
}
impl<'a>
OptBuilder<'a,
Set<(method::text, text::Plain)>,
Set<method::value>,
Set<method::url>>
{
pub fn build(self) -> Opt<'a, text::Plain, AllowUrl> {
Opt { text: self.text.unwrap(),
value: self.value.unwrap(),
url: self.url,
description: self.description,
marker: PhantomData::<_> }
}
}
impl<'a, T: Into<text::Text>>
OptBuilder<'a,
Set<(method::text, T)>,
Set<method::value>,
OptionalMethodNotCalled<method::url>>
{
pub fn build(self) -> Opt<'a, T, NoUrl> {
Opt { text: self.text.unwrap(),
value: self.value.unwrap(),
url: self.url,
description: self.description,
marker: PhantomData::<_> }
}
}
}
#[cfg(feature = "validation")]
mod validate {
use super::*;
use crate::val_helpr::{below_len, ValidatorResult};
pub(super) fn text(text: &text::Text) -> ValidatorResult {
below_len("Option Text", 75, text.as_ref())
}
pub(super) fn desc(text: &text::Text) -> ValidatorResult {
below_len("Option Description", 75, text.as_ref())
}
pub(super) fn url(text: &Cow<'_, str>) -> ValidatorResult {
below_len("URL", 3000, text.as_ref())
}
}