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,
})
}
}