1use crate::{AsValue, DynQuery, Value};
2use proc_macro2::TokenStream;
3use quote::{ToTokens, TokenStreamExt, quote};
4use rust_decimal::prelude::ToPrimitive;
5use serde_json::{Map, Number, Value as JsonValue};
6use std::{
7 borrow::Cow,
8 cmp::min,
9 collections::BTreeMap,
10 ffi::{CStr, CString},
11 fmt::Write,
12 ptr,
13};
14use syn::Path;
15use time::{Date, Time};
16
17#[derive(Clone)]
18pub enum EitherIterator<A, B>
20where
21 A: Iterator,
22 B: Iterator<Item = A::Item>,
23{
24 Left(A),
25 Right(B),
26}
27
28impl<A, B> Iterator for EitherIterator<A, B>
29where
30 A: Iterator,
31 B: Iterator<Item = A::Item>,
32{
33 type Item = A::Item;
34 fn next(&mut self) -> Option<Self::Item> {
35 match self {
36 EitherIterator::Left(a) => a.next(),
37 EitherIterator::Right(b) => b.next(),
38 }
39 }
40}
41
42pub fn value_to_json(v: &Value) -> Option<JsonValue> {
43 Some(match v {
44 _ if v.is_null() => JsonValue::Null,
45 Value::Boolean(Some(v), ..) => JsonValue::Bool(*v),
46 Value::Int8(Some(v), ..) => JsonValue::Number(Number::from_i128(*v as _)?),
47 Value::Int16(Some(v), ..) => JsonValue::Number(Number::from_i128(*v as _)?),
48 Value::Int32(Some(v), ..) => JsonValue::Number(Number::from_i128(*v as _)?),
49 Value::Int64(Some(v), ..) => JsonValue::Number(Number::from_i128(*v as _)?),
50 Value::Int128(Some(v), ..) => JsonValue::Number(Number::from_i128(*v as _)?),
51 Value::UInt8(Some(v), ..) => JsonValue::Number(Number::from_u128(*v as _)?),
52 Value::UInt16(Some(v), ..) => JsonValue::Number(Number::from_u128(*v as _)?),
53 Value::UInt32(Some(v), ..) => JsonValue::Number(Number::from_u128(*v as _)?),
54 Value::UInt64(Some(v), ..) => JsonValue::Number(Number::from_u128(*v as _)?),
55 Value::UInt128(Some(v), ..) => JsonValue::Number(Number::from_u128(*v as _)?),
56 Value::Float32(Some(v), ..) => JsonValue::Number(Number::from_f64(*v as _)?),
57 Value::Float64(Some(v), ..) => JsonValue::Number(Number::from_f64(*v as _)?),
58 Value::Decimal(Some(v), ..) => JsonValue::Number(Number::from_f64(v.to_f64()?)?),
59 Value::Char(Some(v), ..) => JsonValue::String(v.to_string()),
60 Value::Varchar(Some(v), ..) => JsonValue::String(v.to_string()),
61 Value::Blob(Some(v), ..) => JsonValue::Array(
62 v.iter()
63 .map(|v| Number::from_u128(*v as _).map(JsonValue::Number))
64 .collect::<Option<_>>()?,
65 ),
66 Value::Date(Some(v), ..) => {
67 JsonValue::String(format!("{:04}-{:02}-{:02}", v.year(), v.month(), v.day()))
68 }
69 Value::Time(Some(v), ..) => {
70 let mut out = String::new();
71 print_timer(
72 &mut out,
73 "",
74 v.hour() as _,
75 v.minute(),
76 v.second(),
77 v.nanosecond(),
78 );
79 JsonValue::String(out)
80 }
81 Value::Timestamp(Some(v), ..) => {
82 let date = v.date();
83 let time = v.time();
84 let mut out = String::new();
85 print_date(&mut out, "", &date);
86 out.push(' ');
87 print_timer(
88 &mut out,
89 "",
90 time.hour() as _,
91 time.minute(),
92 time.second(),
93 time.nanosecond(),
94 );
95 JsonValue::String(out)
96 }
97 Value::TimestampWithTimezone(Some(v), ..) => {
98 let date = v.date();
99 let time = v.time();
100 let mut out = String::new();
101 print_date(&mut out, "", &date);
102 out.push(' ');
103 print_timer(
104 &mut out,
105 "",
106 time.hour() as _,
107 time.minute(),
108 time.second(),
109 time.nanosecond(),
110 );
111 let (h, m, s) = v.offset().as_hms();
112 out.push(' ');
113 if h >= 0 {
114 out.push('+');
115 } else {
116 out.push('-');
117 }
118 let offset = Time::from_hms(h.abs() as _, m.abs() as _, s.abs() as _).ok()?;
119 print_timer(
120 &mut out,
121 "",
122 offset.hour() as _,
123 offset.minute(),
124 offset.second(),
125 offset.nanosecond(),
126 );
127 JsonValue::String(out)
128 }
129 Value::Interval(Some(_v), ..) => {
130 return None;
131 }
132 Value::Uuid(Some(v), ..) => JsonValue::String(v.to_string()),
133 Value::Array(Some(v), ..) => {
134 JsonValue::Array(v.iter().map(value_to_json).collect::<Option<_>>()?)
135 }
136 Value::List(Some(v), ..) => {
137 JsonValue::Array(v.iter().map(value_to_json).collect::<Option<_>>()?)
138 }
139 Value::Map(Some(v), ..) => {
140 let mut map = Map::new();
141 for (k, v) in v.iter() {
142 let Ok(k) = String::try_from_value(k.clone()) else {
143 return None;
144 };
145 let Some(v) = value_to_json(v) else {
146 return None;
147 };
148 map.insert(k, v)?;
149 }
150 JsonValue::Object(map)
151 }
152 Value::Json(Some(v), ..) => v.clone(),
153 Value::Struct(Some(v), ..) => {
154 let mut map = Map::new();
155 for (k, v) in v.iter() {
156 let Some(v) = value_to_json(v) else {
157 return None;
158 };
159 map.insert(k.clone(), v)?;
160 }
161 JsonValue::Object(map)
162 }
163 Value::Unknown(Some(v), ..) => JsonValue::String(v.clone()),
164 _ => {
165 return None;
166 }
167 })
168}
169
170pub fn quote_btree_map<K: ToTokens, V: ToTokens>(value: &BTreeMap<K, V>) -> TokenStream {
172 let mut tokens = TokenStream::new();
173 for (k, v) in value {
174 let ks = k.to_token_stream();
175 let vs = v.to_token_stream();
176 tokens.append_all(quote! {
177 (#ks, #vs),
178 });
179 }
180 quote! {
181 ::std::collections::BTreeMap::from([
182 #tokens
183 ])
184 }
185}
186
187pub fn quote_cow<T: ToOwned + ToTokens + ?Sized>(value: &Cow<T>) -> TokenStream
189where
190 <T as ToOwned>::Owned: ToTokens,
191{
192 match value {
193 Cow::Borrowed(v) => quote! { ::std::borrow::Cow::Borrowed(#v) },
194 Cow::Owned(v) => quote! { ::std::borrow::Cow::Borrowed(#v) },
195 }
196}
197
198pub fn quote_option<T: ToTokens>(value: &Option<T>) -> TokenStream {
200 match value {
201 None => quote! { None },
202 Some(v) => quote! { Some(#v) },
203 }
204}
205
206pub fn matches_path(path: &Path, expect: &[&str]) -> bool {
208 let len = min(path.segments.len(), expect.len());
209 path.segments
210 .iter()
211 .rev()
212 .take(len)
213 .map(|v| &v.ident)
214 .eq(expect.iter().rev().take(len))
215}
216
217pub fn separated_by<T, F>(
219 out: &mut DynQuery,
220 values: impl IntoIterator<Item = T>,
221 mut f: F,
222 separator: &str,
223) where
224 F: FnMut(&mut DynQuery, T),
225{
226 let mut len = out.len();
227 for v in values {
228 if out.len() > len {
229 out.push_str(separator);
230 }
231 len = out.len();
232 f(out, v);
233 }
234}
235
236pub fn as_c_string(str: impl Into<Vec<u8>>) -> CString {
238 CString::new(
239 str.into()
240 .into_iter()
241 .map(|b| if b == 0 { b'?' } else { b })
242 .collect::<Vec<u8>>(),
243 )
244 .unwrap_or_default()
245}
246
247pub fn error_message_from_ptr<'a>(ptr: &'a *const i8) -> Cow<'a, str> {
248 unsafe {
249 if *ptr != ptr::null() {
250 CStr::from_ptr(*ptr).to_string_lossy()
251 } else {
252 Cow::Borrowed("Unknown error: could not extract the error message")
253 }
254 }
255}
256
257pub fn consume_while<'s>(input: &mut &'s str, predicate: impl FnMut(&char) -> bool) -> &'s str {
259 let len = input.chars().take_while(predicate).count();
260 if len == 0 {
261 return "";
262 }
263 let result = &input[..len];
264 *input = &input[len..];
265 result
266}
267
268pub fn extract_number<'s, const SIGNED: bool>(input: &mut &'s str) -> &'s str {
269 let mut end = 0;
270 let mut chars = input.chars().peekable();
271 if SIGNED && matches!(chars.peek(), Some('+') | Some('-')) {
272 chars.next();
273 end += 1;
274 }
275 for _ in chars.take_while(char::is_ascii_digit) {
276 end += 1;
277 }
278 let result = &input[..end];
279 *input = &input[end..];
280 result
281}
282
283pub fn print_date(out: &mut impl Write, quote: &str, date: &Date) {
284 let _ = write!(
285 out,
286 "{quote}{:04}-{:02}-{:02}{quote}",
287 date.year(),
288 date.month() as u8,
289 date.day(),
290 );
291}
292
293pub fn print_timer(out: &mut impl Write, quote: &str, h: i64, m: u8, s: u8, ns: u32) {
294 let mut subsecond = ns;
295 let mut width = 9;
296 while width > 1 && subsecond % 10 == 0 {
297 subsecond /= 10;
298 width -= 1;
299 }
300 let _ = write!(
301 out,
302 "{quote}{h:02}:{m:02}:{s:02}.{subsecond:0width$}{quote}",
303 );
304}
305
306#[macro_export]
307macro_rules! number_to_month {
308 ($month:expr, $throw:expr $(,)?) => {
309 match $month {
310 1 => Month::January,
311 2 => Month::February,
312 3 => Month::March,
313 4 => Month::April,
314 5 => Month::May,
315 6 => Month::June,
316 7 => Month::July,
317 8 => Month::August,
318 9 => Month::September,
319 10 => Month::October,
320 11 => Month::November,
321 12 => Month::December,
322 _ => $throw,
323 }
324 };
325}
326
327#[macro_export]
328macro_rules! month_to_number {
329 ($month:expr $(,)?) => {
330 match $month {
331 Month::January => 1,
332 Month::February => 2,
333 Month::March => 3,
334 Month::April => 4,
335 Month::May => 5,
336 Month::June => 6,
337 Month::July => 7,
338 Month::August => 8,
339 Month::September => 9,
340 Month::October => 10,
341 Month::November => 11,
342 Month::December => 12,
343 }
344 };
345}
346
347#[macro_export]
348macro_rules! possibly_parenthesized {
350 ($out:ident, $cond:expr, $v:expr) => {
351 if $cond {
352 $out.push('(');
353 $v;
354 $out.push(')');
355 } else {
356 $v;
357 }
358 };
359}
360
361#[macro_export]
362macro_rules! truncate_long {
378 ($query:expr) => {
379 format_args!(
380 "{}{}",
381 &$query[..::std::cmp::min($query.len(), 497)].trim(),
382 if $query.len() > 497 { "...\n" } else { "" },
383 )
384 };
385}
386
387#[macro_export]
399macro_rules! send_value {
400 ($tx:ident, $value:expr) => {{
401 if let Err(e) = $tx.send($value) {
402 log::error!("{e:#}");
403 }
404 }};
405}
406
407#[doc(hidden)]
413#[macro_export]
414macro_rules! take_until {
415 ($original:expr, $($parser:expr),+ $(,)?) => {{
416 let macro_local_input = $original.fork();
417 let mut macro_local_result = (
418 TokenStream::new(),
419 ($({
420 let _ = $parser;
421 None
422 }),+),
423 );
424 loop {
425 if macro_local_input.is_empty() {
426 break;
427 }
428 let mut parsed = false;
429 let produced = ($({
430 let attempt = macro_local_input.fork();
431 if let Ok(content) = ($parser)(&attempt) {
432 macro_local_input.advance_to(&attempt);
433 parsed = true;
434 Some(content)
435 } else {
436 None
437 }
438 }),+);
439 if parsed {
440 macro_local_result.1 = produced;
441 break;
442 }
443 macro_local_result.0.append(macro_local_input.parse::<TokenTree>()?);
444 }
445 $original.advance_to(¯o_local_input);
446 macro_local_result
447 }};
448}
449
450#[macro_export]
451macro_rules! impl_executor_transaction {
477 ($driver:ty, $transaction:ident $(< $lt:lifetime >)?, $connection:ident) => {
479 impl $(<$lt>)? ::tank_core::Executor for $transaction $(<$lt>)? {
480 type Driver = $driver;
481
482 fn accepts_multiple_statements(&self) -> bool {
483 self.$connection.accepts_multiple_statements()
484 }
485
486 fn prepare(
487 &mut self,
488 query: String,
489 ) -> impl Future<Output = ::tank_core::Result<::tank_core::Query<Self::Driver>>> + Send
490 {
491 self.$connection.prepare(query)
492 }
493
494 fn run<'s>(
495 &'s mut self,
496 query: impl ::tank_core::AsQuery<Self::Driver> + 's,
497 ) -> impl ::tank_core::stream::Stream<
498 Item = ::tank_core::Result<::tank_core::QueryResult>,
499 > + Send {
500 self.$connection.run(query)
501 }
502
503 fn fetch<'s>(
504 &'s mut self,
505 query: impl ::tank_core::AsQuery<Self::Driver> + 's,
506 ) -> impl ::tank_core::stream::Stream<
507 Item = ::tank_core::Result<::tank_core::RowLabeled>,
508 > + Send
509 + 's {
510 self.$connection.fetch(query)
511 }
512
513 fn execute<'s>(
514 &'s mut self,
515 query: impl ::tank_core::AsQuery<Self::Driver> + 's,
516 ) -> impl Future<Output = ::tank_core::Result<::tank_core::RowsAffected>> + Send {
517 self.$connection.execute(query)
518 }
519
520 fn append<'a, E, It>(
521 &mut self,
522 entities: It,
523 ) -> impl Future<Output = ::tank_core::Result<::tank_core::RowsAffected>> + Send
524 where
525 E: ::tank_core::Entity + 'a,
526 It: IntoIterator<Item = &'a E> + Send,
527 <It as IntoIterator>::IntoIter: Send,
528 {
529 self.$connection.append(entities)
530 }
531 }
532 }
533}