iota_graphql_rpc/types/
move_enum.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use async_graphql::*;
6use iota_package_resolver::{DataDef, MoveData, VariantDef};
7
8use crate::{
9    error::Error,
10    types::{
11        iota_address::IotaAddress,
12        move_module::MoveModule,
13        move_struct::{MoveField, MoveStructTypeParameter},
14        open_move_type::{MoveAbility, abilities},
15    },
16};
17
18pub(crate) struct MoveEnum {
19    defining_id: IotaAddress,
20    module: String,
21    name: String,
22    abilities: Vec<MoveAbility>,
23    type_parameters: Vec<MoveStructTypeParameter>,
24    variants: Vec<MoveEnumVariant>,
25    checkpoint_viewed_at: u64,
26}
27
28/// Information for a particular Move variant
29pub(crate) struct MoveEnumVariant {
30    name: String,
31    fields: Vec<MoveField>,
32}
33
34/// Description of an enum type, defined in a Move module.
35#[Object]
36impl MoveEnum {
37    /// The module this enum was originally defined in.
38    pub(crate) async fn module(&self, ctx: &Context<'_>) -> Result<MoveModule> {
39        let Some(module) = MoveModule::query(
40            ctx,
41            self.defining_id,
42            &self.module,
43            self.checkpoint_viewed_at,
44        )
45        .await
46        .extend()?
47        else {
48            return Err(Error::Internal(format!(
49                "Failed to load module for enum: {}::{}::{}",
50                self.defining_id, self.module, self.name,
51            )))
52            .extend();
53        };
54
55        Ok(module)
56    }
57
58    /// The enum's (unqualified) type name.
59    pub(crate) async fn name(&self) -> &str {
60        &self.name
61    }
62
63    /// The enum's abilities.
64    pub(crate) async fn abilities(&self) -> Option<&Vec<MoveAbility>> {
65        Some(&self.abilities)
66    }
67
68    /// Constraints on the enum's formal type parameters.  Move bytecode does
69    /// not name type parameters, so when they are referenced (e.g. in field
70    /// types) they are identified by their index in this list.
71    pub(crate) async fn type_parameters(&self) -> Option<&Vec<MoveStructTypeParameter>> {
72        Some(&self.type_parameters)
73    }
74
75    /// The names and types of the enum's fields.  Field types reference type
76    /// parameters, by their index in the defining enum's `typeParameters`
77    /// list.
78    pub(crate) async fn variants(&self) -> Option<&Vec<MoveEnumVariant>> {
79        Some(&self.variants)
80    }
81}
82
83#[Object]
84impl MoveEnumVariant {
85    /// The name of the variant
86    pub(crate) async fn name(&self) -> &str {
87        &self.name
88    }
89
90    /// The names and types of the variant's fields.  Field types reference type
91    /// parameters, by their index in the defining enum's `typeParameters`
92    /// list.
93    pub(crate) async fn fields(&self) -> Option<&Vec<MoveField>> {
94        Some(&self.fields)
95    }
96}
97
98impl MoveEnum {
99    pub(crate) fn new(
100        module: String,
101        name: String,
102        def: DataDef,
103        checkpoint_viewed_at: u64,
104    ) -> Result<Self, Error> {
105        let type_parameters = def
106            .type_params
107            .into_iter()
108            .map(|param| MoveStructTypeParameter {
109                constraints: abilities(param.constraints),
110                is_phantom: param.is_phantom,
111            })
112            .collect();
113
114        let MoveData::Enum(variants) = def.data else {
115            // This should never happen, as the data should always be an enum if we're
116            // calling this function. So signal an internal error if it does.
117            return Err(Error::Internal(format!(
118                "Expected enum data, but got: {:?}",
119                def.data
120            )));
121        };
122        let variants = variants
123            .into_iter()
124            .map(|VariantDef { name, signatures }| MoveEnumVariant {
125                name,
126                fields: signatures
127                    .into_iter()
128                    .map(|(name, signature)| MoveField {
129                        name,
130                        type_: signature.into(),
131                    })
132                    .collect(),
133            })
134            .collect();
135
136        Ok(MoveEnum {
137            defining_id: IotaAddress::from(def.defining_id),
138            module,
139            name,
140            abilities: abilities(def.abilities),
141            type_parameters,
142            variants,
143            checkpoint_viewed_at,
144        })
145    }
146}