sui_graphql_rpc/types/
move_struct.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
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

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

use crate::error::Error;

use super::{
    move_module::MoveModule,
    open_move_type::{abilities, MoveAbility, OpenMoveType},
    sui_address::SuiAddress,
};

pub(crate) struct MoveStruct {
    defining_id: SuiAddress,
    module: String,
    name: String,
    abilities: Vec<MoveAbility>,
    type_parameters: Vec<MoveStructTypeParameter>,
    fields: Vec<MoveField>,
    checkpoint_viewed_at: u64,
}

#[derive(SimpleObject)]
pub(crate) struct MoveStructTypeParameter {
    pub(crate) constraints: Vec<MoveAbility>,
    pub(crate) is_phantom: bool,
}

/// Information for a particular field on a Move struct.
#[derive(SimpleObject)]
#[graphql(complex)]
pub(crate) struct MoveField {
    pub(crate) name: String,
    #[graphql(skip)]
    pub(crate) type_: OpenMoveType,
}

/// Description of a struct type, defined in a Move module.
#[Object]
impl MoveStruct {
    /// The module this struct 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 struct: {}::{}::{}",
                self.defining_id, self.module, self.name,
            )))
            .extend();
        };

        Ok(module)
    }

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

    /// Abilities this struct has.
    pub(crate) async fn abilities(&self) -> Option<&Vec<MoveAbility>> {
        Some(&self.abilities)
    }

    /// Constraints on the struct'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 struct's fields.  Field types reference type parameters, by their
    /// index in the defining struct's `typeParameters` list.
    pub(crate) async fn fields(&self) -> Option<&Vec<MoveField>> {
        Some(&self.fields)
    }
}

#[ComplexObject]
impl MoveField {
    #[graphql(name = "type")]
    async fn type_(&self) -> Option<&OpenMoveType> {
        Some(&self.type_)
    }
}

impl MoveStruct {
    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::Struct(fields) = def.data else {
            // This should never happen, as the data should always be a struct if we're calling
            // this function. Signal an internal error if it does.
            return Err(Error::Internal(format!(
                "Expected struct data, but got: {:?}",
                def.data
            )));
        };
        let fields = fields
            .into_iter()
            .map(|(name, signature)| MoveField {
                name,
                type_: signature.into(),
            })
            .collect();

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