openapi_type 0.6.0

OpenAPI type information for Rust structs and enums
Documentation
use crate::{ObjectVisitor, OpenapiType, Visitor};
use indexmap::{IndexMap, IndexSet};
use serde_json::Value;
use std::{
	collections::{BTreeMap, BTreeSet, HashMap, HashSet, LinkedList, VecDeque},
	ffi::{CStr, CString},
	num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize}
};

impl OpenapiType for () {
	fn visit_type<V: Visitor>(visitor: &mut V) {
		visitor.visit_unit();
	}
}

impl OpenapiType for Value {
	fn visit_type<V: Visitor>(visitor: &mut V) {
		visitor.visit_any();
	}
}

impl OpenapiType for bool {
	fn visit_type<V: Visitor>(visitor: &mut V) {
		visitor.visit_bool();
	}
}

////////////////////////////////////////////////////////////////////////////////
// Tuples use a recursive macro to implement.
// To reduce compilation time, several features exist that extend the number of elements
// within the tuple. Always add the #[cfg] twice, once to reduce compilation overhead by
// having the compiler not expand the recursive macro, and once so that rustdoc picks up
// which feature needs to be enabled for the implementation to exist.

macro_rules! tuples {
	($(#[$($attr:tt)*])* ($($fixed:ident),*),) => {};

	($(#[$($attr:tt)*])* ($($fixed:ident),*), $first:ident $(, $other:ident)*) => {
		// Implement for |fixed| < n < |fixed| + 1 + |other|
		tuples!($(#[$($attr)*])* ($($fixed),*), $($other),*);

		// Implement for |fixed| + 1 + |other|
		$(#[$($attr)*])*
		impl<$first, $($other,)* $($fixed,)*> OpenapiType for ($first, $($other,)* $($fixed,)*)
		where
			$first: OpenapiType,
			$($other: OpenapiType,)*
			$($fixed: OpenapiType,)*
		{
			fn visit_type<V: Visitor>(visitor: &mut V) {
				let visitor = visitor.visit_tuple();
				use $crate::TupleVisitor as _;
				$first::visit_type(visitor.visit_field(None));
				$($other::visit_type(visitor.visit_field(None));)*
				$($fixed::visit_type(visitor.visit_field(None));)*
			}
		}
	};
}

#[cfg(feature = "tuples16")]
tuples! {
	#[cfg(feature = "tuples16")]
	(),
	T15, T14, T13, T12, T11, T10, T9, T8, T7, T6, T5, T4, T3, T2, T1, T0
}

#[cfg(feature = "tuples32")]
tuples! {
	#[cfg(feature = "tuples32")]
	(T15, T14, T13, T12, T11, T10, T9, T8, T7, T6, T5, T4, T3, T2, T1, T0),
	T31, T30, T29, T28, T27, T26, T25, T24, T23, T22, T21, T20, T19, T18, T17, T16
}

#[cfg(feature = "tuples48")]
tuples! {
	#[cfg(feature = "tuples48")]
	(
		T31, T30, T29, T28, T27, T26, T25, T24, T23, T22, T21, T20, T19, T18, T17, T16,
		T15, T14, T13, T12, T11, T10, T9, T8, T7, T6, T5, T4, T3, T2, T1, T0
	),
	T47, T46, T45, T44, T43, T42, T41, T40, T39, T38, T37, T36, T35, T34, T33, T32
}

#[cfg(feature = "tuples64")]
tuples! {
	#[cfg(feature = "tuples64")]
	(
		T47, T46, T45, T44, T43, T42, T41, T40, T39, T38, T37, T36, T35, T34, T33, T32,
		T31, T30, T29, T28, T27, T26, T25, T24, T23, T22, T21, T20, T19, T18, T17, T16,
		T15, T14, T13, T12, T11, T10, T9, T8, T7, T6, T5, T4, T3, T2, T1, T0
	),
	T63, T62, T61, T60, T59, T58, T57, T56, T55, T54, T53, T52, T51, T50, T49, T48
}

////////////////////////////////////////////////////////////////////////////////

macro_rules! int {
	($($ty:ident($minimum:expr, $bits:expr);)+) => {
		$(
			impl OpenapiType for $ty {
				fn visit_type<V: Visitor>(visitor: &mut V) {
					visitor.visit_int($bits, $minimum);
				}
			}
		)+
	}
}

int! {
	isize(None, None);
	i8(None, Some(8));
	i16(None, Some(16));
	i32(None, Some(32));
	i64(None, Some(64));
	i128(None, Some(128));

	usize(Some(0), None);
	u8(Some(0), Some(8));
	u16(Some(0), Some(16));
	u32(Some(0), Some(32));
	u64(Some(0), Some(64));
	u128(Some(0), Some(128));

	NonZeroUsize(Some(1), None);
	NonZeroU8(Some(1), Some(8));
	NonZeroU16(Some(1), Some(16));
	NonZeroU32(Some(1), Some(32));
	NonZeroU64(Some(1), Some(64));
	NonZeroU128(Some(1), Some(128));
}

////////////////////////////////////////////////////////////////////////////////

macro_rules! number {
	($($ty:ident($bits:expr);)+) => {
		$(
			impl OpenapiType for $ty {
				fn visit_type<V: Visitor>(visitor: &mut V) {
					visitor.visit_number($bits);
				}
			}
		)+
	}
}

number! {
	f32(Some(32));
	f64(Some(64));
}

////////////////////////////////////////////////////////////////////////////////

impl OpenapiType for char {
	fn visit_type<V: Visitor>(visitor: &mut V) {
		visitor.visit_char();
	}
}

////////////////////////////////////////////////////////////////////////////////

macro_rules! string {
	($($ty:ident;)+) => {
		$(
			impl OpenapiType for $ty {
				fn visit_type<V: Visitor>(visitor: &mut V) {
					visitor.visit_string();
				}
			}
		)+
	}
}

string! {
	String;
	str;
	CString;
	CStr;
}

////////////////////////////////////////////////////////////////////////////////

#[cfg(feature = "url2")]
impl OpenapiType for url2::Url {
	fn visit_type<V: Visitor>(visitor: &mut V) {
		visitor.visit_url();
	}
}

////////////////////////////////////////////////////////////////////////////////

#[cfg(feature = "uuid1")]
impl OpenapiType for uuid1::Uuid {
	fn visit_type<V: Visitor>(visitor: &mut V) {
		visitor.visit_uuid();
	}
}

////////////////////////////////////////////////////////////////////////////////

#[cfg(feature = "_datetime")]
macro_rules! date {
	($($(#[$($attr:tt)*])* $($ty:ident)::+ $(<$arg:ident: $bound:path>)?;)+) => {
		$(
			$(#[$($attr)*])*
			impl$(<$arg: $bound>)? OpenapiType for $($ty)::+$(<$arg>)? {
				fn visit_type<V: Visitor>(visitor: &mut V) {
					visitor.visit_date();
				}
			}
		)+
	}
}

#[cfg(feature = "_datetime")]
date! {
	#[cfg(feature = "chrono04")]
	#[allow(deprecated)]
	chrono04::Date<T: chrono04::TimeZone>;
	#[cfg(feature = "chrono04")]
	chrono04::NaiveDate;

	#[cfg(feature = "jiff02")]
	jiff02::civil::Date;

	#[cfg(feature = "time03")]
	time03::Date;
}

////////////////////////////////////////////////////////////////////////////////

#[cfg(feature = "_datetime")]
macro_rules! datetime {
	($($(#[$($attr:tt)*])* $($ty:ident)::+ $(<$arg:ident: $bound:path>)?;)+) => {
		$(
			$(#[$($attr)*])*
			impl$(<$arg: $bound>)? OpenapiType for $($ty)::+$(<$arg>)? {
				fn visit_type<V: Visitor>(visitor: &mut V) {
					visitor.visit_datetime();
				}
			}
		)+
	}
}

#[cfg(feature = "_datetime")]
datetime! {
	#[cfg(feature = "chrono04")]
	chrono04::DateTime<T: chrono04::TimeZone>;
	#[cfg(feature = "chrono04")]
	chrono04::NaiveDateTime;

	#[cfg(feature = "jiff02")]
	jiff02::civil::DateTime;
	#[cfg(feature = "jiff02")]
	jiff02::Timestamp;
	#[cfg(feature = "jiff02")]
	jiff02::Zoned;

	#[cfg(feature = "time03")]
	time03::PrimitiveDateTime;
	#[cfg(feature = "time03")]
	time03::OffsetDateTime;
	#[cfg(feature = "time03")]
	time03::UtcDateTime;
}

////////////////////////////////////////////////////////////////////////////////

impl<T: OpenapiType> OpenapiType for Option<T> {
	fn visit_type<V: Visitor>(visitor: &mut V) {
		let v = visitor.visit_option();
		T::visit_type(v);
	}
}

////////////////////////////////////////////////////////////////////////////////

macro_rules! array {
	($($(#[$($attr:tt)*])* $($ty:ident)::+ $(<$($arg:ident),+>)? ($unique_items:literal, $inner:ident);)+) => {
		$(
			$(#[$($attr)*])*
			impl$(<$($arg),+>)? OpenapiType for $($ty)::+$(<$($arg),+>)?
			where
				$inner: OpenapiType
			{
				fn visit_type<V: Visitor>(visitor: &mut V) {
					let v = visitor.visit_array(None, $unique_items);
					<$inner as OpenapiType>::visit_type(v);
				}
			}
		)+
	}
}

type Array<T> = [T];

array! {
	Array<T>(false, T);
	LinkedList<T>(false, T);
	Vec<T>(false, T);
	VecDeque<T>(false, T);

	BTreeSet<T>(true, T);
	HashSet<T, S>(true, T);
	IndexSet<T, S>(true, T);

	#[cfg(feature = "hashbrown016")]
	hashbrown016::HashSet<T, S>(true, T);

	#[cfg(feature = "hashbrown017")]
	hashbrown017::HashSet<T, S>(true, T);
}

impl<T: OpenapiType, const N: usize> OpenapiType for [T; N] {
	fn visit_type<V: Visitor>(visitor: &mut V) {
		let v = visitor.visit_array(Some(N as u64), false);
		T::visit_type(v);
	}
}

////////////////////////////////////////////////////////////////////////////////

macro_rules! map {
	($($(#[$($attr:tt)*])* $($ty:ident)::+ $(<$($arg:ident$(: $bound:path)?),+>)? ($inner:ident);)+) => {
		$(
			$(#[$($attr)*])*
			impl$(<$($arg$(: $bound)?),+>)? OpenapiType for $($ty)::+$(<$($arg),+>)?
			where
				$inner: OpenapiType
			{
				fn visit_type<Vi: Visitor>(visitor: &mut Vi) {
					let obj = visitor.visit_object();
					let v = obj.visit_additional();
					<$inner as OpenapiType>::visit_type(v);
				}
			}
		)+
	}
}

map! {
	BTreeMap<K, V>(V);
	HashMap<K, V, S>(V);
	IndexMap<K, V, S>(V);

	#[cfg(feature = "hashbrown016")]
	hashbrown016::HashMap<K, V, S>(V);

	#[cfg(feature = "hashbrown017")]
	hashbrown017::HashMap<K, V, S>(V);

	#[cfg(feature = "linked-hash-map05")]
	linked_hash_map05::LinkedHashMap<K, V, S>(V);
}