tank_core/
util.rs

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
78#[macro_export]
79macro_rules! possibly_parenthesized {
80    ($buff:ident, $cond:expr, $v:expr) => {
81        if $cond {
82            $buff.push('(');
83            $v;
84            $buff.push(')');
85        } else {
86            $v;
87        }
88    };
89}
90
91#[macro_export]
92macro_rules! printable_query {
93    ($query:expr) => {
94        format_args!(
95            "{}{}\n",
96            &$query[..::std::cmp::min($query.len(), 247)].trim_end(),
97            if $query.len() > 247 { "..." } else { "" },
98        )
99    };
100}
101
102/// Sends the value through the channel and logs in case of error.
103#[macro_export]
104macro_rules! send_value {
105    ($tx:ident, $value:expr) => {{
106        if let Err(e) = $tx.send($value) {
107            log::error!("{:#}", e);
108        }
109    }};
110}
111
112/// Accumulates the tokens until a parser matches.
113///
114/// It returns the accumulated `TokenStream` as well as the result of the match (if any).
115#[macro_export]
116macro_rules! take_until {
117    ($original:expr, $($parser:expr),+ $(,)?) => {{
118        let macro_local_input = $original.fork();
119        let mut macro_local_result = (
120            TokenStream::new(),
121            ($({
122                let _ = $parser;
123                None
124            }),+),
125        );
126        loop {
127            if macro_local_input.is_empty() {
128                break;
129            }
130            let mut parsed = false;
131            let produced = ($({
132                let attempt = macro_local_input.fork();
133                if let Ok(content) = ($parser)(&attempt) {
134                    macro_local_input.advance_to(&attempt);
135                    parsed = true;
136                    Some(content)
137                } else {
138                    None
139                }
140            }),+);
141            if parsed {
142                macro_local_result.1 = produced;
143                break;
144            }
145            macro_local_result.0.append(macro_local_input.parse::<TokenTree>()?);
146        }
147        $original.advance_to(&macro_local_input);
148        macro_local_result
149    }};
150}