sui_types/object/
option_visitor.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Shared OptionVisitor implementation for deserializing Move Option types.
5
6use move_core_types::{
7    account_address::AccountAddress, annotated_value::MoveTypeLayout, annotated_visitor as AV,
8    u256::U256, visitor_default,
9};
10
11use crate::base_types::RESOLVED_STD_OPTION;
12
13/// Error type for OptionVisitor.
14#[derive(thiserror::Error, Debug)]
15#[error("Unexpected type")]
16pub struct Error;
17
18/// A visitor that deserializes an `Option<T>` by interpreting an empty vector as `None` and a
19/// single-element vector as `Some(T)`.
20pub struct OptionVisitor<'a, T>(pub &'a mut T);
21
22impl<'b, 'l, T, E> AV::Visitor<'b, 'l> for OptionVisitor<'_, T>
23where
24    T: AV::Visitor<'b, 'l, Error = E>,
25    E: From<Error> + From<AV::Error>,
26{
27    type Value = Option<T::Value>;
28    type Error = E;
29
30    visitor_default! { <'b, 'l> u8, u16, u32, u64, u128, u256 = Err(Error.into()) }
31    visitor_default! { <'b, 'l> bool, address, signer, variant = Err(Error.into()) }
32
33    fn visit_vector(
34        &mut self,
35        driver: &mut AV::VecDriver<'_, 'b, 'l>,
36    ) -> Result<Self::Value, Self::Error> {
37        match driver.len() {
38            0 => Ok(None),
39            1 => driver.next_element(self.0),
40            _ => Err(Error.into()),
41        }
42    }
43
44    fn visit_struct(
45        &mut self,
46        driver: &mut AV::StructDriver<'_, 'b, 'l>,
47    ) -> Result<Self::Value, Self::Error> {
48        if is_option(driver.struct_layout()) {
49            driver
50                .next_field(self)?
51                .ok_or_else(|| Error.into())
52                .map(|(_, option)| option)
53        } else {
54            Err(Error.into())
55        }
56    }
57}
58
59/// Check if a struct layout represents a Move Option type.
60fn is_option(struct_layout: &move_core_types::annotated_value::MoveStructLayout) -> bool {
61    let ty = &struct_layout.type_;
62
63    if (&ty.address, ty.module.as_ref(), ty.name.as_ref()) != RESOLVED_STD_OPTION {
64        return false;
65    }
66
67    if ty.type_params.len() != 1 {
68        return false;
69    }
70
71    let Some(type_param) = ty.type_params.first() else {
72        return false;
73    };
74
75    if struct_layout.fields.len() != 1 {
76        return false;
77    }
78
79    let Some(field) = struct_layout.fields.first() else {
80        return false;
81    };
82
83    if field.name.as_str() != "vec" {
84        return false;
85    }
86
87    match &field.layout {
88        MoveTypeLayout::Vector(elem) => {
89            if !elem.is_type(type_param) {
90                return false;
91            }
92        }
93        _ => return false,
94    }
95
96    true
97}