1use crate::metadata::{ContractMetadataKind, MAX_METADATA_DEPTH};
2use ab_io_type::metadata::{IoTypeDetails, IoTypeMetadataKind};
3use core::mem::ManuallyDrop;
4use derive_destructure2::destructure;
5
6#[derive(Debug, thiserror::Error)]
8pub enum MetadataDecodingError<'metadata> {
9 #[error("Not enough metadata to decode")]
11 NotEnoughMetadata,
12 #[error("Invalid first metadata byte")]
14 InvalidFirstMetadataByte { byte: u8 },
15 #[error("Multiple contracts found")]
17 MultipleContractsFound,
18 #[error("Expected contract or trait kind, found something else: {metadata_kind:?}")]
20 ExpectedContractOrTrait { metadata_kind: ContractMetadataKind },
21 #[error("Failed to decode state type name")]
23 FailedToDecodeStateTypeName,
24 #[error("Invalid state I/O type")]
26 InvalidStateIoType,
27 #[error("Unexpected method kind {method_kind:?} for container kind {container_kind:?}")]
29 UnexpectedMethodKind {
30 method_kind: MethodKind,
31 container_kind: MethodsContainerKind,
32 },
33 #[error("Expected method kind, found something else: {metadata_kind:?}")]
35 ExpectedMethodKind { metadata_kind: ContractMetadataKind },
36 #[error("Expected argument kind, found something else: {metadata_kind:?}")]
38 ExpectedArgumentKind { metadata_kind: ContractMetadataKind },
39 #[error("Unexpected argument kind {argument_kind:?} for method kind {method_kind:?}")]
41 UnexpectedArgumentKind {
42 argument_kind: ArgumentKind,
43 method_kind: MethodKind,
44 },
45 #[error("Argument of kind {argument_kind:?} is out of order")]
48 ArgumentOutOfOrder { argument_kind: ArgumentKind },
49 #[error("Invalid argument I/O type of kind {argument_kind:?} for {argument_name:?}")]
51 InvalidArgumentIoType {
52 argument_name: &'metadata [u8],
53 argument_kind: ArgumentKind,
54 },
55}
56
57#[derive(Debug)]
58pub enum MetadataItem<'a, 'metadata> {
59 Contract {
60 state_type_name: &'metadata [u8],
65 state_type_details: IoTypeDetails,
66 slot_type_details: IoTypeDetails,
67 tmp_type_details: IoTypeDetails,
68 num_methods: u8,
69 decoder: MethodsMetadataDecoder<'a, 'metadata>,
70 },
71 Trait {
72 trait_name: &'metadata [u8],
77 num_methods: u8,
78 decoder: MethodsMetadataDecoder<'a, 'metadata>,
79 },
80}
81
82impl<'a, 'metadata> MetadataItem<'a, 'metadata> {
83 #[inline(always)]
84 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
85 #[expect(
86 clippy::rest_pattern_accessible_field,
87 reason = "Do not need other fields"
88 )]
89 pub fn num_methods(&self) -> u8 {
90 match self {
91 MetadataItem::Contract { num_methods, .. }
92 | MetadataItem::Trait { num_methods, .. } => *num_methods,
93 }
94 }
95
96 #[inline(always)]
97 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
98 #[expect(
99 clippy::rest_pattern_accessible_field,
100 reason = "Do not need other fields"
101 )]
102 pub fn into_decoder(self) -> MethodsMetadataDecoder<'a, 'metadata> {
103 match self {
104 MetadataItem::Contract { decoder, .. } | MetadataItem::Trait { decoder, .. } => decoder,
105 }
106 }
107}
108
109#[derive(Debug)]
110pub struct MetadataDecoder<'metadata> {
111 metadata: &'metadata [u8],
112 found_contract: bool,
113 found_something: bool,
114}
115
116impl<'metadata> MetadataDecoder<'metadata> {
117 #[inline(always)]
118 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
119 pub fn new(metadata: &'metadata [u8]) -> Self {
120 Self {
121 metadata,
122 found_contract: false,
123 found_something: false,
124 }
125 }
126
127 #[inline(always)]
129 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
130 pub fn remaining_metadata_bytes(&self) -> usize {
131 self.metadata.len()
132 }
133
134 #[inline]
136 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
137 pub fn decode_next<'a>(
138 &'a mut self,
139 ) -> Option<Result<MetadataItem<'a, 'metadata>, MetadataDecodingError<'metadata>>> {
140 let metadata_kind = *self.metadata.split_off_first()?;
142 let Ok(metadata_kind) = ContractMetadataKind::try_from(metadata_kind) else {
143 return Some(Err(MetadataDecodingError::InvalidFirstMetadataByte {
144 byte: metadata_kind,
145 }));
146 };
147
148 self.found_something = true;
149
150 match metadata_kind {
151 ContractMetadataKind::Contract => {
152 if self.found_contract {
153 return Some(Err(MetadataDecodingError::MultipleContractsFound));
154 }
155 self.found_contract = true;
156
157 Some(self.decode_contract())
158 }
159 ContractMetadataKind::Trait => Some(self.decode_trait()),
160 ContractMetadataKind::Init
162 | ContractMetadataKind::UpdateStateless
163 | ContractMetadataKind::UpdateStatefulRo
164 | ContractMetadataKind::UpdateStatefulRw
165 | ContractMetadataKind::ViewStateless
166 | ContractMetadataKind::ViewStateful
167 | ContractMetadataKind::EnvRo
168 | ContractMetadataKind::EnvRw
169 | ContractMetadataKind::TmpRo
170 | ContractMetadataKind::TmpRw
171 | ContractMetadataKind::SlotRo
172 | ContractMetadataKind::SlotRw
173 | ContractMetadataKind::Input
174 | ContractMetadataKind::Output
175 | ContractMetadataKind::Return => {
176 Some(Err(MetadataDecodingError::ExpectedContractOrTrait {
177 metadata_kind,
178 }))
179 }
180 }
181 }
182
183 #[inline(always)]
184 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
185 fn decode_contract<'a>(
186 &'a mut self,
187 ) -> Result<MetadataItem<'a, 'metadata>, MetadataDecodingError<'metadata>> {
188 let state_type_name = IoTypeMetadataKind::type_name(self.metadata)
190 .ok_or(MetadataDecodingError::FailedToDecodeStateTypeName)?;
191
192 let state_type_details;
194 (state_type_details, self.metadata) =
195 IoTypeMetadataKind::type_details::<MAX_METADATA_DEPTH>(self.metadata)
196 .ok_or(MetadataDecodingError::InvalidStateIoType)?;
197
198 let slot_type_details;
200 (slot_type_details, self.metadata) =
201 IoTypeMetadataKind::type_details::<MAX_METADATA_DEPTH>(self.metadata)
202 .ok_or(MetadataDecodingError::InvalidStateIoType)?;
203
204 let tmp_type_details;
206 (tmp_type_details, self.metadata) =
207 IoTypeMetadataKind::type_details::<MAX_METADATA_DEPTH>(self.metadata)
208 .ok_or(MetadataDecodingError::InvalidStateIoType)?;
209
210 let num_methods = *self
212 .metadata
213 .split_off_first()
214 .ok_or(MetadataDecodingError::NotEnoughMetadata)?;
215
216 Ok(MetadataItem::Contract {
217 state_type_name,
218 state_type_details,
219 slot_type_details,
220 tmp_type_details,
221 num_methods,
222 decoder: MethodsMetadataDecoder::new(
223 &mut self.metadata,
224 MethodsContainerKind::Contract,
225 num_methods,
226 ),
227 })
228 }
229
230 #[inline(always)]
231 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
232 fn decode_trait<'a>(
233 &'a mut self,
234 ) -> Result<MetadataItem<'a, 'metadata>, MetadataDecodingError<'metadata>> {
235 let trait_name_length = usize::from(
237 *self
238 .metadata
239 .split_off_first()
240 .ok_or(MetadataDecodingError::NotEnoughMetadata)?,
241 );
242
243 let trait_name = self
244 .metadata
245 .split_off(..trait_name_length)
246 .ok_or(MetadataDecodingError::NotEnoughMetadata)?;
247
248 let num_methods = *self
250 .metadata
251 .split_off_first()
252 .ok_or(MetadataDecodingError::NotEnoughMetadata)?;
253
254 Ok(MetadataItem::Trait {
255 trait_name,
256 num_methods,
257 decoder: MethodsMetadataDecoder::new(
258 &mut self.metadata,
259 MethodsContainerKind::Trait,
260 num_methods,
261 ),
262 })
263 }
264}
265
266#[derive(Debug, Copy, Clone)]
267pub enum MethodsContainerKind {
268 Contract,
269 Trait,
270 Unknown,
271}
272
273#[derive(Debug)]
274pub struct MethodsMetadataDecoder<'a, 'metadata> {
275 metadata: &'a mut &'metadata [u8],
276 container_kind: MethodsContainerKind,
277 remaining: u8,
278}
279
280impl Drop for MethodsMetadataDecoder<'_, '_> {
281 fn drop(&mut self) {
282 while let Some(_method_metadata_decoder) = self.decode_next() {
283 }
285 }
286}
287
288impl<'a, 'metadata> MethodsMetadataDecoder<'a, 'metadata> {
289 #[inline(always)]
290 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
291 fn new(
292 metadata: &'a mut &'metadata [u8],
293 container_kind: MethodsContainerKind,
294 num_methods: u8,
295 ) -> Self {
296 Self {
297 metadata,
298 container_kind,
299 remaining: num_methods,
300 }
301 }
302
303 #[inline(always)]
305 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
306 pub fn remaining_methods(&self) -> u8 {
307 self.remaining
308 }
309
310 #[inline(always)]
312 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
313 pub fn remaining_metadata_bytes(&self) -> usize {
314 self.metadata.len()
315 }
316
317 #[inline(always)]
318 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
319 pub fn decode_next<'b>(&'b mut self) -> Option<MethodMetadataDecoder<'b, 'metadata>> {
320 if self.remaining == 0 {
321 return None;
322 }
323
324 self.remaining -= 1;
325
326 Some(MethodMetadataDecoder::new(
327 self.metadata,
328 self.container_kind,
329 ))
330 }
331}
332
333#[derive(Debug, Copy, Clone)]
334pub enum MethodKind {
335 Init,
337 UpdateStateless,
339 UpdateStatefulRo,
341 UpdateStatefulRw,
343 ViewStateless,
345 ViewStateful,
347}
348
349impl MethodKind {
350 #[inline(always)]
351 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
352 pub fn has_self(&self) -> bool {
353 match self {
354 MethodKind::Init | MethodKind::UpdateStateless | MethodKind::ViewStateless => false,
355 MethodKind::UpdateStatefulRo
356 | MethodKind::UpdateStatefulRw
357 | MethodKind::ViewStateful => true,
358 }
359 }
360}
361
362#[derive(Debug, Copy, Clone)]
363pub struct MethodMetadataItem<'metadata> {
364 pub method_name: &'metadata [u8],
368 pub method_kind: MethodKind,
369 pub num_arguments: u8,
373}
374
375#[derive(Debug, destructure)]
377pub struct MethodMetadataDecoder<'a, 'metadata> {
378 metadata: &'a mut &'metadata [u8],
379 container_kind: MethodsContainerKind,
380}
381
382impl Drop for MethodMetadataDecoder<'_, '_> {
383 fn drop(&mut self) {
384 let metadata_before = *self.metadata;
385
386 if MethodMetadataDecoder::new(self.metadata, self.container_kind)
388 .decode_next()
389 .is_err()
390 {
391 *self.metadata = metadata_before;
394 }
395 }
396}
397
398impl<'a, 'metadata> MethodMetadataDecoder<'a, 'metadata> {
399 #[inline(always)]
400 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
401 pub fn new(metadata: &'a mut &'metadata [u8], container_kind: MethodsContainerKind) -> Self {
402 Self {
403 metadata,
404 container_kind,
405 }
406 }
407
408 #[inline(always)]
410 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
411 pub fn remaining_metadata_bytes(&self) -> usize {
412 self.metadata.len()
413 }
414
415 #[inline]
416 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
417 pub fn decode_next(
418 self,
419 ) -> Result<
420 (
421 ArgumentsMetadataDecoder<'a, 'metadata>,
422 MethodMetadataItem<'metadata>,
423 ),
424 MetadataDecodingError<'metadata>,
425 > {
426 let (metadata, container_kind) = self.destructure();
427
428 let metadata_kind = *metadata
430 .split_off_first()
431 .ok_or(MetadataDecodingError::NotEnoughMetadata)?;
432 let metadata_kind = ContractMetadataKind::try_from(metadata_kind).map_err(|()| {
433 MetadataDecodingError::InvalidFirstMetadataByte {
434 byte: metadata_kind,
435 }
436 })?;
437
438 let method_kind = match metadata_kind {
439 ContractMetadataKind::Init => MethodKind::Init,
440 ContractMetadataKind::UpdateStateless => MethodKind::UpdateStateless,
441 ContractMetadataKind::UpdateStatefulRo => MethodKind::UpdateStatefulRo,
442 ContractMetadataKind::UpdateStatefulRw => MethodKind::UpdateStatefulRw,
443 ContractMetadataKind::ViewStateless => MethodKind::ViewStateless,
444 ContractMetadataKind::ViewStateful => MethodKind::ViewStateful,
445 ContractMetadataKind::Contract
447 | ContractMetadataKind::Trait
448 | ContractMetadataKind::EnvRo
449 | ContractMetadataKind::EnvRw
450 | ContractMetadataKind::TmpRo
451 | ContractMetadataKind::TmpRw
452 | ContractMetadataKind::SlotRo
453 | ContractMetadataKind::SlotRw
454 | ContractMetadataKind::Input
455 | ContractMetadataKind::Output
456 | ContractMetadataKind::Return => {
457 return Err(MetadataDecodingError::ExpectedMethodKind { metadata_kind });
458 }
459 };
460
461 let method_allowed = match container_kind {
462 MethodsContainerKind::Contract | MethodsContainerKind::Unknown => match method_kind {
463 MethodKind::Init
464 | MethodKind::UpdateStateless
465 | MethodKind::UpdateStatefulRo
466 | MethodKind::UpdateStatefulRw
467 | MethodKind::ViewStateless
468 | MethodKind::ViewStateful => true,
469 },
470 MethodsContainerKind::Trait => match method_kind {
471 MethodKind::Init
472 | MethodKind::UpdateStatefulRo
473 | MethodKind::UpdateStatefulRw
474 | MethodKind::ViewStateful => false,
475 MethodKind::UpdateStateless | MethodKind::ViewStateless => true,
476 },
477 };
478
479 if !method_allowed {
480 return Err(MetadataDecodingError::UnexpectedMethodKind {
481 method_kind,
482 container_kind,
483 });
484 }
485
486 let method_name_length = usize::from(
488 *metadata
489 .split_off_first()
490 .ok_or(MetadataDecodingError::NotEnoughMetadata)?,
491 );
492
493 let method_name = metadata
494 .split_off(..method_name_length)
495 .ok_or(MetadataDecodingError::NotEnoughMetadata)?;
496
497 let num_arguments = *metadata
499 .split_off_first()
500 .ok_or(MetadataDecodingError::NotEnoughMetadata)?;
501
502 let decoder = ArgumentsMetadataDecoder {
503 metadata,
504 method_kind,
505 remaining: num_arguments,
506 next_position: ArgumentPosition::Env,
507 };
508 let item = MethodMetadataItem {
509 method_name,
510 method_kind,
511 num_arguments,
512 };
513
514 Ok((decoder, item))
515 }
516}
517
518#[derive(Debug, Copy, Clone)]
519pub enum ArgumentKind {
520 EnvRo,
522 EnvRw,
524 TmpRo,
526 TmpRw,
528 SlotRo,
530 SlotRw,
532 Input,
534 Output,
536 Return,
538}
539
540#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
543enum ArgumentPosition {
544 Env,
545 Tmp,
546 Slots,
547 Inputs,
548 Outputs,
549 Return,
550 End,
552}
553
554#[derive(Debug)]
555pub struct ArgumentMetadataItem<'metadata> {
556 pub argument_name: &'metadata [u8],
560 pub argument_kind: ArgumentKind,
561 pub type_details: Option<IoTypeDetails>,
566}
567
568#[derive(Debug)]
569pub struct ArgumentsMetadataDecoder<'a, 'metadata> {
570 metadata: &'a mut &'metadata [u8],
571 method_kind: MethodKind,
572 remaining: u8,
573 next_position: ArgumentPosition,
575}
576
577impl Drop for ArgumentsMetadataDecoder<'_, '_> {
578 fn drop(&mut self) {
579 let metadata_before = *self.metadata;
580 while let Some(maybe_argument_metadata_item) = self.decode_next() {
581 if maybe_argument_metadata_item.is_err() {
582 *self.metadata = metadata_before;
585 break;
586 }
587 }
588 }
589}
590
591impl<'metadata> ArgumentsMetadataDecoder<'_, 'metadata> {
592 pub fn without_auto_drain(self) -> ManuallyDrop<Self> {
602 ManuallyDrop::new(self)
603 }
604
605 #[inline(always)]
607 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
608 pub fn remaining_metadata_bytes(&self) -> usize {
609 self.metadata.len()
610 }
611
612 #[inline]
619 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
620 pub fn decode_next<'a>(
621 &'a mut self,
622 ) -> Option<Result<ArgumentMetadataItem<'metadata>, MetadataDecodingError<'metadata>>> {
623 if self.remaining == 0 {
624 return None;
625 }
626
627 self.remaining -= 1;
628
629 Some(self.decode_argument())
630 }
631
632 #[inline(always)]
633 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
634 fn decode_argument<'a>(
635 &'a mut self,
636 ) -> Result<ArgumentMetadataItem<'metadata>, MetadataDecodingError<'metadata>> {
637 let metadata_kind = *self
639 .metadata
640 .split_off_first()
641 .ok_or(MetadataDecodingError::NotEnoughMetadata)?;
642 let metadata_kind = ContractMetadataKind::try_from(metadata_kind).map_err(|()| {
643 MetadataDecodingError::InvalidFirstMetadataByte {
644 byte: metadata_kind,
645 }
646 })?;
647
648 let argument_kind = match metadata_kind {
649 ContractMetadataKind::EnvRo => ArgumentKind::EnvRo,
650 ContractMetadataKind::EnvRw => ArgumentKind::EnvRw,
651 ContractMetadataKind::TmpRo => ArgumentKind::TmpRo,
652 ContractMetadataKind::TmpRw => ArgumentKind::TmpRw,
653 ContractMetadataKind::SlotRo => ArgumentKind::SlotRo,
654 ContractMetadataKind::SlotRw => ArgumentKind::SlotRw,
655 ContractMetadataKind::Input => ArgumentKind::Input,
656 ContractMetadataKind::Output => ArgumentKind::Output,
657 ContractMetadataKind::Return => ArgumentKind::Return,
658 ContractMetadataKind::Contract
660 | ContractMetadataKind::Trait
661 | ContractMetadataKind::Init
662 | ContractMetadataKind::UpdateStateless
663 | ContractMetadataKind::UpdateStatefulRo
664 | ContractMetadataKind::UpdateStatefulRw
665 | ContractMetadataKind::ViewStateless
666 | ContractMetadataKind::ViewStateful => {
667 return Err(MetadataDecodingError::ExpectedArgumentKind { metadata_kind });
668 }
669 };
670
671 let argument_allowed = match self.method_kind {
672 MethodKind::Init
673 | MethodKind::UpdateStateless
674 | MethodKind::UpdateStatefulRo
675 | MethodKind::UpdateStatefulRw => match argument_kind {
676 ArgumentKind::EnvRo
677 | ArgumentKind::EnvRw
678 | ArgumentKind::TmpRo
679 | ArgumentKind::TmpRw
680 | ArgumentKind::SlotRo
681 | ArgumentKind::SlotRw
682 | ArgumentKind::Input
683 | ArgumentKind::Output
684 | ArgumentKind::Return => true,
685 },
686 MethodKind::ViewStateless | MethodKind::ViewStateful => match argument_kind {
687 ArgumentKind::EnvRo
688 | ArgumentKind::SlotRo
689 | ArgumentKind::Input
690 | ArgumentKind::Output
691 | ArgumentKind::Return => true,
692 ArgumentKind::EnvRw
693 | ArgumentKind::TmpRo
694 | ArgumentKind::TmpRw
695 | ArgumentKind::SlotRw => false,
696 },
697 };
698
699 if !argument_allowed {
700 return Err(MetadataDecodingError::UnexpectedArgumentKind {
701 argument_kind,
702 method_kind: self.method_kind,
703 });
704 }
705
706 let (position, next_position) = match argument_kind {
710 ArgumentKind::EnvRo | ArgumentKind::EnvRw => {
711 (ArgumentPosition::Env, ArgumentPosition::Tmp)
712 }
713 ArgumentKind::TmpRo | ArgumentKind::TmpRw => {
714 (ArgumentPosition::Tmp, ArgumentPosition::Slots)
715 }
716 ArgumentKind::SlotRo | ArgumentKind::SlotRw => {
717 (ArgumentPosition::Slots, ArgumentPosition::Slots)
718 }
719 ArgumentKind::Input => (ArgumentPosition::Inputs, ArgumentPosition::Inputs),
720 ArgumentKind::Output => (ArgumentPosition::Outputs, ArgumentPosition::Outputs),
721 ArgumentKind::Return => (ArgumentPosition::Return, ArgumentPosition::End),
722 };
723 if position < self.next_position {
724 return Err(MetadataDecodingError::ArgumentOutOfOrder { argument_kind });
725 }
726 self.next_position = next_position;
727
728 let (argument_name, type_details) = match argument_kind {
729 ArgumentKind::EnvRo | ArgumentKind::EnvRw => ("env".as_bytes(), None),
730 ArgumentKind::TmpRo
731 | ArgumentKind::TmpRw
732 | ArgumentKind::SlotRo
733 | ArgumentKind::SlotRw
734 | ArgumentKind::Input
735 | ArgumentKind::Output
736 | ArgumentKind::Return => {
737 let argument_name_length = usize::from(
739 *self
740 .metadata
741 .split_off_first()
742 .ok_or(MetadataDecodingError::NotEnoughMetadata)?,
743 );
744 let argument_name = self
745 .metadata
746 .split_off(..argument_name_length)
747 .ok_or(MetadataDecodingError::NotEnoughMetadata)?;
748
749 let recommended_capacity = match argument_kind {
750 ArgumentKind::EnvRo
751 | ArgumentKind::EnvRw
752 | ArgumentKind::TmpRo
753 | ArgumentKind::TmpRw
754 | ArgumentKind::SlotRo
755 | ArgumentKind::SlotRw => None,
756 ArgumentKind::Input => {
757 let decoded =
758 IoTypeMetadataKind::type_details::<MAX_METADATA_DEPTH>(self.metadata);
759 let recommended_capacity;
760 (recommended_capacity, *self.metadata) =
761 decoded.ok_or(MetadataDecodingError::InvalidArgumentIoType {
762 argument_name,
763 argument_kind,
764 })?;
765
766 Some(recommended_capacity)
767 }
768 ArgumentKind::Output | ArgumentKind::Return => {
769 let last_argument = self.remaining == 0;
770 if matches!((self.method_kind, last_argument), (MethodKind::Init, true)) {
773 None
774 } else {
775 let decoded = IoTypeMetadataKind::type_details::<MAX_METADATA_DEPTH>(
776 self.metadata,
777 );
778 let recommended_capacity;
779 (recommended_capacity, *self.metadata) =
780 decoded.ok_or(MetadataDecodingError::InvalidArgumentIoType {
781 argument_name,
782 argument_kind,
783 })?;
784
785 Some(recommended_capacity)
786 }
787 }
788 };
789
790 (argument_name, recommended_capacity)
791 }
792 };
793
794 Ok(ArgumentMetadataItem {
795 argument_name,
796 argument_kind,
797 type_details,
798 })
799 }
800}