1use crate::MAX_TOTAL_METHOD_ARGS;
2use crate::metadata::{ContractMetadataKind, MAX_METADATA_DEPTH};
3use ab_io_type::metadata::{IoTypeDetails, IoTypeMetadataKind};
4use core::mem::ManuallyDrop;
5use derive_destructure2::destructure;
6
7#[derive(Debug, thiserror::Error)]
9pub enum MetadataDecodingError<'metadata> {
10 #[error("Not enough metadata to decode")]
12 NotEnoughMetadata,
13 #[error("Invalid first metadata byte")]
15 InvalidFirstMetadataByte { byte: u8 },
16 #[error("Multiple contracts found")]
18 MultipleContractsFound,
19 #[error("Expected contract or trait kind, found something else: {metadata_kind:?}")]
21 ExpectedContractOrTrait { metadata_kind: ContractMetadataKind },
22 #[error("Failed to decode state type name")]
24 FailedToDecodeStateTypeName,
25 #[error("Invalid state I/O type")]
27 InvalidStateIoType,
28 #[error("Unexpected method kind {method_kind:?} for container kind {container_kind:?}")]
30 UnexpectedMethodKind {
31 method_kind: MethodKind,
32 container_kind: MethodsContainerKind,
33 },
34 #[error("Expected method kind, found something else: {metadata_kind:?}")]
36 ExpectedMethodKind { metadata_kind: ContractMetadataKind },
37 #[error("Too many arguments: {number_of_arguments}")]
39 TooManyArguments {
40 number_of_arguments: u8,
42 },
43 #[error("`#[init]` method doesn't end with the state")]
45 InitWithoutState,
46 #[error("Expected argument kind, found something else: {metadata_kind:?}")]
48 ExpectedArgumentKind { metadata_kind: ContractMetadataKind },
49 #[error(
51 "Unexpected argument kind {argument_kind:?} for method kind {method_kind:?} in container \
52 kind {container_kind:?}"
53 )]
54 UnexpectedArgumentKind {
55 argument_kind: ArgumentKind,
56 method_kind: MethodKind,
57 container_kind: MethodsContainerKind,
58 },
59 #[error("Argument of kind {argument_kind:?} is out of order")]
62 ArgumentOutOfOrder { argument_kind: ArgumentKind },
63 #[error("Invalid argument I/O type of kind {argument_kind:?} for {argument_name:?}")]
65 InvalidArgumentIoType {
66 argument_name: &'metadata [u8],
67 argument_kind: ArgumentKind,
68 },
69}
70
71#[derive(Debug)]
72pub enum MetadataItem<'a, 'metadata> {
73 Contract {
74 state_type_name: &'metadata [u8],
79 state_type_details: IoTypeDetails,
80 slot_type_details: IoTypeDetails,
81 tmp_type_details: IoTypeDetails,
82 num_methods: u8,
83 decoder: MethodsMetadataDecoder<'a, 'metadata>,
84 },
85 Trait {
86 trait_name: &'metadata [u8],
91 num_methods: u8,
92 decoder: MethodsMetadataDecoder<'a, 'metadata>,
93 },
94}
95
96impl<'a, 'metadata> MetadataItem<'a, 'metadata> {
97 #[inline(always)]
98 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
99 #[expect(
100 clippy::rest_pattern_accessible_field,
101 reason = "Do not need other fields"
102 )]
103 pub fn num_methods(&self) -> u8 {
104 match self {
105 MetadataItem::Contract { num_methods, .. }
106 | MetadataItem::Trait { num_methods, .. } => *num_methods,
107 }
108 }
109
110 #[inline(always)]
111 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
112 #[expect(
113 clippy::rest_pattern_accessible_field,
114 reason = "Do not need other fields"
115 )]
116 pub fn into_decoder(self) -> MethodsMetadataDecoder<'a, 'metadata> {
117 match self {
118 MetadataItem::Contract { decoder, .. } | MetadataItem::Trait { decoder, .. } => decoder,
119 }
120 }
121}
122
123#[derive(Debug)]
124pub struct MetadataDecoder<'metadata> {
125 metadata: &'metadata [u8],
126 found_contract: bool,
127 found_something: bool,
128}
129
130impl<'metadata> MetadataDecoder<'metadata> {
131 #[inline(always)]
132 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
133 pub fn new(metadata: &'metadata [u8]) -> Self {
134 Self {
135 metadata,
136 found_contract: false,
137 found_something: false,
138 }
139 }
140
141 #[inline(always)]
143 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
144 pub fn remaining_metadata_bytes(&self) -> usize {
145 self.metadata.len()
146 }
147
148 #[inline]
150 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
151 pub fn decode_next<'a>(
152 &'a mut self,
153 ) -> Option<Result<MetadataItem<'a, 'metadata>, MetadataDecodingError<'metadata>>> {
154 let metadata_kind = *self.metadata.split_off_first()?;
156 let Ok(metadata_kind) = ContractMetadataKind::try_from(metadata_kind) else {
157 return Some(Err(MetadataDecodingError::InvalidFirstMetadataByte {
158 byte: metadata_kind,
159 }));
160 };
161
162 self.found_something = true;
163
164 match metadata_kind {
165 ContractMetadataKind::Contract => {
166 if self.found_contract {
167 return Some(Err(MetadataDecodingError::MultipleContractsFound));
168 }
169 self.found_contract = true;
170
171 Some(self.decode_contract())
172 }
173 ContractMetadataKind::Trait => Some(self.decode_trait()),
174 ContractMetadataKind::Init
176 | ContractMetadataKind::UpdateStateless
177 | ContractMetadataKind::UpdateStatefulRo
178 | ContractMetadataKind::UpdateStatefulRw
179 | ContractMetadataKind::ViewStateless
180 | ContractMetadataKind::ViewStateful
181 | ContractMetadataKind::EnvRo
182 | ContractMetadataKind::EnvRw
183 | ContractMetadataKind::TmpRo
184 | ContractMetadataKind::TmpRw
185 | ContractMetadataKind::SlotRo
186 | ContractMetadataKind::SlotRw
187 | ContractMetadataKind::Input
188 | ContractMetadataKind::Output
189 | ContractMetadataKind::Return => {
190 Some(Err(MetadataDecodingError::ExpectedContractOrTrait {
191 metadata_kind,
192 }))
193 }
194 }
195 }
196
197 #[inline(always)]
198 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
199 fn decode_contract<'a>(
200 &'a mut self,
201 ) -> Result<MetadataItem<'a, 'metadata>, MetadataDecodingError<'metadata>> {
202 let state_type_name = IoTypeMetadataKind::type_name(self.metadata)
204 .ok_or(MetadataDecodingError::FailedToDecodeStateTypeName)?;
205
206 let state_type_details;
208 (state_type_details, self.metadata) =
209 IoTypeMetadataKind::type_details::<MAX_METADATA_DEPTH>(self.metadata)
210 .ok_or(MetadataDecodingError::InvalidStateIoType)?;
211
212 let slot_type_details;
214 (slot_type_details, self.metadata) =
215 IoTypeMetadataKind::type_details::<MAX_METADATA_DEPTH>(self.metadata)
216 .ok_or(MetadataDecodingError::InvalidStateIoType)?;
217
218 let tmp_type_details;
220 (tmp_type_details, self.metadata) =
221 IoTypeMetadataKind::type_details::<MAX_METADATA_DEPTH>(self.metadata)
222 .ok_or(MetadataDecodingError::InvalidStateIoType)?;
223
224 let num_methods = *self
226 .metadata
227 .split_off_first()
228 .ok_or(MetadataDecodingError::NotEnoughMetadata)?;
229
230 Ok(MetadataItem::Contract {
231 state_type_name,
232 state_type_details,
233 slot_type_details,
234 tmp_type_details,
235 num_methods,
236 decoder: MethodsMetadataDecoder::new(
237 &mut self.metadata,
238 MethodsContainerKind::Contract,
239 num_methods,
240 ),
241 })
242 }
243
244 #[inline(always)]
245 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
246 fn decode_trait<'a>(
247 &'a mut self,
248 ) -> Result<MetadataItem<'a, 'metadata>, MetadataDecodingError<'metadata>> {
249 let trait_name_length = usize::from(
251 *self
252 .metadata
253 .split_off_first()
254 .ok_or(MetadataDecodingError::NotEnoughMetadata)?,
255 );
256
257 let trait_name = self
258 .metadata
259 .split_off(..trait_name_length)
260 .ok_or(MetadataDecodingError::NotEnoughMetadata)?;
261
262 let num_methods = *self
264 .metadata
265 .split_off_first()
266 .ok_or(MetadataDecodingError::NotEnoughMetadata)?;
267
268 Ok(MetadataItem::Trait {
269 trait_name,
270 num_methods,
271 decoder: MethodsMetadataDecoder::new(
272 &mut self.metadata,
273 MethodsContainerKind::Trait,
274 num_methods,
275 ),
276 })
277 }
278}
279
280#[derive(Debug, Copy, Clone)]
281pub enum MethodsContainerKind {
282 Contract,
283 Trait,
284 Unknown,
285}
286
287#[derive(Debug)]
288pub struct MethodsMetadataDecoder<'a, 'metadata> {
289 metadata: &'a mut &'metadata [u8],
290 container_kind: MethodsContainerKind,
291 remaining: u8,
292}
293
294impl Drop for MethodsMetadataDecoder<'_, '_> {
295 fn drop(&mut self) {
296 while let Some(_method_metadata_decoder) = self.decode_next() {
297 }
299 }
300}
301
302impl<'a, 'metadata> MethodsMetadataDecoder<'a, 'metadata> {
303 #[inline(always)]
304 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
305 fn new(
306 metadata: &'a mut &'metadata [u8],
307 container_kind: MethodsContainerKind,
308 num_methods: u8,
309 ) -> Self {
310 Self {
311 metadata,
312 container_kind,
313 remaining: num_methods,
314 }
315 }
316
317 #[inline(always)]
319 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
320 pub fn remaining_methods(&self) -> u8 {
321 self.remaining
322 }
323
324 #[inline(always)]
326 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
327 pub fn remaining_metadata_bytes(&self) -> usize {
328 self.metadata.len()
329 }
330
331 #[inline(always)]
332 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
333 pub fn decode_next<'b>(&'b mut self) -> Option<MethodMetadataDecoder<'b, 'metadata>> {
334 if self.remaining == 0 {
335 return None;
336 }
337
338 self.remaining -= 1;
339
340 Some(MethodMetadataDecoder::new(
341 self.metadata,
342 self.container_kind,
343 ))
344 }
345}
346
347#[derive(Debug, Copy, Clone)]
348pub enum MethodKind {
349 Init,
351 UpdateStateless,
353 UpdateStatefulRo,
355 UpdateStatefulRw,
357 ViewStateless,
359 ViewStateful,
361}
362
363impl MethodKind {
364 #[inline(always)]
365 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
366 pub fn has_self(&self) -> bool {
367 match self {
368 MethodKind::Init | MethodKind::UpdateStateless | MethodKind::ViewStateless => false,
369 MethodKind::UpdateStatefulRo
370 | MethodKind::UpdateStatefulRw
371 | MethodKind::ViewStateful => true,
372 }
373 }
374}
375
376#[derive(Debug, Copy, Clone)]
377pub struct MethodMetadataItem<'metadata> {
378 pub method_name: &'metadata [u8],
382 pub method_kind: MethodKind,
383 pub num_arguments: u8,
387}
388
389#[derive(Debug, destructure)]
391pub struct MethodMetadataDecoder<'a, 'metadata> {
392 metadata: &'a mut &'metadata [u8],
393 container_kind: MethodsContainerKind,
394}
395
396impl Drop for MethodMetadataDecoder<'_, '_> {
397 fn drop(&mut self) {
398 let metadata_before = *self.metadata;
399
400 if MethodMetadataDecoder::new(self.metadata, self.container_kind)
402 .decode_next()
403 .is_err()
404 {
405 *self.metadata = metadata_before;
408 }
409 }
410}
411
412impl<'a, 'metadata> MethodMetadataDecoder<'a, 'metadata> {
413 #[inline(always)]
414 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
415 pub fn new(metadata: &'a mut &'metadata [u8], container_kind: MethodsContainerKind) -> Self {
416 Self {
417 metadata,
418 container_kind,
419 }
420 }
421
422 #[inline(always)]
424 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
425 pub fn remaining_metadata_bytes(&self) -> usize {
426 self.metadata.len()
427 }
428
429 #[inline]
430 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
431 pub fn decode_next(
432 self,
433 ) -> Result<
434 (
435 ArgumentsMetadataDecoder<'a, 'metadata>,
436 MethodMetadataItem<'metadata>,
437 ),
438 MetadataDecodingError<'metadata>,
439 > {
440 let (metadata, container_kind) = self.destructure();
441
442 let metadata_kind = *metadata
444 .split_off_first()
445 .ok_or(MetadataDecodingError::NotEnoughMetadata)?;
446 let metadata_kind = ContractMetadataKind::try_from(metadata_kind).map_err(|()| {
447 MetadataDecodingError::InvalidFirstMetadataByte {
448 byte: metadata_kind,
449 }
450 })?;
451
452 let method_kind = match metadata_kind {
453 ContractMetadataKind::Init => MethodKind::Init,
454 ContractMetadataKind::UpdateStateless => MethodKind::UpdateStateless,
455 ContractMetadataKind::UpdateStatefulRo => MethodKind::UpdateStatefulRo,
456 ContractMetadataKind::UpdateStatefulRw => MethodKind::UpdateStatefulRw,
457 ContractMetadataKind::ViewStateless => MethodKind::ViewStateless,
458 ContractMetadataKind::ViewStateful => MethodKind::ViewStateful,
459 ContractMetadataKind::Contract
461 | ContractMetadataKind::Trait
462 | ContractMetadataKind::EnvRo
463 | ContractMetadataKind::EnvRw
464 | ContractMetadataKind::TmpRo
465 | ContractMetadataKind::TmpRw
466 | ContractMetadataKind::SlotRo
467 | ContractMetadataKind::SlotRw
468 | ContractMetadataKind::Input
469 | ContractMetadataKind::Output
470 | ContractMetadataKind::Return => {
471 return Err(MetadataDecodingError::ExpectedMethodKind { metadata_kind });
472 }
473 };
474
475 let method_allowed = match container_kind {
476 MethodsContainerKind::Contract | MethodsContainerKind::Unknown => match method_kind {
477 MethodKind::Init
478 | MethodKind::UpdateStateless
479 | MethodKind::UpdateStatefulRo
480 | MethodKind::UpdateStatefulRw
481 | MethodKind::ViewStateless
482 | MethodKind::ViewStateful => true,
483 },
484 MethodsContainerKind::Trait => match method_kind {
485 MethodKind::Init
486 | MethodKind::UpdateStatefulRo
487 | MethodKind::UpdateStatefulRw
488 | MethodKind::ViewStateful => false,
489 MethodKind::UpdateStateless | MethodKind::ViewStateless => true,
490 },
491 };
492
493 if !method_allowed {
494 return Err(MetadataDecodingError::UnexpectedMethodKind {
495 method_kind,
496 container_kind,
497 });
498 }
499
500 let method_name_length = usize::from(
502 *metadata
503 .split_off_first()
504 .ok_or(MetadataDecodingError::NotEnoughMetadata)?,
505 );
506
507 let method_name = metadata
508 .split_off(..method_name_length)
509 .ok_or(MetadataDecodingError::NotEnoughMetadata)?;
510
511 let num_arguments = *metadata
513 .split_off_first()
514 .ok_or(MetadataDecodingError::NotEnoughMetadata)?;
515
516 let number_of_arguments = num_arguments.saturating_add(u8::from(method_kind.has_self()));
518 if number_of_arguments > MAX_TOTAL_METHOD_ARGS {
519 return Err(MetadataDecodingError::TooManyArguments {
520 number_of_arguments,
521 });
522 }
523
524 if matches!(method_kind, MethodKind::Init) && num_arguments == 0 {
526 return Err(MetadataDecodingError::InitWithoutState);
527 }
528
529 let decoder = ArgumentsMetadataDecoder {
530 metadata,
531 method_kind,
532 container_kind,
533 remaining: num_arguments,
534 next_position: ArgumentPosition::Env,
535 };
536 let item = MethodMetadataItem {
537 method_name,
538 method_kind,
539 num_arguments,
540 };
541
542 Ok((decoder, item))
543 }
544}
545
546#[derive(Debug, Copy, Clone)]
547pub enum ArgumentKind {
548 EnvRo,
550 EnvRw,
552 TmpRo,
554 TmpRw,
556 SlotRo,
558 SlotRw,
560 Input,
562 Output,
564 Return,
566}
567
568#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
571enum ArgumentPosition {
572 Env,
573 Tmp,
574 Slots,
575 Inputs,
576 Outputs,
577 Return,
578 End,
580}
581
582#[derive(Debug)]
583pub struct ArgumentMetadataItem<'metadata> {
584 pub argument_name: &'metadata [u8],
588 pub argument_kind: ArgumentKind,
589 pub type_details: Option<IoTypeDetails>,
594}
595
596#[derive(Debug)]
597pub struct ArgumentsMetadataDecoder<'a, 'metadata> {
598 metadata: &'a mut &'metadata [u8],
599 method_kind: MethodKind,
600 container_kind: MethodsContainerKind,
601 remaining: u8,
602 next_position: ArgumentPosition,
604}
605
606impl Drop for ArgumentsMetadataDecoder<'_, '_> {
607 fn drop(&mut self) {
608 let metadata_before = *self.metadata;
609 while let Some(maybe_argument_metadata_item) = self.decode_next() {
610 if maybe_argument_metadata_item.is_err() {
611 *self.metadata = metadata_before;
614 break;
615 }
616 }
617 }
618}
619
620impl<'metadata> ArgumentsMetadataDecoder<'_, 'metadata> {
621 pub fn without_auto_drain(self) -> ManuallyDrop<Self> {
631 ManuallyDrop::new(self)
632 }
633
634 #[inline(always)]
636 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
637 pub fn remaining_metadata_bytes(&self) -> usize {
638 self.metadata.len()
639 }
640
641 #[inline]
649 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
650 pub fn decode_next<'a>(
651 &'a mut self,
652 ) -> Option<Result<ArgumentMetadataItem<'metadata>, MetadataDecodingError<'metadata>>> {
653 if self.remaining == 0 {
654 return None;
655 }
656
657 self.remaining -= 1;
658
659 Some(self.decode_argument())
660 }
661
662 #[inline(always)]
663 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
664 fn decode_argument<'a>(
665 &'a mut self,
666 ) -> Result<ArgumentMetadataItem<'metadata>, MetadataDecodingError<'metadata>> {
667 let metadata_kind = *self
669 .metadata
670 .split_off_first()
671 .ok_or(MetadataDecodingError::NotEnoughMetadata)?;
672 let metadata_kind = ContractMetadataKind::try_from(metadata_kind).map_err(|()| {
673 MetadataDecodingError::InvalidFirstMetadataByte {
674 byte: metadata_kind,
675 }
676 })?;
677
678 let argument_kind = match metadata_kind {
679 ContractMetadataKind::EnvRo => ArgumentKind::EnvRo,
680 ContractMetadataKind::EnvRw => ArgumentKind::EnvRw,
681 ContractMetadataKind::TmpRo => ArgumentKind::TmpRo,
682 ContractMetadataKind::TmpRw => ArgumentKind::TmpRw,
683 ContractMetadataKind::SlotRo => ArgumentKind::SlotRo,
684 ContractMetadataKind::SlotRw => ArgumentKind::SlotRw,
685 ContractMetadataKind::Input => ArgumentKind::Input,
686 ContractMetadataKind::Output => ArgumentKind::Output,
687 ContractMetadataKind::Return => ArgumentKind::Return,
688 ContractMetadataKind::Contract
690 | ContractMetadataKind::Trait
691 | ContractMetadataKind::Init
692 | ContractMetadataKind::UpdateStateless
693 | ContractMetadataKind::UpdateStatefulRo
694 | ContractMetadataKind::UpdateStatefulRw
695 | ContractMetadataKind::ViewStateless
696 | ContractMetadataKind::ViewStateful => {
697 return Err(MetadataDecodingError::ExpectedArgumentKind { metadata_kind });
698 }
699 };
700
701 let argument_allowed = match self.method_kind {
702 MethodKind::Init
703 | MethodKind::UpdateStateless
704 | MethodKind::UpdateStatefulRo
705 | MethodKind::UpdateStatefulRw => match argument_kind {
706 ArgumentKind::EnvRo
707 | ArgumentKind::EnvRw
708 | ArgumentKind::TmpRo
709 | ArgumentKind::TmpRw
710 | ArgumentKind::SlotRo
711 | ArgumentKind::SlotRw
712 | ArgumentKind::Input
713 | ArgumentKind::Output
714 | ArgumentKind::Return => true,
715 },
716 MethodKind::ViewStateless | MethodKind::ViewStateful => match argument_kind {
717 ArgumentKind::EnvRo
718 | ArgumentKind::SlotRo
719 | ArgumentKind::Input
720 | ArgumentKind::Output
721 | ArgumentKind::Return => true,
722 ArgumentKind::EnvRw
723 | ArgumentKind::TmpRo
724 | ArgumentKind::TmpRw
725 | ArgumentKind::SlotRw => false,
726 },
727 };
728
729 let argument_allowed_in_container = match self.container_kind {
731 MethodsContainerKind::Contract | MethodsContainerKind::Unknown => true,
732 MethodsContainerKind::Trait => match argument_kind {
733 ArgumentKind::EnvRo
734 | ArgumentKind::EnvRw
735 | ArgumentKind::Input
736 | ArgumentKind::Output
737 | ArgumentKind::Return => true,
738 ArgumentKind::TmpRo
739 | ArgumentKind::TmpRw
740 | ArgumentKind::SlotRo
741 | ArgumentKind::SlotRw => false,
742 },
743 };
744
745 if !argument_allowed || !argument_allowed_in_container {
746 return Err(MetadataDecodingError::UnexpectedArgumentKind {
747 argument_kind,
748 method_kind: self.method_kind,
749 container_kind: self.container_kind,
750 });
751 }
752
753 let (position, next_position) = match argument_kind {
757 ArgumentKind::EnvRo | ArgumentKind::EnvRw => {
758 (ArgumentPosition::Env, ArgumentPosition::Tmp)
759 }
760 ArgumentKind::TmpRo | ArgumentKind::TmpRw => {
761 (ArgumentPosition::Tmp, ArgumentPosition::Slots)
762 }
763 ArgumentKind::SlotRo | ArgumentKind::SlotRw => {
764 (ArgumentPosition::Slots, ArgumentPosition::Slots)
765 }
766 ArgumentKind::Input => (ArgumentPosition::Inputs, ArgumentPosition::Inputs),
767 ArgumentKind::Output => (ArgumentPosition::Outputs, ArgumentPosition::Outputs),
768 ArgumentKind::Return => (ArgumentPosition::Return, ArgumentPosition::End),
769 };
770 if position < self.next_position {
771 return Err(MetadataDecodingError::ArgumentOutOfOrder { argument_kind });
772 }
773 self.next_position = next_position;
774
775 let last_argument = self.remaining == 0;
776 if matches!(self.method_kind, MethodKind::Init)
778 && last_argument
779 && !matches!(argument_kind, ArgumentKind::Output | ArgumentKind::Return)
780 {
781 return Err(MetadataDecodingError::InitWithoutState);
782 }
783
784 let (argument_name, type_details) = match argument_kind {
785 ArgumentKind::EnvRo | ArgumentKind::EnvRw => ("env".as_bytes(), None),
786 ArgumentKind::TmpRo
787 | ArgumentKind::TmpRw
788 | ArgumentKind::SlotRo
789 | ArgumentKind::SlotRw
790 | ArgumentKind::Input
791 | ArgumentKind::Output
792 | ArgumentKind::Return => {
793 let argument_name_length = usize::from(
795 *self
796 .metadata
797 .split_off_first()
798 .ok_or(MetadataDecodingError::NotEnoughMetadata)?,
799 );
800 let argument_name = self
801 .metadata
802 .split_off(..argument_name_length)
803 .ok_or(MetadataDecodingError::NotEnoughMetadata)?;
804
805 let recommended_capacity = match argument_kind {
806 ArgumentKind::EnvRo
807 | ArgumentKind::EnvRw
808 | ArgumentKind::TmpRo
809 | ArgumentKind::TmpRw
810 | ArgumentKind::SlotRo
811 | ArgumentKind::SlotRw => None,
812 ArgumentKind::Input => {
813 let decoded =
814 IoTypeMetadataKind::type_details::<MAX_METADATA_DEPTH>(self.metadata);
815 let recommended_capacity;
816 (recommended_capacity, *self.metadata) =
817 decoded.ok_or(MetadataDecodingError::InvalidArgumentIoType {
818 argument_name,
819 argument_kind,
820 })?;
821
822 Some(recommended_capacity)
823 }
824 ArgumentKind::Output | ArgumentKind::Return => {
825 if matches!((self.method_kind, last_argument), (MethodKind::Init, true)) {
828 None
829 } else {
830 let decoded = IoTypeMetadataKind::type_details::<MAX_METADATA_DEPTH>(
831 self.metadata,
832 );
833 let recommended_capacity;
834 (recommended_capacity, *self.metadata) =
835 decoded.ok_or(MetadataDecodingError::InvalidArgumentIoType {
836 argument_name,
837 argument_kind,
838 })?;
839
840 Some(recommended_capacity)
841 }
842 }
843 };
844
845 (argument_name, recommended_capacity)
846 }
847 };
848
849 Ok(ArgumentMetadataItem {
850 argument_name,
851 argument_kind,
852 type_details,
853 })
854 }
855}