sqlx_pg_uint_macros/
lib.rs1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, DeriveInput};
4
5#[proc_macro_derive(UIntWrapper)]
6pub fn uint_wrapper_derive(input: TokenStream) -> TokenStream {
13 let input = parse_macro_input!(input as DeriveInput);
14 let name = &input.ident;
15
16 let gen = quote! {
17 impl std::fmt::Display for #name {
18 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
19 write!(f, "{}", self.to_uint())
20 }
21 }
22
23 impl std::ops::Add for #name {
24 type Output = Self;
25
26 fn add(self, rhs: Self) -> Self::Output {
27 Self::new(self.to_uint() + rhs.to_uint())
28 }
29 }
30
31 impl std::ops::Mul for #name {
32 type Output = Self;
33
34 fn mul(self, rhs: Self) -> Self::Output {
35 Self::new(self.to_uint() * rhs.to_uint())
36 }
37 }
38
39 impl std::ops::Sub for #name {
40 type Output = Self;
41
42 fn sub(self, rhs: Self) -> Self::Output {
43 Self::new(self.to_uint() - rhs.to_uint())
44 }
45 }
46
47 impl std::ops::Div for #name {
48 type Output = Self;
49
50 fn div(self, rhs: Self) -> Self::Output {
51 Self::new(self.to_uint() / rhs.to_uint())
52 }
53 }
54
55 impl std::ops::Rem for #name {
56 type Output = Self;
57
58 fn rem(self, rhs: Self) -> Self::Output {
59 Self::new(self.to_uint() % rhs.to_uint())
60 }
61 }
62
63 impl std::ops::AddAssign for #name {
64 fn add_assign(&mut self, rhs: Self) {
65 let inner = BigDecimal::from(self.to_uint() + rhs.to_uint());
66 *self = Self { inner };
67 }
68 }
69
70 impl std::ops::SubAssign for #name {
71 fn sub_assign(&mut self, rhs: Self) {
72 let inner = BigDecimal::from(self.to_uint() - rhs.to_uint());
73 *self = Self { inner };
74 }
75 }
76
77 impl std::ops::MulAssign for #name {
78 fn mul_assign(&mut self, rhs: Self) {
79 let inner = BigDecimal::from(self.to_uint() * rhs.to_uint());
80 *self = Self { inner };
81 }
82 }
83
84 impl std::ops::DivAssign for #name {
85 fn div_assign(&mut self, rhs: Self) {
86 let inner = BigDecimal::from(self.to_uint() / rhs.to_uint());
87 *self = Self { inner };
88 }
89 }
90
91 impl std::str::FromStr for #name {
92 type Err = Error;
93
94 fn from_str(s: &str) -> Result<Self, Self::Err> {
95 let unsigned_int: <Self as UIntType>::Uint = s.parse()?;
96 Ok(Self::from(unsigned_int))
97 }
98 }
99
100 impl #name {
101 pub fn to_uint(&self) -> <#name as UIntType>::Uint {
103 let stringed_num = self.inner.to_string();
104 stringed_num.parse().unwrap()
105 }
106
107 pub fn to_option_uint(&self) -> Option<<#name as UIntType>::Uint> {
109 <Option<#name> as OptionPgUint<#name>>::to_option_uint(&Some(self.clone()))
110 }
111
112 pub fn new(num: <#name as UIntType>::Uint) -> Self {
114 Self {
115 inner: BigDecimal::from(num),
116 }
117 }
118
119 pub fn as_big_decimal(&self) -> &BigDecimal {
121 &self.inner
122 }
123 }
124
125 impl OptionPgUint<#name> for Option<#name> where #name: UIntType {
126 fn to_option_uint(&self) -> Option<<#name as UIntType>::Uint> {
127 self.clone().map(|v| v.to_uint())
128 }
129 }
130
131 impl TryFrom<BigDecimal> for #name {
132 type Error = crate::Error;
133
134 fn try_from(value: BigDecimal) -> Result<Self, Self::Error> {
135 let value_ref = &value;
136 if !value_ref.is_integer() {
137 return Err(crate::Error::Fractional(value));
138 }
139 if value_ref.to_string().parse::<u128>().is_err() {
140 return Err(crate::Error::InvalidValue(value));
141 }
142 Ok(Self { inner: value })
143 }
144 }
145
146 impl From<#name> for BigDecimal {
147 fn from(value: #name) -> Self {
148 value.inner
149 }
150 }
151
152 impl Default for #name {
153 fn default() -> Self {
154 Self::from(0)
155 }
156 }
157
158 impl sqlx::Type<sqlx::Postgres> for #name {
159 fn type_info() -> <sqlx::Postgres as sqlx::Database>::TypeInfo {
160 <BigDecimal as sqlx::Type<sqlx::Postgres>>::type_info()
161 }
162 }
163
164 impl<'q> sqlx::Encode<'q, sqlx::Postgres> for #name {
165 fn encode_by_ref(
166 &self,
167 buf: &mut <sqlx::Postgres as sqlx::Database>::ArgumentBuffer<'q>,
168 ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> {
169 <BigDecimal as sqlx::Encode<sqlx::Postgres>>::encode_by_ref(&self.inner, buf)
170 }
171 }
172
173 impl<'r> sqlx::Decode<'r, sqlx::Postgres> for #name {
174 fn decode(
175 value: <sqlx::Postgres as sqlx::Database>::ValueRef<'r>,
176 ) -> Result<Self, sqlx::error::BoxDynError> {
177 let big_decimal = <BigDecimal as sqlx::Decode<sqlx::Postgres>>::decode(value)
178 ?;
179 Ok(#name::try_from(big_decimal)?)
180 }
181 }
182
183 impl sqlx::postgres::PgHasArrayType for #name {
184 fn array_type_info() -> sqlx::postgres::PgTypeInfo {
185 <Vec<BigDecimal> as sqlx::Type<sqlx::Postgres>>::type_info()
186 }
187 }
188
189 #[cfg(feature = "serde")]
190 impl serde::ser::Serialize for #name {
191 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
192 where
193 S: serde::Serializer,
194 {
195 self.to_uint().serialize(serializer)
196 }
197 }
198
199 #[cfg(feature = "serde")]
200 impl<'de> serde::de::Deserialize<'de> for #name {
201 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
202 where
203 D: serde::Deserializer<'de>,
204 {
205 let big_decimal = BigDecimal::deserialize(deserializer)?;
206 #name::try_from(big_decimal).map_err(serde::de::Error::custom)
207 }
208 }
209 };
210
211 gen.into()
212}