#![allow(clippy::use_self)] use std::fmt::{self, Debug, Display, Formatter};
use std::marker::PhantomData;
use std::ops::{Index, IndexMut};
use super::typestate::NoItems;
use super::{Corpus, CorpusType, Named};
use crate::corpora::typestate::{CorpusBuildState, HasItems, HasName, NoName};
use crate::input::Data;
use crate::std_ext::fmt::DisplayExt;
use crate::std_ext::ops::Len;
use crate::AsInner;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Copy, Clone, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
enum HttpMethodGroup {
#[default]
Safe,
Idempotent,
Cacheable,
All,
}
#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct HttpMethodsCorpus {
items: Vec<Data>,
corpus_name: String,
}
impl Corpus for HttpMethodsCorpus {
fn add(&mut self, value: Data) {
self.items.push(value);
}
fn get(&self, index: usize) -> Option<&Data> {
self.items.get(index)
}
#[inline]
fn items(&self) -> &[Data] {
&self.items
}
}
impl Named for HttpMethodsCorpus {
fn name(&self) -> &str {
&self.corpus_name
}
}
impl HttpMethodsCorpus {
#[must_use]
#[allow(clippy::new_ret_no_self)]
pub const fn new() -> HttpMethodsBuilder<NoItems, NoName> {
HttpMethodsBuilder {
items: None,
corpus_name: None,
_item_state: PhantomData,
_name_state: PhantomData,
}
}
#[must_use]
pub fn all() -> HttpMethodsBuilder<HasItems, NoName> {
HttpMethodsBuilder {
items: Some(Self::from_group(HttpMethodGroup::All)),
corpus_name: None,
_item_state: PhantomData,
_name_state: PhantomData,
}
}
#[must_use]
pub fn safe() -> HttpMethodsBuilder<HasItems, NoName> {
HttpMethodsBuilder {
items: Some(Self::from_group(HttpMethodGroup::Safe)),
corpus_name: None,
_item_state: PhantomData,
_name_state: PhantomData,
}
}
#[must_use]
pub fn idempotent() -> HttpMethodsBuilder<HasItems, NoName> {
HttpMethodsBuilder {
items: Some(Self::from_group(HttpMethodGroup::Idempotent)),
corpus_name: None,
_item_state: PhantomData,
_name_state: PhantomData,
}
}
#[must_use]
pub fn cacheable() -> HttpMethodsBuilder<HasItems, NoName> {
HttpMethodsBuilder {
items: Some(Self::from_group(HttpMethodGroup::Cacheable)),
corpus_name: None,
_item_state: PhantomData,
_name_state: PhantomData,
}
}
#[inline]
pub fn with_methods<I, T>(http_methods: I) -> HttpMethodsBuilder<HasItems, NoName>
where
Data: From<T>,
I: IntoIterator<Item = T>,
{
HttpMethodsBuilder {
items: Some(http_methods.into_iter().map(Data::from).collect()),
corpus_name: None,
_item_state: PhantomData,
_name_state: PhantomData,
}
}
#[must_use]
fn from_group(group: HttpMethodGroup) -> Vec<Data> {
let mut items = Vec::new();
match group {
HttpMethodGroup::Safe => {
items.push("GET".into());
items.push("HEAD".into());
items.push("OPTIONS".into());
items.push("TRACE".into());
}
HttpMethodGroup::Idempotent => {
items.push("GET".into());
items.push("HEAD".into());
items.push("OPTIONS".into());
items.push("TRACE".into());
items.push("PUT".into());
items.push("DELETE".into());
}
HttpMethodGroup::Cacheable => {
items.push("GET".into());
items.push("HEAD".into());
}
HttpMethodGroup::All => {
items.push("GET".into());
items.push("HEAD".into());
items.push("POST".into());
items.push("PUT".into());
items.push("DELETE".into());
items.push("CONNECT".into());
items.push("OPTIONS".into());
items.push("TRACE".into());
items.push("PATCH".into());
}
}
items
}
#[must_use]
#[inline]
pub fn items_mut(&mut self) -> &mut [Data] {
&mut self.items
}
#[must_use]
pub fn iter_mut(&mut self) -> <&mut [Data] as IntoIterator>::IntoIter {
<&mut Self as IntoIterator>::into_iter(self)
}
#[must_use]
pub fn iter(&self) -> <&[Data] as IntoIterator>::IntoIter {
<&Self as IntoIterator>::into_iter(self)
}
}
impl Len for HttpMethodsCorpus {
#[inline]
fn len(&self) -> usize {
self.items.len()
}
}
impl AsInner for HttpMethodsCorpus {
type Type = Vec<Data>;
fn inner(&self) -> &Self::Type {
&self.items
}
}
impl Display for HttpMethodsCorpus {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.display_top(3))
}
}
impl Index<usize> for HttpMethodsCorpus {
type Output = Data;
fn index(&self, index: usize) -> &Self::Output {
&self.items()[index]
}
}
impl IndexMut<usize> for HttpMethodsCorpus {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.items_mut()[index]
}
}
impl<'i> IntoIterator for &'i mut HttpMethodsCorpus {
type Item = &'i mut Data;
type IntoIter = <&'i mut [Data] as IntoIterator>::IntoIter;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.items.iter_mut()
}
}
impl IntoIterator for HttpMethodsCorpus {
type Item = Data;
type IntoIter = <Vec<Data> as IntoIterator>::IntoIter;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.items.into_iter()
}
}
impl<'i> IntoIterator for &'i HttpMethodsCorpus {
type Item = &'i Data;
type IntoIter = <&'i [Data] as IntoIterator>::IntoIter;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.items.iter()
}
}
pub struct HttpMethodsBuilder<IS, NS>
where
IS: CorpusBuildState,
NS: CorpusBuildState,
{
items: Option<Vec<Data>>,
corpus_name: Option<String>,
_item_state: PhantomData<IS>,
_name_state: PhantomData<NS>,
}
impl<IS> HttpMethodsBuilder<IS, NoName>
where
IS: CorpusBuildState,
{
pub fn name(self, corpus_name: &str) -> HttpMethodsBuilder<IS, HasName> {
HttpMethodsBuilder {
items: self.items,
corpus_name: Some(corpus_name.to_string()),
_item_state: PhantomData,
_name_state: PhantomData,
}
}
}
impl<IS, NS> HttpMethodsBuilder<IS, NS>
where
IS: CorpusBuildState,
NS: CorpusBuildState,
{
pub fn method<T>(self, http_method: T) -> HttpMethodsBuilder<HasItems, NS>
where
Data: From<T>,
{
let mut items = self.items.unwrap_or_default();
items.push(http_method.into());
HttpMethodsBuilder {
items: Some(items),
corpus_name: self.corpus_name,
_item_state: PhantomData,
_name_state: PhantomData,
}
}
pub fn methods<I, T>(self, http_methods: I) -> HttpMethodsBuilder<HasItems, NS>
where
Data: From<T>,
I: IntoIterator<Item = T>,
{
let mut items = self.items.unwrap_or_default();
items.extend(http_methods.into_iter().map(Data::from));
HttpMethodsBuilder {
items: Some(items),
corpus_name: self.corpus_name,
_item_state: PhantomData,
_name_state: PhantomData,
}
}
}
impl HttpMethodsBuilder<HasItems, HasName> {
pub fn build(self) -> CorpusType {
CorpusType::HttpMethods(HttpMethodsCorpus {
items: self.items.unwrap(),
corpus_name: self.corpus_name.unwrap(),
})
}
}