1use proc_macro2::TokenStream;
2use quote::{ToTokens, quote};
3use std::{borrow::Cow, cmp::min, ffi::CString};
4use syn::Path;
5
6#[derive(Clone)]
7pub enum EitherIterator<A, B>
9where
10 A: Iterator,
11 B: Iterator<Item = A::Item>,
12{
13 Left(A),
14 Right(B),
15}
16impl<A, B> Iterator for EitherIterator<A, B>
17where
18 A: Iterator,
19 B: Iterator<Item = A::Item>,
20{
21 type Item = A::Item;
22 fn next(&mut self) -> Option<Self::Item> {
23 match self {
24 EitherIterator::Left(a) => a.next(),
25 EitherIterator::Right(b) => b.next(),
26 }
27 }
28}
29
30pub fn quote_cow<T: ToOwned + ToTokens + ?Sized>(value: &Cow<T>) -> TokenStream
32where
33 <T as ToOwned>::Owned: ToTokens,
34{
35 match value {
36 Cow::Borrowed(v) => quote! { ::std::borrow::Cow::Borrowed(#v) },
37 Cow::Owned(v) => quote! { ::std::borrow::Cow::Borrowed(#v) },
38 }
39}
40
41pub fn quote_option<T: ToTokens>(value: &Option<T>) -> TokenStream {
43 match value {
44 None => quote! { None },
45 Some(v) => quote! { Some(#v) },
46 }
47}
48
49pub fn matches_path(path: &Path, expect: &[&str]) -> bool {
51 let len = min(path.segments.len(), expect.len());
52 path.segments
53 .iter()
54 .rev()
55 .take(len)
56 .map(|v| &v.ident)
57 .eq(expect.iter().rev().take(len))
58}
59
60pub fn separated_by<T, F>(
62 out: &mut String,
63 values: impl IntoIterator<Item = T>,
64 mut f: F,
65 separator: &str,
66) where
67 F: FnMut(&mut String, T),
68{
69 let mut len = out.len();
70 for v in values {
71 if out.len() > len {
72 out.push_str(separator);
73 }
74 len = out.len();
75 f(out, v);
76 }
77}
78
79pub fn as_c_string<S: Into<Vec<u8>>>(str: S) -> CString {
81 CString::new(str.into()).expect("Expected a valid C string")
82}
83
84pub fn consume_while<'s>(input: &mut &'s str, predicate: impl FnMut(&char) -> bool) -> &'s str {
86 let len = input.chars().take_while(predicate).count();
87 if len == 0 {
88 return "";
89 }
90 let result = &input[..len];
91 *input = &input[len..];
92 result
93}
94
95#[macro_export]
96macro_rules! possibly_parenthesized {
97 ($out:ident, $cond:expr, $v:expr) => {
98 if $cond {
99 $out.push('(');
100 $v;
101 $out.push(')');
102 } else {
103 $v;
104 }
105 };
106}
107
108#[macro_export]
109macro_rules! truncate_long {
110 ($query:expr) => {
111 format_args!(
112 "{}{}\n",
113 &$query[..::std::cmp::min($query.len(), 497)].trim_end(),
114 if $query.len() > 497 { "..." } else { "" },
115 )
116 };
117}
118
119#[macro_export]
121macro_rules! send_value {
122 ($tx:ident, $value:expr) => {{
123 if let Err(e) = $tx.send($value) {
124 log::error!("{:#}", e);
125 }
126 }};
127}
128
129#[macro_export]
134macro_rules! take_until {
135 ($original:expr, $($parser:expr),+ $(,)?) => {{
136 let macro_local_input = $original.fork();
137 let mut macro_local_result = (
138 TokenStream::new(),
139 ($({
140 let _ = $parser;
141 None
142 }),+),
143 );
144 loop {
145 if macro_local_input.is_empty() {
146 break;
147 }
148 let mut parsed = false;
149 let produced = ($({
150 let attempt = macro_local_input.fork();
151 if let Ok(content) = ($parser)(&attempt) {
152 macro_local_input.advance_to(&attempt);
153 parsed = true;
154 Some(content)
155 } else {
156 None
157 }
158 }),+);
159 if parsed {
160 macro_local_result.1 = produced;
161 break;
162 }
163 macro_local_result.0.append(macro_local_input.parse::<TokenTree>()?);
164 }
165 $original.advance_to(¯o_local_input);
166 macro_local_result
167 }};
168}
169
170#[macro_export]
171macro_rules! impl_executor_transaction {
172 ($driver:ty, $transaction:ident, $connection:ident) => {
173 impl<'c> ::tank_core::Executor for $transaction<'c> {
174 type Driver = $driver;
175
176 fn driver(&self) -> &Self::Driver {
177 self.$connection.driver()
178 }
179
180 fn prepare(
181 &mut self,
182 query: String,
183 ) -> impl Future<Output = ::tank_core::Result<::tank_core::Query<Self::Driver>>> + Send
184 {
185 self.$connection.prepare(query)
186 }
187
188 fn run(
189 &mut self,
190 query: ::tank_core::Query<Self::Driver>,
191 ) -> impl ::tank_core::stream::Stream<
192 Item = ::tank_core::Result<::tank_core::QueryResult>,
193 > + Send {
194 self.$connection.run(query)
195 }
196
197 fn fetch<'s>(
198 &'s mut self,
199 query: ::tank_core::Query<Self::Driver>,
200 ) -> impl ::tank_core::stream::Stream<
201 Item = ::tank_core::Result<::tank_core::RowLabeled>,
202 > + Send
203 + 's {
204 self.$connection.fetch(query)
205 }
206
207 fn execute(
208 &mut self,
209 query: ::tank_core::Query<Self::Driver>,
210 ) -> impl Future<Output = ::tank_core::Result<::tank_core::RowsAffected>> + Send {
211 self.$connection.execute(query)
212 }
213
214 fn append<'a, E, It>(
215 &mut self,
216 entities: It,
217 ) -> impl Future<Output = ::tank_core::Result<::tank_core::RowsAffected>> + Send
218 where
219 E: ::tank_core::Entity + 'a,
220 It: IntoIterator<Item = &'a E> + Send,
221 {
222 self.$connection.append(entities)
223 }
224 }
225 };
226}