glib_macros/
clone_old.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::iter::Peekable;
4
5use proc_macro::{
6    token_stream::IntoIter as ProcIter, Delimiter, Group, Ident, Literal, Punct, Spacing, Span,
7    TokenStream, TokenTree,
8};
9
10use crate::utils::crate_ident_new;
11
12struct PeekableProcIter {
13    inner: Peekable<ProcIter>,
14    current_span: Option<Span>,
15    next_span: Option<Span>,
16}
17
18impl<'a> From<&'a Group> for PeekableProcIter {
19    fn from(f: &'a Group) -> Self {
20        let current_span = Some(f.span());
21        let mut inner = f.stream().into_iter().peekable();
22        let next_span = inner.peek().map(|n| n.span());
23        Self {
24            inner,
25            current_span,
26            next_span,
27        }
28    }
29}
30
31impl From<TokenStream> for PeekableProcIter {
32    fn from(f: TokenStream) -> Self {
33        let mut inner = f.into_iter().peekable();
34        let next_span = inner.peek().map(|n| n.span());
35        Self {
36            inner,
37            current_span: None,
38            next_span,
39        }
40    }
41}
42
43impl Iterator for PeekableProcIter {
44    type Item = TokenTree;
45
46    fn next(&mut self) -> Option<Self::Item> {
47        let next = self.inner.next()?;
48        self.current_span = Some(next.span());
49        self.next_span = self.inner.peek().map(|n| n.span());
50        Some(next)
51    }
52}
53
54impl PeekableProcIter {
55    fn peek(&mut self) -> Option<&TokenTree> {
56        self.inner.peek()
57    }
58
59    fn generate_error(&self, message: &str) -> TokenStream {
60        self.generate_error_with_span(message, self.current_span)
61    }
62
63    fn generate_error_with_next_span(&self, message: &str) -> TokenStream {
64        self.generate_error_with_span(message, self.next_span)
65    }
66
67    fn generate_error_with_span(&self, message: &str, span: Option<Span>) -> TokenStream {
68        let span = span.unwrap_or_else(Span::call_site);
69        // We generate a `compile_error` macro and assign it to the current span so the error
70        // displayed by rustc points to the right location.
71        let mut stream = TokenStream::new();
72        stream.extend(vec![TokenTree::Literal(Literal::string(message))]);
73
74        let mut tokens = vec![
75            TokenTree::Ident(Ident::new("compile_error", span)),
76            TokenTree::Punct(Punct::new('!', Spacing::Alone)),
77            TokenTree::Group(Group::new(Delimiter::Parenthesis, stream)),
78            TokenTree::Punct(Punct::new(';', Spacing::Alone)),
79        ];
80
81        for tok in &mut tokens {
82            tok.set_span(span);
83        }
84
85        let mut stream = TokenStream::new();
86        stream.extend(tokens);
87        let mut t = TokenTree::Group(Group::new(Delimiter::Brace, stream));
88        t.set_span(span);
89
90        let mut stream = TokenStream::new();
91        stream.extend(vec![t]);
92        stream
93    }
94}
95
96#[derive(Clone, Copy, Debug)]
97enum BorrowKind {
98    Weak,
99    WeakAllowNone,
100    Strong,
101    ToOwned,
102}
103
104impl BorrowKind {
105    fn to_str(self) -> &'static str {
106        match self {
107            Self::Weak => "@weak",
108            Self::WeakAllowNone => "@weak-allow-none",
109            Self::Strong => "@strong",
110            Self::ToOwned => "@to-owned",
111        }
112    }
113}
114
115enum WrapperKind {
116    DefaultPanic,
117    DefaultReturn(String),
118}
119
120impl WrapperKind {
121    fn to_str(&self) -> String {
122        match *self {
123            Self::DefaultPanic => "@default-panic".to_owned(),
124            Self::DefaultReturn(ref r) => format!("@default-return {r}"),
125        }
126    }
127
128    fn keyword(&self) -> &'static str {
129        match *self {
130            Self::DefaultPanic => "default-panic",
131            Self::DefaultReturn(_) => "default-return",
132        }
133    }
134}
135
136#[derive(Debug)]
137struct ElemToClone {
138    name: String,
139    alias: Option<String>,
140    borrow_kind: BorrowKind,
141}
142
143impl ElemToClone {
144    fn to_str_before(&self) -> String {
145        match self.borrow_kind {
146            BorrowKind::Weak | BorrowKind::WeakAllowNone => format!(
147                "let {} = {}::clone::Downgrade::downgrade(&{});",
148                if let Some(ref a) = self.alias {
149                    a
150                } else {
151                    &self.name
152                },
153                crate_ident_new(),
154                self.name,
155            ),
156            BorrowKind::Strong => format!(
157                "let {} = {}.clone();",
158                if let Some(ref a) = self.alias {
159                    a
160                } else {
161                    &self.name
162                },
163                self.name,
164            ),
165            BorrowKind::ToOwned => format!(
166                "let {} = ::std::borrow::ToOwned::to_owned(&*{});",
167                if let Some(ref a) = self.alias {
168                    a
169                } else {
170                    &self.name
171                },
172                self.name,
173            ),
174        }
175    }
176
177    fn to_str_after(&self, wrapper_kind: &Option<WrapperKind>) -> String {
178        let name = if let Some(ref a) = self.alias {
179            a
180        } else {
181            &self.name
182        };
183        match (self.borrow_kind, wrapper_kind) {
184            (BorrowKind::Weak, Some(WrapperKind::DefaultPanic)) => {
185                format!(
186                    "\
187let {0} = match {1}::clone::Upgrade::upgrade(&{0}) {{
188    Some(val) => val,
189    None => panic!(
190        \"failed to upgrade `{0}` (if you don't want to panic, use @default-return)\",
191    ),
192}};",
193                    name,
194                    crate_ident_new(),
195                )
196            }
197            (BorrowKind::Weak, Some(WrapperKind::DefaultReturn(ref r))) => {
198                let not_unit_ret = r.chars().any(|c| c != '(' && c != ')' && c != ' ');
199                format!(
200                    "\
201let {0} = match {1}::clone::Upgrade::upgrade(&{0}) {{
202    Some(val) => val,
203    None => {{
204        {1}::g_debug!(
205            {1}::CLONE_MACRO_LOG_DOMAIN,
206            \"Failed to upgrade {0}\",
207        );
208        let ___return_value = || {{ {2} }};
209        return ___return_value();
210    }}
211}};",
212                    name,
213                    crate_ident_new(),
214                    if not_unit_ret { r } else { "" },
215                )
216            }
217            (BorrowKind::Weak, None) => {
218                format!(
219                    "\
220let {0} = match {1}::clone::Upgrade::upgrade(&{0}) {{
221    Some(val) => val,
222    None => {{
223        {1}::g_debug!(
224            {1}::CLONE_MACRO_LOG_DOMAIN,
225            \"Failed to upgrade {0}\",
226        );
227        return;
228    }}
229}};",
230                    name,
231                    crate_ident_new(),
232                )
233            }
234            (BorrowKind::WeakAllowNone, _) => format!(
235                "let {0} = {1}::clone::Upgrade::upgrade(&{0});",
236                name,
237                crate_ident_new(),
238            ),
239            _ => String::new(),
240        }
241    }
242}
243
244enum SimpleToken {
245    Punct(&'static str),
246    Ident(&'static str),
247}
248
249impl SimpleToken {
250    fn to_str(&self) -> &str {
251        match *self {
252            Self::Punct(p) => p,
253            Self::Ident(i) => i,
254        }
255    }
256}
257
258impl PartialEq<TokenTree> for SimpleToken {
259    fn eq(&self, other: &TokenTree) -> bool {
260        match (self, other) {
261            (SimpleToken::Punct(p1), TokenTree::Punct(ref p2)) => *p1 == p2.to_string(),
262            (SimpleToken::Ident(i1), TokenTree::Ident(ref i2)) => *i1 == i2.to_string(),
263            _ => false,
264        }
265    }
266}
267
268fn is_punct(elem: &TokenTree, punct: &str) -> bool {
269    match elem {
270        TokenTree::Punct(ref p) => p.to_string() == punct,
271        _ => false,
272    }
273}
274
275enum TokenCheck {
276    UnexpectedToken(String, String),
277    UnexpectedEnd(String),
278}
279
280fn check_tokens(
281    tokens_to_check: &[SimpleToken],
282    parts: &mut PeekableProcIter,
283) -> Result<(), TokenCheck> {
284    let mut tokens = String::new();
285
286    for token in tokens_to_check {
287        if let Some(next) = parts.peek() {
288            if token != next {
289                return Err(TokenCheck::UnexpectedToken(tokens, next.to_string()));
290            }
291            tokens.push_str(token.to_str());
292            parts.next();
293        } else {
294            return Err(TokenCheck::UnexpectedEnd(tokens));
295        }
296    }
297    Ok(())
298}
299
300#[doc(alias = "get_full_ident")]
301fn full_ident(
302    parts: &mut PeekableProcIter,
303    borrow_kind: BorrowKind,
304) -> Result<String, TokenStream> {
305    let mut name = String::new();
306    let mut prev_is_ident = false;
307
308    loop {
309        match parts.peek() {
310            Some(TokenTree::Punct(p)) => {
311                let p_s = p.to_string();
312                if p_s == "," || p_s == "=" {
313                    break;
314                } else if p_s == "." {
315                    if !prev_is_ident {
316                        return Err(parts.generate_error_with_next_span(&format!(
317                            "Unexpected `.` after `{}`",
318                            borrow_kind.to_str()
319                        )));
320                    }
321                    prev_is_ident = false;
322                    name.push('.');
323                    parts.next();
324                } else if name.is_empty() {
325                    return Err(parts
326                        .generate_error_with_next_span(&format!("Expected ident, found `{p_s}`")));
327                } else {
328                    return Err(parts.generate_error_with_next_span(&format!(
329                        "Expected ident, found `{p_s}` after `{name}`"
330                    )));
331                }
332            }
333            Some(TokenTree::Ident(i)) => {
334                if prev_is_ident {
335                    break;
336                }
337                prev_is_ident = true;
338                name.push_str(&i.to_string());
339                parts.next();
340            }
341            Some(x) if name.is_empty() => {
342                let err = format!("Expected ident, found `{x}`");
343                return Err(parts.generate_error_with_next_span(&err));
344            }
345            Some(x) => {
346                let err = &format!("Expected ident, found `{x}` after `{name}`");
347                return Err(parts.generate_error_with_next_span(err));
348            }
349            None => {
350                return Err(parts.generate_error(&format!("Unexpected end after ident `{name}`")));
351            }
352        }
353    }
354    if name.is_empty() {
355        if let Some(next) = parts.next() {
356            return Err(parts.generate_error(&format!("Expected ident, found `{next}`")));
357        }
358        return Err(parts.generate_error("Expected something after, found nothing"));
359    }
360    Ok(name)
361}
362
363#[doc(alias = "get_keyword")]
364fn keyword(parts: &mut PeekableProcIter) -> Result<BorrowKind, TokenStream> {
365    let mut ret = String::new();
366    let mut prev_is_ident = false;
367    let mut stored = false;
368    // We unfortunately can't join spans since the `Span::join` method is nightly-only. Well, we'll
369    // do our best...
370    let start_span = parts.next_span;
371
372    loop {
373        match parts.peek() {
374            Some(TokenTree::Ident(i)) => {
375                if prev_is_ident {
376                    break;
377                }
378                prev_is_ident = true;
379                if stored {
380                    ret.push('-');
381                    stored = false;
382                }
383                ret.push_str(&i.to_string());
384            }
385            Some(TokenTree::Punct(p)) if p.to_string() == "-" => {
386                if !prev_is_ident {
387                    break;
388                }
389                // This is to prevent to push `-` if the next item isn't an ident.
390                prev_is_ident = false;
391                stored = true;
392            }
393            _ => break,
394        }
395        parts.next();
396    }
397    let ret = match ret.as_str() {
398        "strong" => BorrowKind::Strong,
399        "weak" => BorrowKind::Weak,
400        "weak-allow-none" => BorrowKind::WeakAllowNone,
401        "to-owned" => BorrowKind::ToOwned,
402        "default-return" => {
403            return Err(parts
404                .generate_error_with_span("`@default-return` should be after `=>`", start_span));
405        }
406        "default-panic" => {
407            return Err(
408                parts.generate_error_with_span("`@default-panic` should be after `=>`", start_span)
409            );
410        }
411        k => {
412            return Err(parts.generate_error_with_span(
413                &format!(
414                    "Unknown keyword `{k}`, only `weak`, `weak-allow-none`, `to-owned` and \
415                    `strong` are allowed"
416                ),
417                start_span,
418            ));
419        }
420    };
421    Ok(ret)
422}
423
424fn parse_ident(
425    parts: &mut PeekableProcIter,
426    elements: &mut Vec<ElemToClone>,
427) -> Result<(), TokenStream> {
428    let borrow_kind = keyword(parts)?;
429    let name = full_ident(parts, borrow_kind)?;
430    let name_span = parts.current_span;
431    if name.ends_with('.') {
432        return Err(
433            parts.generate_error_with_span(&format!("Invalid variable name: `{name}`"), name_span)
434        );
435    }
436    let alias = match parts.peek() {
437        Some(TokenTree::Ident(p)) if p.to_string() == "as" => {
438            parts.next();
439            let current_span = parts.current_span;
440            match parts.next() {
441                Some(TokenTree::Ident(i)) => Some(i.to_string()),
442                Some(x) => {
443                    let err = format!("Expected ident after `as` keyword, found `{x}`");
444                    return Err(parts.generate_error(&err));
445                }
446                None => {
447                    return Err(parts.generate_error_with_span(
448                        "Unexpected end after `as` keyword",
449                        current_span,
450                    ))
451                }
452            }
453        }
454        Some(TokenTree::Ident(p)) => {
455            let err = format!("Unexpected `{p}`");
456            return Err(parts.generate_error(&err));
457        }
458        _ => None,
459    };
460    if name == "self" && alias.is_none() {
461        return Err(parts.generate_error_with_span(
462            "Can't use `self` as variable name. Try storing it in a temporary variable or \
463                rename it using `as`.",
464            name_span,
465        ));
466    } else if name.contains('.') && alias.is_none() {
467        let err = format!("`{name}`: Field accesses are not allowed as is, you must rename it!");
468        return Err(parts.generate_error_with_span(&err, name_span));
469    }
470
471    elements.push(ElemToClone {
472        name,
473        alias,
474        borrow_kind,
475    });
476    Ok(())
477}
478
479fn delimiter_to_string(delimiter: Delimiter, open: bool) -> &'static str {
480    match delimiter {
481        Delimiter::Parenthesis => {
482            if open {
483                "("
484            } else {
485                ")"
486            }
487        }
488        Delimiter::Brace => {
489            if open {
490                "{"
491            } else {
492                "}"
493            }
494        }
495        Delimiter::Bracket => {
496            if open {
497                "["
498            } else {
499                "]"
500            }
501        }
502        Delimiter::None => "",
503    }
504}
505
506fn group_to_string(g: &Group) -> String {
507    format!(
508        "{}{}{}",
509        delimiter_to_string(g.delimiter(), true),
510        tokens_to_string(PeekableProcIter::from(g)),
511        delimiter_to_string(g.delimiter(), false),
512    )
513}
514
515#[doc(alias = "get_expr")]
516fn expr(parts: &mut PeekableProcIter) -> Result<String, TokenStream> {
517    let mut ret = String::new();
518    let mut total = 0;
519    let span = parts.current_span;
520    match parts.next() {
521        Some(TokenTree::Literal(l)) => ret.push_str(&l.to_string()),
522        Some(TokenTree::Ident(i)) => ret.push_str(&i.to_string()),
523        Some(TokenTree::Punct(p)) => match p.to_string().as_str() {
524            "[" | "{" | "(" => {
525                total += 1;
526            }
527            x => {
528                return Err(parts
529                    .generate_error(&format!("Unexpected token `{x}` after `@default-return`")))
530            }
531        },
532        Some(TokenTree::Group(g)) => return Ok(group_to_string(&g)),
533        None => {
534            return Err(
535                parts.generate_error_with_span("Unexpected end after `@default-return`", span)
536            )
537        }
538    };
539    loop {
540        match parts.peek() {
541            Some(TokenTree::Punct(p)) => {
542                let p_s = p.to_string();
543                if p_s == "{" || p_s == "(" || p_s == "[" || p_s == "<" {
544                    total += 1;
545                } else if p_s == "}" || p_s == ")" || p_s == "]" || p_s == ">" {
546                    total -= 1;
547                } else if p_s == "," && total == 0 {
548                    return Ok(ret);
549                }
550                ret.push_str(&p_s);
551            }
552            Some(TokenTree::Group(g)) => {
553                ret.push_str(&group_to_string(g));
554            }
555            Some(x) => {
556                if total == 0 && !ret.ends_with(':') {
557                    return Ok(ret);
558                }
559                ret.push_str(&x.to_string())
560            }
561            None => return Err(parts.generate_error(
562                "Unexpected end after `{ret}`. Did you forget a `,` after the @default-return value?",
563            )),
564        }
565        parts.next();
566    }
567}
568
569#[doc(alias = "get_return_kind")]
570fn return_kind(parts: &mut PeekableProcIter) -> Result<WrapperKind, TokenStream> {
571    match check_tokens(
572        &[SimpleToken::Ident("default"), SimpleToken::Punct("-")],
573        parts,
574    ) {
575        Err(TokenCheck::UnexpectedToken(tokens, unexpected_token)) => {
576            return Err(
577                parts.generate_error(&format!("Unknown keyword `{tokens}{unexpected_token}`"))
578            );
579        }
580        Err(TokenCheck::UnexpectedEnd(tokens)) => {
581            return Err(parts.generate_error(&format!("Unexpected end after tokens `{tokens}`")));
582        }
583        Ok(()) => {}
584    }
585    let prev = parts.current_span;
586    match parts.next() {
587        Some(TokenTree::Ident(i)) => {
588            let i_s = i.to_string();
589            if i_s == "panic" {
590                return Ok(WrapperKind::DefaultPanic);
591            }
592            assert!(i_s == "return", "Unknown keyword `@default-{i_s}`");
593        }
594        Some(x) => {
595            let err = format!("Unknown token `{x}` after `@default-`");
596            return Err(parts.generate_error(&err));
597        }
598        None => {
599            return Err(parts.generate_error_with_span("Unexpected end after `@default-`", prev))
600        }
601    }
602    Ok(WrapperKind::DefaultReturn(expr(parts)?))
603}
604
605fn parse_return_kind(parts: &mut PeekableProcIter) -> Result<Option<WrapperKind>, TokenStream> {
606    match parts.peek() {
607        Some(TokenTree::Punct(p)) if p.to_string() == "@" => {}
608        None => return Err(parts.generate_error("Unexpected end 2")),
609        _ => return Ok(None),
610    }
611    parts.next();
612    let ret = return_kind(parts)?;
613    match check_tokens(&[SimpleToken::Punct(",")], parts) {
614        Err(TokenCheck::UnexpectedToken(_, unexpected_token)) => {
615            let err = format!(
616                "Expected `,` after `{}`, found `{unexpected_token}`",
617                ret.to_str(),
618            );
619            return Err(parts.generate_error_with_next_span(&err));
620        }
621        Err(TokenCheck::UnexpectedEnd(tokens)) => {
622            let err = format!("Expected `,` after `{}{tokens}`", ret.to_str());
623            return Err(parts.generate_error(&err));
624        }
625        Ok(()) => {}
626    }
627    Ok(Some(ret))
628}
629
630enum BlockKind {
631    Closure(Vec<TokenTree>),
632    ClosureWrappingAsync(Vec<TokenTree>),
633    AsyncClosure(Vec<TokenTree>),
634    AsyncBlock,
635}
636
637impl BlockKind {
638    #[doc(alias = "get_closure")]
639    fn closure(self) -> Option<Vec<TokenTree>> {
640        match self {
641            Self::AsyncBlock => None,
642            Self::Closure(c) | Self::ClosureWrappingAsync(c) | Self::AsyncClosure(c) => Some(c),
643        }
644    }
645}
646
647fn check_move_after_async(parts: &mut PeekableProcIter) -> Result<(), TokenStream> {
648    let span = parts.current_span;
649    match parts.next() {
650        Some(TokenTree::Ident(i)) if i.to_string() == "move" => Ok(()),
651        // The next checks are just for better error messages.
652        Some(TokenTree::Ident(i)) => {
653            let err = format!("Expected `move` after `async`, found `{i}`");
654            Err(parts.generate_error(&err))
655        }
656        Some(TokenTree::Punct(p)) => {
657            let err = format!("Expected `move` after `async`, found `{p}`");
658            Err(parts.generate_error(&err))
659        }
660        Some(TokenTree::Group(g)) => {
661            let err = format!(
662                "Expected `move` after `async`, found `{}`",
663                delimiter_to_string(g.delimiter(), true),
664            );
665            Err(parts.generate_error(&err))
666        }
667        _ => Err(parts.generate_error_with_span("Expected `move` after `async`", span)),
668    }
669}
670
671fn check_async_syntax(parts: &mut PeekableProcIter) -> Result<BlockKind, TokenStream> {
672    check_move_after_async(parts)?;
673    match parts.peek() {
674        Some(TokenTree::Punct(p)) if p.to_string() == "|" => {
675            parts.next();
676            Ok(BlockKind::AsyncClosure(closure(parts)?))
677        }
678        Some(TokenTree::Punct(p)) => {
679            let err = format!("Expected closure or block after `async move`, found `{p}`");
680            Err(parts.generate_error_with_next_span(&err))
681        }
682        Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Brace => Ok(BlockKind::AsyncBlock),
683        Some(TokenTree::Group(g)) => {
684            let err = format!(
685                "Expected closure or block after `async move`, found `{}`",
686                delimiter_to_string(g.delimiter(), true),
687            );
688            Err(parts.generate_error_with_next_span(&err))
689        }
690        _ => Err(parts.generate_error("Expected closure or block after `async move`")),
691    }
692}
693
694// Returns `true` if this is an async context.
695fn check_before_closure(parts: &mut PeekableProcIter) -> Result<BlockKind, TokenStream> {
696    let is_async = match parts.peek() {
697        Some(TokenTree::Ident(i)) if i.to_string() == "move" => false,
698        Some(TokenTree::Ident(i)) if i.to_string() == "async" => true,
699        Some(TokenTree::Ident(i)) if i.to_string() == "default" => {
700            let span = parts.next_span;
701            let ret = return_kind(parts)?;
702            let err = format!("Missing `@` before `{}`", ret.keyword());
703            return Err(parts.generate_error_with_span(&err, span));
704        }
705        Some(TokenTree::Punct(p)) if p.to_string() == "|" => {
706            return Err(parts.generate_error_with_next_span(
707                "Closure needs to be \"moved\" so please add `move` before closure",
708            ));
709        }
710        _ => {
711            return Err(
712                parts.generate_error_with_next_span("Missing `move` and closure declaration")
713            )
714        }
715    };
716    parts.next();
717    if is_async {
718        return check_async_syntax(parts);
719    }
720    match parts.peek() {
721        Some(TokenTree::Punct(p)) if p.to_string() == "|" => {}
722        Some(x) => {
723            let err = format!("Expected closure, found `{x}`");
724            return Err(parts.generate_error_with_next_span(&err));
725        }
726        None => return Err(parts.generate_error("Expected closure")),
727    }
728    parts.next();
729
730    let closure = closure(parts)?;
731    match parts.peek() {
732        Some(TokenTree::Ident(i)) if i.to_string() == "async" => {
733            parts.next();
734            check_move_after_async(parts)?;
735            match parts.peek() {
736                Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Brace => {
737                    Ok(BlockKind::ClosureWrappingAsync(closure))
738                }
739                // The next matchings are for better error messages.
740                Some(TokenTree::Punct(p)) => {
741                    let err = format!("Expected block after `| async move`, found `{p}`");
742                    Err(parts.generate_error_with_next_span(&err))
743                }
744                Some(TokenTree::Group(g)) => {
745                    let err = format!(
746                        "Expected block after `| async move`, found `{}`",
747                        delimiter_to_string(g.delimiter(), true),
748                    );
749                    Err(parts.generate_error_with_next_span(&err))
750                }
751                _ => {
752                    Err(parts.generate_error_with_next_span("Expected block after `| async move`"))
753                }
754            }
755        }
756        _ => Ok(BlockKind::Closure(closure)),
757    }
758}
759
760#[doc(alias = "get_closure")]
761fn closure(parts: &mut PeekableProcIter) -> Result<Vec<TokenTree>, TokenStream> {
762    let mut ret = Vec::new();
763
764    loop {
765        let span = parts.current_span;
766        match parts.next() {
767            Some(TokenTree::Punct(p)) if p.to_string() == "|" => break,
768            Some(x) => ret.push(x),
769            None => return Err(parts.generate_error_with_span("Unexpected end 3", span)),
770        }
771    }
772    Ok(ret)
773}
774
775fn tokens_to_string(parts: impl Iterator<Item = TokenTree>) -> String {
776    let mut ret = String::new();
777    // This is used in case of "if ident" or other similar cases.
778    let mut prev_is_ident = false;
779    let handle_ident_like = |i: String, ret: &mut String, prev_is_ident: &mut bool| {
780        if *prev_is_ident {
781            ret.push(' ');
782        }
783        ret.push_str(&i);
784        *prev_is_ident = true;
785    };
786
787    for token in parts {
788        match token {
789            TokenTree::Punct(p) => {
790                prev_is_ident = false;
791                ret.push_str(&p.to_string());
792            }
793            TokenTree::Ident(i) => handle_ident_like(i.to_string(), &mut ret, &mut prev_is_ident),
794            TokenTree::Literal(l) => handle_ident_like(l.to_string(), &mut ret, &mut prev_is_ident),
795            TokenTree::Group(g) => {
796                prev_is_ident = false;
797                ret.push_str(&group_to_string(&g));
798            }
799        }
800    }
801    ret
802}
803
804fn build_closure(
805    parts: PeekableProcIter,
806    elements: Vec<ElemToClone>,
807    return_kind: Option<WrapperKind>,
808    kind: BlockKind,
809) -> TokenStream {
810    let mut body = TokenStream::new();
811
812    for el in &elements {
813        let stream: TokenStream = el
814            .to_str_after(&return_kind)
815            .parse()
816            .expect("failed to convert element after");
817        body.extend(stream.into_iter().collect::<Vec<_>>());
818    }
819    body.extend(parts.collect::<Vec<_>>());
820
821    // To prevent to lose the spans in case some errors occur in the code, we need to keep `body`!
822    //
823    // If we replaced everything that follows with a `format!`, it'd look like this:
824    //
825    // format!(
826    //     "{{\n{}\nmove |{}| {{\n{}\nlet ____ret = {{ {} }};\n____ret\n}}\n}}",
827    //     elements
828    //         .iter()
829    //         .map(|x| x.to_str_before())
830    //         .collect::<Vec<_>>()
831    //         .join("\n"),
832    //     closure,
833    //     elements
834    //         .iter()
835    //         .map(|x| x.to_str_after(&return_kind))
836    //         .collect::<Vec<_>>()
837    //         .join("\n"),
838    //     body,
839    // )
840    let mut ret: Vec<TokenTree> = vec![];
841    for el in elements {
842        let stream: TokenStream = el
843            .to_str_before()
844            .parse()
845            .expect("failed to convert element");
846        ret.extend(stream.into_iter().collect::<Vec<_>>());
847    }
848
849    // This part is creating the TokenStream using the variables that needs to be cloned (from the
850    // @weak and @strong annotations).
851    let mut inner: Vec<TokenTree> = Vec::new();
852
853    {
854        let stream = "{
855#[deprecated = \"Using old-style clone! syntax\"]
856macro_rules! clone { () => {}; }
857clone!();
858}"
859        .parse::<TokenStream>()
860        .expect("can't parse deprecation");
861
862        inner.extend(stream);
863    }
864
865    if matches!(kind, BlockKind::ClosureWrappingAsync(_)) {
866        inner.extend(vec![
867            TokenTree::Ident(Ident::new("async", Span::call_site())),
868            TokenTree::Ident(Ident::new("move", Span::call_site())),
869        ]);
870    }
871
872    let is_async_closure_kind = matches!(kind, BlockKind::AsyncClosure(_));
873    if let Some(closure) = kind.closure() {
874        if is_async_closure_kind {
875            ret.push(TokenTree::Ident(Ident::new("async", Span::call_site())));
876        }
877        ret.extend(vec![
878            TokenTree::Ident(Ident::new("move", Span::call_site())),
879            TokenTree::Punct(Punct::new('|', Spacing::Alone)),
880        ]);
881        ret.extend(closure);
882        ret.extend(vec![TokenTree::Punct(Punct::new('|', Spacing::Alone))]);
883    } else {
884        ret.extend(vec![
885            TokenTree::Ident(Ident::new("async", Span::call_site())),
886            TokenTree::Ident(Ident::new("move", Span::call_site())),
887        ]);
888    }
889    // The commented lines that follow *might* be useful, don't know. Just in case, I'm keeping
890    // them around. You're welcome future me!
891    inner.extend(vec![
892        // TokenTree::Ident(Ident::new("let", Span::call_site())),
893        // TokenTree::Ident(Ident::new("____ret", Span::call_site())),
894        // TokenTree::Punct(Punct::new('=', Spacing::Alone)),
895        TokenTree::Group(Group::new(Delimiter::Brace, body)),
896        // TokenTree::Punct(Punct::new(';', Spacing::Alone)),
897        // TokenTree::Ident(Ident::new("____ret", Span::call_site())),
898    ]);
899    let mut inners = TokenStream::new();
900    inners.extend(inner);
901    ret.extend(vec![TokenTree::Group(Group::new(Delimiter::Brace, inners))]);
902
903    let mut rets = TokenStream::new();
904    rets.extend(ret);
905
906    TokenTree::Group(Group::new(Delimiter::Brace, rets)).into()
907}
908
909pub(crate) fn clone_inner(item: TokenStream) -> TokenStream {
910    let mut parts: PeekableProcIter = item.into();
911    let mut elements = Vec::new();
912    let mut prev_is_ident = false;
913
914    loop {
915        let prev = parts.current_span;
916        match parts.next() {
917            Some(TokenTree::Punct(ref p)) => {
918                let p_s = p.to_string();
919                if p_s == "=" && parts.peek().map_or_else(|| false, |n| is_punct(n, ">")) {
920                    parts.next();
921                    break;
922                } else if p_s == "@" {
923                    if let Err(e) = parse_ident(&mut parts, &mut elements) {
924                        return e;
925                    }
926                    prev_is_ident = true;
927                } else if p_s == "," {
928                    assert!(prev_is_ident, "Unexpected `,`");
929                    prev_is_ident = false;
930                } else if p_s == "|" {
931                    assert!(
932                        !elements.is_empty(),
933                        "If you have nothing to clone, no need to use this macro!"
934                    );
935                    return parts.generate_error("Expected `=>` before closure");
936                }
937            }
938            Some(TokenTree::Ident(i)) => {
939                let err = format!(
940                    "Unexpected ident `{i}`: you need to specify if this is a weak or a strong \
941                     clone.",
942                );
943                return parts.generate_error(&err);
944            }
945            Some(t) => {
946                let err = format!("Unexpected token `{t}`");
947                return parts.generate_error(&err);
948            }
949            None => return parts.generate_error_with_span("Unexpected end 4", prev),
950        }
951    }
952    assert!(
953        !elements.is_empty(),
954        "If you have nothing to clone, no need to use this macro!"
955    );
956    let return_kind = match parse_return_kind(&mut parts) {
957        Ok(r) => r,
958        Err(e) => return e,
959    };
960    let kind = match check_before_closure(&mut parts) {
961        Ok(r) => r,
962        Err(e) => return e,
963    };
964    build_closure(parts, elements, return_kind, kind)
965}