Skip to main content

sui_rpc_api/grpc/v2/move_package_service/
conversions.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4// This module contains conversion functions from sui-package-resolver types to their protobuf representations.
5// We use explicit conversion functions instead of From traits because:
6// 1. The orphan rule prevents implementing From for external types
7// 2. Many conversions require additional context (e.g., package_id, module_name) that From traits cannot provide
8
9use crate::{Result, RpcError};
10use move_binary_format::file_format::{
11    Ability as MoveAbility, AbilitySet as MoveAbilitySet, DatatypeTyParameter,
12    Visibility as MoveVisibility,
13};
14use sui_package_resolver::{DataDef, FunctionDef, MoveData, VariantDef};
15use sui_rpc::proto::sui::rpc::v2::{
16    Ability, DatatypeDescriptor, FieldDescriptor, FunctionDescriptor, Module, OpenSignature,
17    OpenSignatureBody, TypeParameter, VariantDescriptor, datatype_descriptor::DatatypeKind,
18    function_descriptor::Visibility, open_signature::Reference,
19    open_signature_body::Type as SignatureType,
20};
21use sui_types::base_types::ObjectID;
22
23pub fn convert_error(e: sui_package_resolver::error::Error) -> RpcError {
24    RpcError::new(tonic::Code::Internal, e.to_string())
25}
26
27pub fn convert_datatype(
28    datatype_name: &str,
29    data_def: &DataDef,
30    package_id: &ObjectID,
31    module_name: &str,
32) -> DatatypeDescriptor {
33    let type_parameters = data_def
34        .type_params
35        .iter()
36        .map(convert_type_parameter)
37        .collect();
38    let abilities = convert_ability_set(data_def.abilities);
39
40    let (kind, fields, variants) = match &data_def.data {
41        MoveData::Struct(fields) => {
42            let proto_fields = fields
43                .iter()
44                .enumerate()
45                .map(|(pos, (name, sig))| {
46                    let mut message = FieldDescriptor::default();
47                    message.name = Some(name.clone());
48                    message.position = Some(pos as u32);
49                    message.r#type = Some(convert_open_signature_body(sig));
50                    message
51                })
52                .collect();
53            (DatatypeKind::Struct, proto_fields, vec![])
54        }
55        MoveData::Enum(variants) => {
56            let proto_variants = variants
57                .iter()
58                .enumerate()
59                .map(|(pos, variant)| convert_variant(pos, variant))
60                .collect();
61            (DatatypeKind::Enum, vec![], proto_variants)
62        }
63    };
64
65    let mut message = DatatypeDescriptor::default();
66    message.type_name = Some(format!(
67        "{}::{}::{}",
68        package_id.to_canonical_string(true),
69        module_name,
70        datatype_name
71    ));
72    message.defining_id = Some(data_def.defining_id.to_canonical_string(true));
73    message.module = Some(module_name.to_string());
74    message.name = Some(datatype_name.to_string());
75    message.abilities = abilities;
76    message.type_parameters = type_parameters;
77    message.kind = Some(kind as i32);
78    message.fields = fields;
79    message.variants = variants;
80    message
81}
82
83pub fn convert_module(
84    module_name: &str,
85    resolved_module: &sui_package_resolver::Module,
86    package_id: &ObjectID,
87) -> Result<Module> {
88    let mut datatypes = Vec::new();
89    for datatype_name in resolved_module.datatypes(None, None) {
90        let data_def = resolved_module
91            .data_def(datatype_name)
92            .map_err(convert_error)?
93            .unwrap_or_else(|| {
94                panic!(
95                    "datatype {} does not have a data_def. This shouldn't happen.",
96                    datatype_name
97                )
98            });
99
100        let descriptor = convert_datatype(datatype_name, &data_def, package_id, module_name);
101        datatypes.push(descriptor);
102    }
103
104    let mut functions = Vec::new();
105    for func_name in resolved_module.functions(None, None) {
106        let func_def = resolved_module
107            .function_def(func_name)
108            .map_err(convert_error)?
109            .unwrap_or_else(|| {
110                panic!(
111                    "function {} does not have a function_def. This shouldn't happen.",
112                    func_name
113                )
114            });
115
116        let descriptor = convert_function(func_name, &func_def);
117        functions.push(descriptor);
118    }
119
120    let mut message = Module::default();
121    message.name = Some(module_name.to_string());
122    message.datatypes = datatypes;
123    message.functions = functions;
124    Ok(message)
125}
126
127pub fn convert_function(function_name: &str, func_def: &FunctionDef) -> FunctionDescriptor {
128    let visibility = match func_def.visibility {
129        MoveVisibility::Private => Visibility::Private,
130        MoveVisibility::Public => Visibility::Public,
131        MoveVisibility::Friend => Visibility::Friend,
132    };
133
134    let type_parameters = func_def
135        .type_params
136        .iter()
137        .map(|abilities| {
138            let mut message = TypeParameter::default();
139            message.constraints = convert_ability_set(*abilities);
140            message
141        })
142        .collect();
143
144    let parameters = func_def
145        .parameters
146        .iter()
147        .map(convert_open_signature)
148        .collect();
149    let returns = func_def
150        .return_
151        .iter()
152        .map(convert_open_signature)
153        .collect();
154
155    let mut message = FunctionDescriptor::default();
156    message.name = Some(function_name.to_string());
157    message.visibility = Some(visibility as i32);
158    message.is_entry = Some(func_def.is_entry);
159    message.type_parameters = type_parameters;
160    message.parameters = parameters;
161    message.returns = returns;
162    message
163}
164
165fn convert_type_parameter(tp: &DatatypeTyParameter) -> TypeParameter {
166    let mut message = TypeParameter::default();
167    message.constraints = convert_ability_set(tp.constraints);
168    message.is_phantom = Some(tp.is_phantom);
169    message
170}
171
172fn convert_ability_set(abilities: MoveAbilitySet) -> Vec<i32> {
173    let mut result = Vec::new();
174
175    if abilities.has_ability(MoveAbility::Copy) {
176        result.push(Ability::Copy as i32);
177    }
178    if abilities.has_ability(MoveAbility::Drop) {
179        result.push(Ability::Drop as i32);
180    }
181    if abilities.has_ability(MoveAbility::Store) {
182        result.push(Ability::Store as i32);
183    }
184    if abilities.has_ability(MoveAbility::Key) {
185        result.push(Ability::Key as i32);
186    }
187
188    result
189}
190
191fn convert_variant(position: usize, variant: &VariantDef) -> VariantDescriptor {
192    let fields = variant
193        .signatures
194        .iter()
195        .enumerate()
196        .map(|(pos, (name, sig))| {
197            let mut message = FieldDescriptor::default();
198            message.name = Some(name.clone());
199            message.position = Some(pos as u32);
200            message.r#type = Some(convert_open_signature_body(sig));
201            message
202        })
203        .collect();
204
205    let mut message = VariantDescriptor::default();
206    message.name = Some(variant.name.clone());
207    message.position = Some(position as u32);
208    message.fields = fields;
209    message
210}
211
212fn convert_open_signature(sig: &sui_package_resolver::OpenSignature) -> OpenSignature {
213    let reference = sig.ref_.map(|r| match r {
214        sui_package_resolver::Reference::Immutable => Reference::Immutable as i32,
215        sui_package_resolver::Reference::Mutable => Reference::Mutable as i32,
216    });
217
218    let mut message = OpenSignature::default();
219    message.reference = reference;
220    message.body = Some(convert_open_signature_body(&sig.body));
221    message
222}
223
224fn convert_open_signature_body(
225    body: &sui_package_resolver::OpenSignatureBody,
226) -> OpenSignatureBody {
227    let (type_enum, type_name, type_params, type_param_idx) = match body {
228        sui_package_resolver::OpenSignatureBody::Bool => (SignatureType::Bool, None, vec![], None),
229        sui_package_resolver::OpenSignatureBody::U8 => (SignatureType::U8, None, vec![], None),
230        sui_package_resolver::OpenSignatureBody::U16 => (SignatureType::U16, None, vec![], None),
231        sui_package_resolver::OpenSignatureBody::U32 => (SignatureType::U32, None, vec![], None),
232        sui_package_resolver::OpenSignatureBody::U64 => (SignatureType::U64, None, vec![], None),
233        sui_package_resolver::OpenSignatureBody::U128 => (SignatureType::U128, None, vec![], None),
234        sui_package_resolver::OpenSignatureBody::U256 => (SignatureType::U256, None, vec![], None),
235        sui_package_resolver::OpenSignatureBody::Address => {
236            (SignatureType::Address, None, vec![], None)
237        }
238        sui_package_resolver::OpenSignatureBody::Vector(inner) => {
239            let inner_body = convert_open_signature_body(inner.as_ref());
240            (SignatureType::Vector, None, vec![inner_body], None)
241        }
242        sui_package_resolver::OpenSignatureBody::Datatype(key, args) => {
243            let type_name = format!(
244                "{}::{}::{}",
245                key.package.to_canonical_string(true),
246                key.module,
247                key.name
248            );
249
250            let type_args = args.iter().map(convert_open_signature_body).collect();
251            (SignatureType::Datatype, Some(type_name), type_args, None)
252        }
253        sui_package_resolver::OpenSignatureBody::TypeParameter(idx) => {
254            (SignatureType::Parameter, None, vec![], Some(*idx as u32))
255        }
256    };
257
258    let mut message = OpenSignatureBody::default();
259    message.r#type = Some(type_enum as i32);
260    message.type_name = type_name;
261    message.type_parameter_instantiation = type_params;
262    message.type_parameter = type_param_idx;
263    message
264}