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,
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    fn visit_vector(
31        &mut self,
32        driver: &mut AV::VecDriver<'_, 'b, 'l>,
33    ) -> Result<Self::Value, Self::Error> {
34        match driver.len() {
35            0 => Ok(None),
36            1 => driver.next_element(self.0),
37            _ => Err(Error.into()),
38        }
39    }
40
41    fn visit_struct(
42        &mut self,
43        driver: &mut AV::StructDriver<'_, 'b, 'l>,
44    ) -> Result<Self::Value, Self::Error> {
45        if is_option(driver.struct_layout()) {
46            driver
47                .next_field(self)?
48                .ok_or_else(|| Error.into())
49                .map(|(_, option)| option)
50        } else {
51            Err(Error.into())
52        }
53    }
54
55    // === Empty/default cases ===
56
57    fn visit_u8(
58        &mut self,
59        _: &AV::ValueDriver<'_, 'b, 'l>,
60        _: u8,
61    ) -> Result<Self::Value, Self::Error> {
62        Err(Error.into())
63    }
64
65    fn visit_u16(
66        &mut self,
67        _: &AV::ValueDriver<'_, 'b, 'l>,
68        _: u16,
69    ) -> Result<Self::Value, Self::Error> {
70        Err(Error.into())
71    }
72
73    fn visit_u32(
74        &mut self,
75        _: &AV::ValueDriver<'_, 'b, 'l>,
76        _: u32,
77    ) -> Result<Self::Value, Self::Error> {
78        Err(Error.into())
79    }
80
81    fn visit_u64(
82        &mut self,
83        _: &AV::ValueDriver<'_, 'b, 'l>,
84        _: u64,
85    ) -> Result<Self::Value, Self::Error> {
86        Err(Error.into())
87    }
88
89    fn visit_u128(
90        &mut self,
91        _: &AV::ValueDriver<'_, 'b, 'l>,
92        _: u128,
93    ) -> Result<Self::Value, Self::Error> {
94        Err(Error.into())
95    }
96
97    fn visit_u256(
98        &mut self,
99        _: &AV::ValueDriver<'_, 'b, 'l>,
100        _: U256,
101    ) -> Result<Self::Value, Self::Error> {
102        Err(Error.into())
103    }
104
105    fn visit_bool(
106        &mut self,
107        _: &AV::ValueDriver<'_, 'b, 'l>,
108        _: bool,
109    ) -> Result<Self::Value, Self::Error> {
110        Err(Error.into())
111    }
112
113    fn visit_address(
114        &mut self,
115        _: &AV::ValueDriver<'_, 'b, 'l>,
116        _: AccountAddress,
117    ) -> Result<Self::Value, Self::Error> {
118        Err(Error.into())
119    }
120
121    fn visit_signer(
122        &mut self,
123        _: &AV::ValueDriver<'_, 'b, 'l>,
124        _: AccountAddress,
125    ) -> Result<Self::Value, Self::Error> {
126        Err(Error.into())
127    }
128
129    fn visit_variant(
130        &mut self,
131        _: &mut AV::VariantDriver<'_, 'b, 'l>,
132    ) -> Result<Self::Value, Self::Error> {
133        Err(Error.into())
134    }
135}
136
137/// Check if a struct layout represents a Move Option type.
138fn is_option(struct_layout: &move_core_types::annotated_value::MoveStructLayout) -> bool {
139    let ty = &struct_layout.type_;
140
141    if (&ty.address, ty.module.as_ref(), ty.name.as_ref()) != RESOLVED_STD_OPTION {
142        return false;
143    }
144
145    if ty.type_params.len() != 1 {
146        return false;
147    }
148
149    let Some(type_param) = ty.type_params.first() else {
150        return false;
151    };
152
153    if struct_layout.fields.len() != 1 {
154        return false;
155    }
156
157    let Some(field) = struct_layout.fields.first() else {
158        return false;
159    };
160
161    if field.name.as_str() != "vec" {
162        return false;
163    }
164
165    match &field.layout {
166        MoveTypeLayout::Vector(elem) => {
167            if !elem.is_type(type_param) {
168                return false;
169            }
170        }
171        _ => return false,
172    }
173
174    true
175}