1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#[doc(hidden)]
pub use bytes::BytesMut;
#[doc(hidden)]
pub use postgres_types::{to_sql_checked, FromSql, IsNull, ToSql, Type};

/// ## Example
/// ```
/// # use fire_postgres::try2;
///
/// fn mul(maybe_num: Option<i32>) -> Result<Option<i32>, &'static str> {
/// 	let x = try2!(maybe_num);
///
/// 	x.checked_mul(2)
/// 		.map(Some)
/// 		.ok_or("overflow")
/// }
/// ```
#[macro_export]
macro_rules! try2 {
	($exp:expr) => {
		match $exp {
			Some(o) => o,
			None => return Ok(None),
		}
	};
}

/// ## Example
/// ```
/// # use fire_postgres::try_vec;
///
/// fn add(maybe_vec: Option<Vec<i32>>) -> Result<Vec<i32>, &'static str> {
/// 	let v = try_vec!(maybe_vec);
///
/// 	Ok(v.into_iter().map(|x| x + 1).collect())
/// }
/// ```
#[macro_export]
macro_rules! try_vec {
	($exp:expr) => {
		match $exp {
			Some(o) => o,
			None => return Ok(vec![]),
		}
	};
}

/// ## Example
/// ```
/// use fire_postgres::enum_u16;
/// enum_u16! {
/// 	#[derive(Debug)]
/// 	pub enum SiteRaw {
/// 		FrameUser = 10,
/// 		Admin = 20,
/// 		App = 30
/// 	}
/// }
/// ```
#[macro_export]
macro_rules! enum_u16 {
	($(#[$metas:meta])* $($pub:ident)? enum $name:ident {
		$($opt:ident = $num:expr),*
	}) => {
		$(#[$metas])*
		#[repr(u16)]
		$($pub)? enum $name {
			$($opt = $num),*
		}

		impl $name {
			pub fn as_u16(&self) -> u16 {
				match self {
					$(Self::$opt => $num),*
				}
			}

			pub fn from_u16(
				num: u16
			) -> std::result::Result<Self, &'static str> {
				match num {
					$($num => Ok(Self::$opt)),*,
					_ => Err(stringify!(could not parse u16 to $name))
				}
			}
		}

		impl $crate::table::column::ColumnType for $name {
			fn column_kind() -> $crate::table::column::ColumnKind {
				$crate::table::column::ColumnKind::I32
			}
		}

		impl $crate::macros::ToSql for $name {
			fn to_sql(
				&self,
				ty: &$crate::macros::Type,
				buf: &mut $crate::macros::BytesMut
			) -> std::result::Result<$crate::macros::IsNull, Box<dyn std::error::Error + Sync + Send>> {
				let val = self.as_u16() as i32;

				val.to_sql(ty, buf)
			}

			fn accepts(ty: &$crate::macros::Type) -> bool {
				<i32 as $crate::macros::ToSql>::accepts(ty)
			}

			$crate::macros::to_sql_checked!();
		}

		impl<'a> $crate::macros::FromSql<'a> for $name {
			fn from_sql(
				ty: &$crate::macros::Type,
				buf: &'a [u8]
			) -> std::result::Result<Self, Box<dyn std::error::Error + Sync + Send>> {
				let num = <i32 as $crate::macros::FromSql>::from_sql(ty, buf)?;
				num.try_into()
					.map_err(|_| "i32 to u16 conversion failed")
					.and_then(Self::from_u16)
					.map_err(|m| m.into())
			}

			fn accepts(ty: &$crate::macros::Type) -> bool {
				<i32 as $crate::macros::FromSql>::accepts(ty)
			}
		}
	};
}