sui_graphql_rpc/types/
move_enum.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use async_graphql::*;
use sui_package_resolver::{DataDef, MoveData, VariantDef};

use crate::error::Error;

use super::{
    move_module::MoveModule,
    move_struct::{MoveField, MoveStructTypeParameter},
    open_move_type::{abilities, MoveAbility},
    sui_address::SuiAddress,
};

pub(crate) struct MoveEnum {
    defining_id: SuiAddress,
    module: String,
    name: String,
    abilities: Vec<MoveAbility>,
    type_parameters: Vec<MoveStructTypeParameter>,
    variants: Vec<MoveEnumVariant>,
    checkpoint_viewed_at: u64,
}

/// Information for a particular Move variant
pub(crate) struct MoveEnumVariant {
    name: String,
    fields: Vec<MoveField>,
}

/// Description of an enum type, defined in a Move module.
#[Object]
impl MoveEnum {
    /// The module this enum was originally defined in.
    pub(crate) async fn module(&self, ctx: &Context<'_>) -> Result<MoveModule> {
        let Some(module) = MoveModule::query(
            ctx,
            self.defining_id,
            &self.module,
            self.checkpoint_viewed_at,
        )
        .await
        .extend()?
        else {
            return Err(Error::Internal(format!(
                "Failed to load module for enum: {}::{}::{}",
                self.defining_id, self.module, self.name,
            )))
            .extend();
        };

        Ok(module)
    }

    /// The enum's (unqualified) type name.
    pub(crate) async fn name(&self) -> &str {
        &self.name
    }

    /// The enum's abilities.
    pub(crate) async fn abilities(&self) -> Option<&Vec<MoveAbility>> {
        Some(&self.abilities)
    }

    /// Constraints on the enum's formal type parameters.  Move bytecode does not name type
    /// parameters, so when they are referenced (e.g. in field types) they are identified by their
    /// index in this list.
    pub(crate) async fn type_parameters(&self) -> Option<&Vec<MoveStructTypeParameter>> {
        Some(&self.type_parameters)
    }

    /// The names and types of the enum's fields.  Field types reference type parameters, by their
    /// index in the defining enum's `typeParameters` list.
    pub(crate) async fn variants(&self) -> Option<&Vec<MoveEnumVariant>> {
        Some(&self.variants)
    }
}

#[Object]
impl MoveEnumVariant {
    /// The name of the variant
    pub(crate) async fn name(&self) -> &str {
        &self.name
    }

    /// The names and types of the variant's fields.  Field types reference type parameters, by their
    /// index in the defining enum's `typeParameters` list.
    pub(crate) async fn fields(&self) -> Option<&Vec<MoveField>> {
        Some(&self.fields)
    }
}

impl MoveEnum {
    pub(crate) fn new(
        module: String,
        name: String,
        def: DataDef,
        checkpoint_viewed_at: u64,
    ) -> Result<Self, Error> {
        let type_parameters = def
            .type_params
            .into_iter()
            .map(|param| MoveStructTypeParameter {
                constraints: abilities(param.constraints),
                is_phantom: param.is_phantom,
            })
            .collect();

        let MoveData::Enum(variants) = def.data else {
            // This should never happen, as the data should always be an enum if we're calling
            // this function. So signal an internal error if it does.
            return Err(Error::Internal(format!(
                "Expected enum data, but got: {:?}",
                def.data
            )));
        };
        let variants = variants
            .into_iter()
            .map(|VariantDef { name, signatures }| MoveEnumVariant {
                name,
                fields: signatures
                    .into_iter()
                    .map(|(name, signature)| MoveField {
                        name,
                        type_: signature.into(),
                    })
                    .collect(),
            })
            .collect();

        Ok(MoveEnum {
            defining_id: SuiAddress::from(def.defining_id),
            module,
            name,
            abilities: abilities(def.abilities),
            type_parameters,
            variants,
            checkpoint_viewed_at,
        })
    }
}