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>
8where
9 A: Iterator,
10 B: Iterator<Item = A::Item>,
11{
12 Left(A),
13 Right(B),
14}
15impl<A, B> Iterator for EitherIterator<A, B>
16where
17 A: Iterator,
18 B: Iterator<Item = A::Item>,
19{
20 type Item = A::Item;
21 fn next(&mut self) -> Option<Self::Item> {
22 match self {
23 EitherIterator::Left(a) => a.next(),
24 EitherIterator::Right(b) => b.next(),
25 }
26 }
27}
28
29pub fn quote_cow<T: ToOwned + ToTokens + ?Sized>(value: &Cow<T>) -> TokenStream
30where
31 <T as ToOwned>::Owned: ToTokens,
32{
33 match value {
34 Cow::Borrowed(v) => quote! { ::std::borrow::Cow::Borrowed(#v) },
35 Cow::Owned(v) => quote! { ::std::borrow::Cow::Borrowed(#v) },
36 }
37}
38
39pub fn quote_option<T: ToTokens>(value: &Option<T>) -> TokenStream {
40 match value {
41 None => quote! { None },
42 Some(v) => quote! { Some(#v) },
43 }
44}
45
46pub fn matches_path(path: &Path, expect: &[&str]) -> bool {
47 let len = min(path.segments.len(), expect.len());
48 path.segments
49 .iter()
50 .rev()
51 .take(len)
52 .map(|v| &v.ident)
53 .eq(expect.iter().rev().take(len))
54}
55
56pub fn separated_by<T, F>(
57 out: &mut String,
58 values: impl IntoIterator<Item = T>,
59 mut f: F,
60 separator: &str,
61) where
62 F: FnMut(&mut String, T),
63{
64 let mut len = out.len();
65 for v in values {
66 if out.len() > len {
67 out.push_str(separator);
68 }
69 len = out.len();
70 f(out, v);
71 }
72}
73
74pub fn as_c_string<S: Into<Vec<u8>>>(str: S) -> CString {
75 CString::new(str.into()).expect("Expected a valid C string")
76}
77
78pub fn consume_while<'s>(input: &mut &'s str, predicate: impl FnMut(&char) -> bool) -> &'s str {
79 let len = input.chars().take_while(predicate).count();
80 if len == 0 {
81 return "";
82 }
83 let result = &input[..len];
84 *input = &input[len..];
85 result
86}
87
88#[macro_export]
89macro_rules! possibly_parenthesized {
90 ($buff:ident, $cond:expr, $v:expr) => {
91 if $cond {
92 $buff.push('(');
93 $v;
94 $buff.push(')');
95 } else {
96 $v;
97 }
98 };
99}
100
101#[macro_export]
102macro_rules! truncate_long {
103 ($query:expr) => {
104 format_args!(
105 "{}{}\n",
106 &$query[..::std::cmp::min($query.len(), 497)].trim_end(),
107 if $query.len() > 497 { "..." } else { "" },
108 )
109 };
110}
111
112#[macro_export]
114macro_rules! send_value {
115 ($tx:ident, $value:expr) => {{
116 if let Err(e) = $tx.send($value) {
117 log::error!("{:#}", e);
118 }
119 }};
120}
121
122#[macro_export]
126macro_rules! take_until {
127 ($original:expr, $($parser:expr),+ $(,)?) => {{
128 let macro_local_input = $original.fork();
129 let mut macro_local_result = (
130 TokenStream::new(),
131 ($({
132 let _ = $parser;
133 None
134 }),+),
135 );
136 loop {
137 if macro_local_input.is_empty() {
138 break;
139 }
140 let mut parsed = false;
141 let produced = ($({
142 let attempt = macro_local_input.fork();
143 if let Ok(content) = ($parser)(&attempt) {
144 macro_local_input.advance_to(&attempt);
145 parsed = true;
146 Some(content)
147 } else {
148 None
149 }
150 }),+);
151 if parsed {
152 macro_local_result.1 = produced;
153 break;
154 }
155 macro_local_result.0.append(macro_local_input.parse::<TokenTree>()?);
156 }
157 $original.advance_to(¯o_local_input);
158 macro_local_result
159 }};
160}