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: Option = Some(f.span());
21 let mut inner: impl Iterator = f.stream().into_iter().peekable();
22 let next_span: Option = inner.peek().map(|n: &TokenTree| 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: impl Iterator = f.into_iter().peekable();
34 let next_span: Option = inner.peek().map(|n: &TokenTree| 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: TokenTree = self.inner.next()?;
48 self.current_span = Some(next.span());
49 self.next_span = self.inner.peek().map(|n: &TokenTree| 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: &String) => 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: &str) => p,
253 Self::Ident(i: &str) => 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: &&str), TokenTree::Punct(ref p2: &Punct)) => *p1 == p2.to_string(),
262 (SimpleToken::Ident(i1: &&str), TokenTree::Ident(ref i2: &Ident)) => *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: &Punct) => 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 = String::new();
285
286 for token: &SimpleToken in tokens_to_check {
287 if let Some(next: &TokenTree) = parts.peek() {
288 if token != next {
289 return Err(TokenCheck::UnexpectedToken(tokens, next.to_string()));
290 }
291 tokens.push_str(string: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: &Punct)) if p.to_string() == "@" => {}
608 None => return Err(parts.generate_error(message:"Unexpected end 2")),
609 _ => return Ok(None),
610 }
611 parts.next();
612 let ret: WrapperKind = return_kind(parts)?;
613 match check_tokens(&[SimpleToken::Punct(",")], parts) {
614 Err(TokenCheck::UnexpectedToken(_, unexpected_token: String)) => {
615 let err: String = 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: String)) => {
622 let err: String = 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: Vec) | Self::ClosureWrappingAsync(c: Vec) | Self::AsyncClosure(c: Vec) => Some(c),
643 }
644 }
645}
646
647fn check_move_after_async(parts: &mut PeekableProcIter) -> Result<(), TokenStream> {
648 let span: Option = parts.current_span;
649 match parts.next() {
650 Some(TokenTree::Ident(i: Ident)) if i.to_string() == "move" => Ok(()),
651 // The next checks are just for better error messages.
652 Some(TokenTree::Ident(i: Ident)) => {
653 let err: String = format!("Expected `move` after `async`, found `{i}`");
654 Err(parts.generate_error(&err))
655 }
656 Some(TokenTree::Punct(p: Punct)) => {
657 let err: String = format!("Expected `move` after `async`, found `{p}`");
658 Err(parts.generate_error(&err))
659 }
660 Some(TokenTree::Group(g: Group)) => {
661 let err: String = 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(message:"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: &Punct)) if p.to_string() == "|" => {
675 parts.next();
676 Ok(BlockKind::AsyncClosure(closure(parts)?))
677 }
678 Some(TokenTree::Punct(p: &Punct)) => {
679 let err: String = 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: &Group)) if g.delimiter() == Delimiter::Brace => Ok(BlockKind::AsyncBlock),
683 Some(TokenTree::Group(g: &Group)) => {
684 let err: String = 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(message:"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 = Vec::new();
763
764 loop {
765 let span: Option = parts.current_span;
766 match parts.next() {
767 Some(TokenTree::Punct(p: Punct)) if p.to_string() == "|" => break,
768 Some(x: TokenTree) => ret.push(x),
769 None => return Err(parts.generate_error_with_span(message:"Unexpected end 3", span)),
770 }
771 }
772 Ok(ret)
773}
774
775pub fn 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 if matches!(kind, BlockKind::ClosureWrappingAsync(_)) {
853 inner.extend(vec![
854 TokenTree::Ident(Ident::new("async", Span::call_site())),
855 TokenTree::Ident(Ident::new("move", Span::call_site())),
856 ]);
857 }
858
859 let is_async_closure_kind = matches!(kind, BlockKind::AsyncClosure(_));
860 if let Some(closure) = kind.closure() {
861 if is_async_closure_kind {
862 ret.push(TokenTree::Ident(Ident::new("async", Span::call_site())));
863 }
864 ret.extend(vec![
865 TokenTree::Ident(Ident::new("move", Span::call_site())),
866 TokenTree::Punct(Punct::new('|', Spacing::Alone)),
867 ]);
868 ret.extend(closure);
869 ret.extend(vec![TokenTree::Punct(Punct::new('|', Spacing::Alone))]);
870 } else {
871 ret.extend(vec![
872 TokenTree::Ident(Ident::new("async", Span::call_site())),
873 TokenTree::Ident(Ident::new("move", Span::call_site())),
874 ]);
875 }
876 // The commented lines that follow *might* be useful, don't know. Just in case, I'm keeping
877 // them around. You're welcome future me!
878 inner.extend(vec![
879 // TokenTree::Ident(Ident::new("let", Span::call_site())),
880 // TokenTree::Ident(Ident::new("____ret", Span::call_site())),
881 // TokenTree::Punct(Punct::new('=', Spacing::Alone)),
882 TokenTree::Group(Group::new(Delimiter::Brace, body)),
883 // TokenTree::Punct(Punct::new(';', Spacing::Alone)),
884 // TokenTree::Ident(Ident::new("____ret", Span::call_site())),
885 ]);
886 let mut inners = TokenStream::new();
887 inners.extend(inner);
888 ret.extend(vec![TokenTree::Group(Group::new(Delimiter::Brace, inners))]);
889
890 let mut rets = TokenStream::new();
891 rets.extend(ret);
892
893 TokenTree::Group(Group::new(Delimiter::Brace, rets)).into()
894}
895
896pub(crate) fn clone_inner(item: TokenStream) -> TokenStream {
897 let mut parts: PeekableProcIter = item.into();
898 let mut elements = Vec::new();
899 let mut prev_is_ident = false;
900
901 loop {
902 let prev = parts.current_span;
903 match parts.next() {
904 Some(TokenTree::Punct(ref p)) => {
905 let p_s = p.to_string();
906 if p_s == "=" && parts.peek().map_or_else(|| false, |n| is_punct(n, ">")) {
907 parts.next();
908 break;
909 } else if p_s == "@" {
910 if let Err(e) = parse_ident(&mut parts, &mut elements) {
911 return e;
912 }
913 prev_is_ident = true;
914 } else if p_s == "," {
915 assert!(prev_is_ident, "Unexpected `,`");
916 prev_is_ident = false;
917 } else if p_s == "|" {
918 assert!(
919 !elements.is_empty(),
920 "If you have nothing to clone, no need to use this macro!"
921 );
922 return parts.generate_error("Expected `=>` before closure");
923 }
924 }
925 Some(TokenTree::Ident(i)) => {
926 let err = format!(
927 "Unexpected ident `{i}`: you need to specify if this is a weak or a strong \
928 clone.",
929 );
930 return parts.generate_error(&err);
931 }
932 Some(t) => {
933 let err = format!("Unexpected token `{t}`");
934 return parts.generate_error(&err);
935 }
936 None => return parts.generate_error_with_span("Unexpected end 4", prev),
937 }
938 }
939 assert!(
940 !elements.is_empty(),
941 "If you have nothing to clone, no need to use this macro!"
942 );
943 let return_kind = match parse_return_kind(&mut parts) {
944 Ok(r) => r,
945 Err(e) => return e,
946 };
947 let kind = match check_before_closure(&mut parts) {
948 Ok(r) => r,
949 Err(e) => return e,
950 };
951 build_closure(parts, elements, return_kind, kind)
952}
953