1use crate::{
4 core::compile::{ast::*, build::*, builtin::*},
5 match1,
6};
7use prelude::{Namespace, NamespacedObject};
8use quote::quote;
9use std::collections::BTreeMap;
10
11#[derive(Clone, Debug, PartialEq)]
12pub enum Python {
13 None,
15 List,
16 Tuple,
17 Int,
18 Bool,
19 Str,
20 Iter,
22 AsLen,
23 Abs,
25 Print,
26 Min,
27 Max,
28 Round,
29 Range,
30 Len,
31 Enumerate,
32 Filter,
33 Map,
34 Zip,
35 Sorted,
36 Sum,
37 ListConstructor,
38}
39
40pub fn namespace() -> Namespace {
42 let data = [
43 ("None", Python::None),
44 ("List", Python::List),
45 ("Tuple", Python::Tuple),
46 ("int", Python::Int),
47 ("bool", Python::Bool),
48 ("str", Python::Str),
49 ("abs", Python::Abs),
50 ("print", Python::Print),
51 ("min", Python::Min),
52 ("max", Python::Max),
53 ("round", Python::Round),
54 ("range", Python::Range),
55 ("len", Python::Len),
56 ("enumerate", Python::Enumerate),
57 ("filter", Python::Filter),
58 ("map", Python::Map),
59 ("zip", Python::Zip),
60 ("sorted", Python::Sorted),
61 ("sum", Python::Sum),
62 ("list", Python::ListConstructor),
63 ];
64
65 let mut namespace = BTreeMap::new();
66 for (name, obj) in data.into_iter() {
67 namespace.insert(
68 name.to_string(),
69 NamespacedObject::Automatic(Builtin::Python(obj)),
70 );
71 }
72
73 return namespace;
74}
75
76impl BuiltinSource for Python {
77 fn name(&self) -> String {
78 match self {
79 Self::None => "None",
80 Self::List => "List",
81 Self::Tuple => "Tuple",
82 Self::Int => "int",
83 Self::Bool => "bool",
84 Self::Str => "str",
85 Self::Iter => "<Iter>",
86 Self::AsLen => "<Len>",
87 Self::Abs => "abs",
88 Self::Print => "print",
89 Self::Min => "min",
90 Self::Max => "max",
91 Self::Round => "round",
92 Self::Range => "range",
93 Self::Len => "len",
94 Self::Enumerate => "enumerate",
95 Self::Filter => "filter",
96 Self::Map => "map",
97 Self::Zip => "zip",
98 Self::Sorted => "sorted",
99 Self::Sum => "sum",
100 Self::ListConstructor => "list",
101 }
102 .to_string()
103 }
104
105 fn ty(&self) -> Ty {
106 match self {
107 Self::Str => Ty::Type(
108 TyName::Builtin(Builtin::Python(self.clone())),
109 Some(Ty::new_function(
110 vec![("", Ty::Any, ParamType::Required)],
111 Ty::Transformed(
112 Ty::python(Self::Str, vec![]).into(),
113 Transformation::new(|mut expr| {
114 let s = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter().next().unwrap());
115
116 expr.obj = if expr.ty.is_display() {
117 ExpressionObj::Rendered(quote! {
118 format!("{}", #s)
119 })
120 } else {
121 ExpressionObj::Rendered(quote! {
122 format!("{:?}", #s)
123 })
124 };
125
126 Ok(Transformed::Expression(expr))
127 })
128 )
129 ).into())
130 ),
131 Self::Abs => Ty::new_function(
133 vec![("x", Ty::Anonymous(0), ParamType::Required)],
134 Ty::Transformed(
135 Ty::Anonymous(0).into(),
136 Transformation::new(|mut expr| {
137 let x = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter().next().unwrap());
138
139 match &expr.ty {
140 Ty::Generic(TyName::Builtin(Builtin::Prelude(Prelude::RustInt(true, _) | Prelude::RustFloat)), _) => {},
141 _ => {
142 return Err(CoreError::make_raw(
143 "cannot take the absolute value of an unsigned integer",
144 ""
145 ))
146 }
147 }
148
149 expr.obj = ExpressionObj::Rendered(quote! {
150 #x.abs()
151 });
152
153 Ok(Transformed::Expression(expr))
154 })
155 )
156 ),
157 Self::Print => Ty::new_function(
159 vec![("", Ty::Any.into(), ParamType::Variadic)],
160 Ty::Transformed(
161 Ty::python(Self::None, vec![]).into(),
162 Transformation::new(|expr| {
163 let args = match1!(expr.obj, ExpressionObj::Call { mut args, .. } => args.remove(0));
164 let args = match1!(args.obj, ExpressionObj::Vec(args) => args);
165
166 let mut format = String::new();
167 for arg in args.iter() {
168 if format.len() > 0 {
169 format.push_str(" ");
170 }
171
172 format.push_str(if arg.ty.is_display() { "{}" } else { "{:?}" });
173 }
174
175 Ok(Transformed::Expression(
176 ExpressionObj::Rendered(quote! {
177 solana_program::msg!(#format, #(#args),*)
178 })
179 .into(),
180 ))
181 }),
182 ),
183 ),
184 Self::Min => Ty::new_function(
186 vec![("", Ty::Anonymous(0), ParamType::Variadic)],
187 Ty::Transformed(
188 Ty::Anonymous(0).into(),
189 Transformation::new(|expr| {
190 let args = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter().next().unwrap());
191 let mut parts =
192 match1!(args.obj, ExpressionObj::Vec(parts) => parts.into_iter());
193 if parts.len() < 2 {
194 return Err(CoreError::make_raw(
195 "min() requires at least 1 argument",
196 "",
197 ));
198 }
199
200 let mut accum = parts.next().unwrap();
201 for part in parts {
202 accum.obj = accum.obj.with_call("min", vec![part]);
203 }
204
205 Ok(Transformed::Expression(accum))
206 }),
207 ),
208 ),
209 Self::Max => Ty::new_function(
211 vec![("", Ty::Anonymous(0), ParamType::Variadic)],
212 Ty::Transformed(
213 Ty::Anonymous(0).into(),
214 Transformation::new(|expr| {
215 let args = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter().next().unwrap());
216 let mut parts =
217 match1!(args.obj, ExpressionObj::Vec(parts) => parts.into_iter());
218 if parts.len() < 2 {
219 return Err(CoreError::make_raw(
220 "max() requires at least 1 argument",
221 "",
222 ));
223 }
224
225 let mut accum = parts.next().unwrap();
226 for part in parts {
227 accum.obj = accum.obj.with_call("max", vec![part]);
228 }
229
230 Ok(Transformed::Expression(accum))
231 }),
232 ),
233 ),
234 Self::Round => Ty::new_function(
236 vec![(
237 "x",
238 Ty::prelude(Prelude::RustFloat, vec![]),
239 ParamType::Required,
240 )],
241 Ty::Transformed(
242 Ty::prelude(Prelude::RustInt(true, 128), vec![]).into(),
243 Transformation::new(|mut expr| {
244 let args = match1!(expr.obj, ExpressionObj::Call { args, .. } => args);
245 let x = args.into_iter().next().unwrap();
246
247 expr.obj = ExpressionObj::As {
248 value: ExpressionObj::Rendered(quote! { #x.round() }).into(),
249 ty: TyExpr::new_specific(vec!["i128"], Mutability::Immutable)
250 };
251
252 Ok(Transformed::Expression(expr))
253 }),
254 ),
255 ),
256 Self::Range => Ty::new_function(
258 vec![
259 ("start", Ty::Anonymous(0), ParamType::Required),
260 ("stop", Ty::Anonymous(0), ParamType::Optional),
261 ("step", Ty::Anonymous(0), ParamType::Optional)
262 ],
263 Ty::Transformed(
264 Ty::python(Self::Iter, vec![Ty::Anonymous(0)]).into(),
265 Transformation::new(|mut expr| {
266 let mut args =
267 match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter());
268 let start = args.next().unwrap();
269 let stop = args.next().unwrap();
270 let step = args.next().unwrap();
271
272 let range = match stop.obj {
273 ExpressionObj::Placeholder => ExpressionObj::Rendered(quote! {
274 0 .. #start
275 }),
276 stop => ExpressionObj::Rendered(quote! {
277 #start .. #stop
278 }),
279 };
280
281 let range = match step.obj {
282 ExpressionObj::Placeholder => range,
283 step => ExpressionObj::Rendered(quote! {
284 (#range).step_by(#step.try_into().unwrap())
285 })
286 };
287
288 expr.obj = range;
289
290 Ok(Transformed::Expression(expr))
291 }),
292 ),
293 ),
294 Self::Len => Ty::new_function(
296 vec![
297 ("iterable", Ty::Cast(Ty::python(Self::AsLen, vec![]).into()), ParamType::Required)
298 ],
299 Ty::Transformed(
300 Ty::prelude(Prelude::RustInt(false, 64), vec![]).into(),
301 Transformation::new(|mut expr| {
302 let len = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter().next().unwrap());
303
304 expr.obj = len.obj;
305
306 Ok(Transformed::Expression(expr))
307 })
308 )
309 ),
310 Self::Enumerate => Ty::new_function(
312 vec![(
313 "iterable",
314 Ty::Cast(Ty::python(Self::Iter, vec![Ty::Anonymous(0)]).into()),
315 ParamType::Required,
316 )],
317 Ty::Transformed(
318 Ty::python(
319 Self::Iter,
320 vec![Ty::python(
321 Self::Tuple,
322 vec![
323 Ty::prelude(Prelude::RustInt(false, 64), vec![]),
324 Ty::Anonymous(0),
325 ],
326 )],
327 )
328 .into(),
329 Transformation::new(|mut expr| {
330 let iterable = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter().next().unwrap());
331
332 expr.obj = ExpressionObj::Rendered(quote! {
333 (#iterable).enumerate().map(|(i, x)| (i as u64, x))
334 });
335
336 Ok(Transformed::Expression(expr))
337 }),
338 ),
339 ),
340 Self::Filter => Ty::new_function(
342 vec![
343 (
344 "function",
345 Ty::new_function(
346 vec![
347 ("x", Ty::Anonymous(0), ParamType::Required)
348 ],
349 Ty::python(Self::Bool, vec![])
350 ),
351 ParamType::Required
352 ),
353 (
354 "iterable",
355 Ty::Cast(Ty::python(Self::Iter, vec![Ty::Anonymous(0)]).into()),
356 ParamType::Required,
357 )
358 ],
359 Ty::Transformed(
360 Ty::python(Self::Iter, vec![Ty::Anonymous(0)]).into(),
361 Transformation::new(|mut expr| {
362 let mut args = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter());
363 let function = args.next().unwrap();
364 let iterable = args.next().unwrap();
365
366 let return_ty = match1!(&function.ty, Ty::Function(_, returns) => *returns.clone());
367
368 let elem = ExpressionObj::Rendered(quote! { elem.clone() });
369 let call = ExpressionObj::Call {
370 function: function.into(),
371 args: vec![elem.into()]
372 }.into();
373
374 let elem = match return_ty {
375 Ty::Transformed(_, transformation) => match (transformation.function)(call, &vec![].into())? {
376 Transformed::Expression(expression) => expression,
377 _ => {
378 return Err(CoreError::make_raw(
379 "can not filter using a special function",
380 "Hint: this function causes an effect that needs compiler magic to work, and can't be called from a filter."
381 ));
382 }
383 }
384 _ => call
385 };
386
387 expr.obj = ExpressionObj::Rendered(quote! {
388 #iterable.filter(|elem| #elem)
389 });
390
391 Ok(Transformed::Expression(expr))
392 })
393 )
394 ),
395 Self::Map => Ty::new_function(
397 vec![
398 (
399 "function",
400 Ty::new_function(
401 vec![
402 ("x", Ty::Anonymous(0), ParamType::Required)
403 ],
404 Ty::Anonymous(1)
405 ),
406 ParamType::Required
407 ),
408 (
409 "iterable",
410 Ty::Cast(Ty::python(Self::Iter, vec![Ty::Anonymous(0)]).into()),
411 ParamType::Required,
412 )
413 ],
414 Ty::Transformed(
415 Ty::python(Self::Iter, vec![Ty::Anonymous(1)]).into(),
416 Transformation::new(|mut expr| {
417 let mut args = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter());
418 let function = args.next().unwrap();
419 let iterable = args.next().unwrap();
420
421 let return_ty = match1!(&function.ty, Ty::Function(_, returns) => *returns.clone());
422
423 let elem = ExpressionObj::Rendered(quote! { elem.clone() });
424 let call = ExpressionObj::Call {
425 function: function.into(),
426 args: vec![elem.into()]
427 }.into();
428
429 let elem = match return_ty {
430 Ty::Transformed(_, transformation) => match (transformation.function)(call, &vec![].into())? {
431 Transformed::Expression(expression) => expression,
432 _ => {
433 return Err(CoreError::make_raw(
434 "can not map using a special function",
435 "Hint: this function causes an effect that needs compiler magic to work, and can't be called from a map."
436 ));
437 }
438 }
439 _ => call
440 };
441
442 expr.obj = ExpressionObj::Rendered(quote! {
443 #iterable.map(|elem| #elem)
444 });
445
446 Ok(Transformed::Expression(expr))
447 })
448 )
449 ),
450 Self::Zip => Ty::new_function(
456 vec![
457 (
458 "iterable1",
459 Ty::Cast(Ty::python(Self::Iter, vec![Ty::Anonymous(0)]).into()),
460 ParamType::Required,
461 ),
462 (
463 "iterable2",
464 Ty::Cast(Ty::python(Self::Iter, vec![Ty::Anonymous(1)]).into()),
465 ParamType::Required,
466 )
467 ],
468 Ty::Transformed(
469 Ty::python(Self::Iter, vec![
470 Ty::python(Self::Tuple, vec![Ty::Anonymous(0), Ty::Anonymous(1)])
471 ]).into(),
472 Transformation::new(|mut expr| {
473 let mut args = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter());
474 let iterable1 = args.next().unwrap();
475 let iterable2 = args.next().unwrap();
476
477 expr.obj = ExpressionObj::Rendered(quote! {
478 #iterable1.zip(#iterable2)
479 });
480
481 Ok(Transformed::Expression(expr))
482 })
483 )
484 ),
485 Self::Sorted => Ty::new_function(
488 vec![(
489 "iterable",
490 Ty::Cast(Ty::python(Self::Iter, vec![Ty::Anonymous(0)]).into()),
491 ParamType::Required,
492 )],
493 Ty::Transformed(
494 Ty::python(
495 Self::List,
496 vec![Ty::Anonymous(0)],
497 ).into(),
498 Transformation::new(|mut expr| {
499 let iterable = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter().next().unwrap());
500
501 expr.obj = ExpressionObj::Rendered(quote! {
502 Mutable::new({
503 let mut temp = #iterable.collect::<Vec<_>>();
504 temp.sort();
505 temp
506 })
507 });
508
509 Ok(Transformed::Expression(expr))
510 }),
511 ),
512 ),
513 Self::Sum => Ty::new_function(
515 vec![(
516 "iterable",
517 Ty::Cast(Ty::python(Self::Iter, vec![Ty::Anonymous(0)]).into()),
518 ParamType::Required,
519 )],
520 Ty::Transformed(
521 Ty::Anonymous(0).into(),
522 Transformation::new(|mut expr| {
523 let iterable = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter().next().unwrap());
524
525 let init = match &expr.ty {
526 Ty::Generic(TyName::Builtin(Builtin::Prelude(Prelude::RustInt(..))), _) => quote! { 0 },
527 Ty::IntParam(..) => quote! { 0 },
528 Ty::Generic(TyName::Builtin(Builtin::Prelude(Prelude::RustFloat)), _) => quote! { 0.0 },
529 ty => {
530 return Err(CoreError::make_raw(
531 format!("cannot perform sum of type {}", ty),
532 "Hint: sums can be performed on numeric types only."
533 ))
534 }
535 };
536
537 expr.obj = ExpressionObj::Rendered(quote! {
538 #iterable.fold(#init, |accum, elem| accum + elem)
541 });
542
543 Ok(Transformed::Expression(expr))
544 })
545 )
546 ),
547 Self::ListConstructor => Ty::new_function(
549 vec![(
550 "iterable",
551 Ty::Cast(Ty::python(Self::Iter, vec![Ty::Anonymous(0)]).into()),
552 ParamType::Required,
553 )],
554 Ty::Transformed(
555 Ty::python(
556 Self::List,
557 vec![Ty::Anonymous(0)],
558 ).into(),
559 Transformation::new(|mut expr| {
560 let iterable = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter().next().unwrap());
561
562 expr.obj = ExpressionObj::Rendered(quote! {
563 Mutable::new((#iterable).collect::<Vec<_>>())
564 });
565
566 Ok(Transformed::Expression(expr))
567 }),
568 ),
569 ),
570 name => Ty::Type(TyName::Builtin(Builtin::Python(name.clone())), None),
571 }
572 }
573
574 fn as_instance(&self, params: &Vec<Ty>) -> CResult<()> {
575 match self {
576 Self::List if params.len() == 1 => Ok(()),
577 Self::Tuple => Ok(()),
578 Self::None | Self::Int if params.len() == 0 => Ok(()),
579 _ => Err(CoreError::make_raw("invalid type", "")),
580 }
581 }
582
583 fn attr(&self, attr: &String) -> Option<(Ty, Ty)> {
584 match (self, attr.as_str()) {
585 (Self::List, "append") => Some((
587 Ty::python(self.clone(), vec![Ty::Anonymous(0)]),
588 Ty::new_function(
589 vec![("x", Ty::Anonymous(0), ParamType::Required)],
590 Ty::Transformed(
591 Ty::python(Self::Tuple, vec![]).into(),
592 Transformation::new(|mut expr| {
593 let (function, args) = match1!(expr.obj, ExpressionObj::Call { function, args } => (*function, args));
594 let value = match1!(function.obj, ExpressionObj::Attribute { value, .. } => *value);
595
596 expr.obj = ExpressionObj::Rendered(quote! {
597 #value.borrow_mut().push(#(#args),*)
598 });
599
600 Ok(Transformed::Expression(expr))
601 }),
602 ),
603 ),
604 )),
605 (Self::List, "pop") => Some((
607 Ty::python(self.clone(), vec![Ty::Anonymous(0)]),
608 Ty::new_function(
609 vec![],
610 Ty::Transformed(
611 Ty::Anonymous(0).into(),
612 Transformation::new(|mut expr| {
613 let function = match1!(expr.obj, ExpressionObj::Call { function, .. } => *function);
614 let value = match1!(function.obj, ExpressionObj::Attribute { value, .. } => *value);
615
616 expr.obj = ExpressionObj::Rendered(quote! {
617 #value.borrow_mut().pop().unwrap()
618 });
619
620 Ok(Transformed::Expression(expr))
621 }),
622 ),
623 ),
624 )),
625 _ => None,
626 }
627 }
628
629 fn index(&self) -> Option<(Ty, Ty)> {
630 match self {
631 Self::List => Some((
633 Ty::python(self.clone(), vec![Ty::Anonymous(0)]),
634 Ty::new_function(
635 vec![
636 ("", Ty::Cast(Ty::prelude(Prelude::RustInt(true, 128), vec![]).into()), ParamType::Required)
637 ],
638 Ty::Transformed(
639 Ty::Anonymous(0).into(),
640 Transformation::new(|mut expr| {
641 let (value, index) = match1!(expr.obj, ExpressionObj::Index { value, index } => (*value, *index));
642
643 if let ExpressionObj::BorrowMut(..) = &value.obj {
644 expr.obj = ExpressionObj::Rendered(quote! {
645 (*#value.index_wrapped_mut(#index.into()))
646 });
647 } else {
648 expr.obj = ExpressionObj::Rendered(quote! {
649 (*#value.index_wrapped(#index.into()))
650 });
651 }
652
653 Ok(Transformed::Expression(expr))
654 })
655 ).into()
656 )
657 )),
658 _ => None
659 }
660 }
661
662 fn static_attr(&self, attr: &String) -> Option<Ty> {
663 None
664 }
665
666 fn casted(&self, ty: &Ty) -> Option<(Ty, Ty)> {
667 let builtin = if let Ty::Generic(TyName::Builtin(builtin), _) = ty {
668 builtin
669 } else {
670 return None;
671 };
672
673 match self {
674 Self::List => match builtin {
675 Builtin::Python(Self::Iter) => Some((
676 Ty::python(Self::List, vec![Ty::Anonymous(0)]),
677 Ty::Transformed(
678 Ty::python(Self::Iter, vec![Ty::Anonymous(0)]).into(),
679 Transformation::new(|mut expr| {
680 let list = expr.obj;
681
682 expr.obj = ExpressionObj::Rendered(quote! {
683 #list.borrow().iter().map(|elem| elem.clone())
684 });
685
686 Ok(Transformed::Expression(expr))
687 }),
688 ),
689 )),
690 Builtin::Python(Self::AsLen) => Some((
691 Ty::python(self.clone(), vec![Ty::Anonymous(0)]),
692 Ty::Transformed(
693 Ty::python(Self::AsLen, vec![]).into(),
694 Transformation::new(|mut expr| {
695 let list = expr.obj;
696
697 expr.obj = ExpressionObj::Rendered(quote! {
698 (#list.borrow().len() as u64)
699 });
700
701 Ok(Transformed::Expression(expr))
702 }),
703 ),
704 )),
705 Builtin::Prelude(Prelude::Seed) => Some((
706 Ty::python(
707 self.clone(),
708 vec![Ty::prelude(Prelude::RustInt(false, 8), vec![])],
709 ),
710 Ty::Transformed(
711 Ty::prelude(Prelude::Seed, vec![]).into(),
712 Transformation::new(|mut expr| {
713 let err = CoreError::make_raw(
714 "to use a list of bytes as a seed, the list must be known at compile-time",
715 ""
716 );
717
718 let list = match expr.obj {
719 ExpressionObj::Mutable(obj) => match obj.obj {
720 ExpressionObj::Vec(list) => {
721 list.into_iter().map(|element| element.without_borrows())
722 }
723 _ => {
724 return Err(err);
725 }
726 },
727 _ => {
728 return Err(err);
729 }
730 };
731
732 expr.obj = ExpressionObj::Rendered(quote! {
733 [#(#list),*].as_ref()
734 });
735
736 Ok(Transformed::Expression(expr))
737 }),
738 ),
739 )),
740 _ => None,
741 },
742 Self::Str => match builtin {
743 Builtin::Prelude(Prelude::Seed) => Some((
744 Ty::python(Python::Str, vec![]),
745 Ty::Transformed(
746 Ty::prelude(Prelude::Seed, vec![]).into(),
747 Transformation::new(|mut expr| {
748 let obj = expr.obj.without_borrows();
750 expr.obj = ExpressionObj::Rendered(quote! {
751 #obj.as_bytes().as_ref()
752 });
753
754 Ok(Transformed::Expression(expr))
755 }),
756 ),
757 )),
758 Builtin::Python(Self::AsLen) => Some((
759 Ty::python(self.clone(), vec![]),
760 Ty::Transformed(
761 Ty::python(Self::AsLen, vec![]).into(),
762 Transformation::new(|mut expr| {
763 let string = expr.obj;
764
765 expr.obj = ExpressionObj::Rendered(quote! {
766 (#string.chars().count() as u64)
767 });
768
769 Ok(Transformed::Expression(expr))
770 }),
771 ),
772 )),
773 _ => None,
774 },
775 Self::Iter => match builtin {
776 Builtin::Python(Self::Iter) => Some((
777 Ty::python(Self::Iter, vec![Ty::Anonymous(0)]),
778 Ty::python(Self::Iter, vec![Ty::Anonymous(0)]),
779 )),
780 Builtin::Python(Self::AsLen) => Some((
781 Ty::python(self.clone(), vec![Ty::Anonymous(0)]),
782 Ty::Transformed(
783 Ty::python(Self::AsLen, vec![]).into(),
784 Transformation::new(|mut expr| {
785 let iterable = expr.obj;
786
787 expr.obj = ExpressionObj::Rendered(quote! {
788 (#iterable.count() as u64)
789 });
790
791 Ok(Transformed::Expression(expr))
792 }),
793 ),
794 )),
795 _ => None,
796 },
797 _ => None,
798 }
799 }
800}