sui_jsonrpc/msgs/
displays.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::fmt::{Display, Formatter};
5
6use tabled::builder::Builder as TableBuilder;
7use tabled::settings::style::HorizontalLine;
8use tabled::settings::{Panel as TablePanel, Style as TableStyle};
9
10use crate::msgs::{
11    SuiArgument,
12    SuiCallArg,
13    SuiCommand,
14    SuiObjectArg,
15    SuiProgrammableMoveCall,
16    SuiProgrammableTransactionBlock,
17};
18
19pub struct Pretty<'a, T>(pub &'a T);
20
21impl Display for Pretty<'_, SuiProgrammableTransactionBlock> {
22    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
23        let Pretty(ptb) = self;
24        let SuiProgrammableTransactionBlock { inputs, commands } = ptb;
25        if !inputs.is_empty() {
26            let mut builder = TableBuilder::default();
27            for (i, input) in inputs.iter().enumerate() {
28                match input {
29                    SuiCallArg::Pure(v) => {
30                        let pure_arg = if let Some(t) = v.value_type() {
31                            format!("{i:<3} Pure Arg: Type: {}, Value: {}", t, v.value())
32                        } else {
33                            format!("{i:<3} Pure Arg: {}", v.value())
34                        };
35                        builder.push_record(vec![pure_arg]);
36                    }
37                    SuiCallArg::Object(SuiObjectArg::ImmOrOwnedObject { object_id, .. }) => {
38                        builder.push_record(vec![format!(
39                            "{i:<3} Imm/Owned Object ID: {}",
40                            object_id
41                        )]);
42                    }
43                    SuiCallArg::Object(SuiObjectArg::SharedObject { object_id, .. }) => {
44                        builder.push_record(vec![format!(
45                            "{i:<3} Shared Object    ID: {}",
46                            object_id
47                        )]);
48                    }
49                    SuiCallArg::Object(SuiObjectArg::Receiving { object_id, .. }) => {
50                        builder.push_record(vec![format!(
51                            "{i:<3} Receiving Object ID: {}",
52                            object_id
53                        )]);
54                    }
55                }
56            }
57
58            let mut table = builder.build();
59            table.with(TablePanel::header("Input Objects"));
60            table.with(TableStyle::rounded().horizontals([HorizontalLine::new(
61                1,
62                TableStyle::modern().get_horizontal(),
63            )]));
64            write!(f, "\n{}", table)?;
65        } else {
66            write!(f, "\n  No input objects for this transaction")?;
67        }
68
69        if !commands.is_empty() {
70            let mut builder = TableBuilder::default();
71            for (i, c) in commands.iter().enumerate() {
72                if i == commands.len() - 1 {
73                    builder.push_record(vec![format!("{i:<2} {}", Pretty(c))]);
74                } else {
75                    builder.push_record(vec![format!("{i:<2} {}\n", Pretty(c))]);
76                }
77            }
78            let mut table = builder.build();
79            table.with(TablePanel::header("Commands"));
80            table.with(TableStyle::rounded().horizontals([HorizontalLine::new(
81                1,
82                TableStyle::modern().get_horizontal(),
83            )]));
84            write!(f, "\n{}", table)
85        } else {
86            write!(f, "\n  No commands for this transaction")
87        }
88    }
89}
90
91impl Display for Pretty<'_, SuiCommand> {
92    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
93        let Pretty(command) = self;
94        match command {
95            SuiCommand::MakeMoveVec(ty_opt, elems) => {
96                write!(f, "MakeMoveVec:\n ┌")?;
97                if let Some(ty) = ty_opt {
98                    write!(f, "\n │ Type Tag: {ty}")?;
99                }
100                write!(f, "\n │ Arguments:\n │   ")?;
101                write_sep(f, elems.iter().map(Pretty), "\n │   ")?;
102                write!(f, "\n └")
103            }
104
105            SuiCommand::MoveCall(p) => write!(f, "{}", Pretty(&**p)),
106
107            SuiCommand::MergeCoins(target, coins) => {
108                write!(
109                    f,
110                    "MergeCoins:\n ┌\n │ Target: {}\n │ Coins: \n │   ",
111                    Pretty(target)
112                )?;
113                write_sep(f, coins.iter().map(Pretty), "\n │   ")?;
114                write!(f, "\n └")
115            }
116
117            SuiCommand::SplitCoins(coin, amounts) => {
118                write!(
119                    f,
120                    "SplitCoins:\n ┌\n │ Coin: {}\n │ Amounts: \n │   ",
121                    Pretty(coin)
122                )?;
123                write_sep(f, amounts.iter().map(Pretty), "\n │   ")?;
124                write!(f, "\n └")
125            }
126
127            SuiCommand::Publish(deps) => {
128                write!(f, "Publish:\n ┌\n │ Dependencies: \n │   ")?;
129                write_sep(f, deps, "\n │   ")?;
130                write!(f, "\n └")
131            }
132
133            SuiCommand::TransferObjects(objs, addr) => {
134                write!(f, "TransferObjects:\n ┌\n │ Arguments: \n │   ")?;
135                write_sep(f, objs.iter().map(Pretty), "\n │   ")?;
136                write!(f, "\n │ Address: {}\n └", Pretty(addr))
137            }
138
139            SuiCommand::Upgrade(deps, current_package_id, ticket) => {
140                write!(f, "Upgrade:\n ┌\n │ Dependencies: \n │   ")?;
141                write_sep(f, deps, "\n │   ")?;
142                write!(f, "\n │ Current Package ID: {current_package_id}")?;
143                write!(f, "\n │ Ticket: {}", Pretty(ticket))?;
144                write!(f, "\n └")
145            }
146        }
147    }
148}
149
150impl Display for Pretty<'_, SuiProgrammableMoveCall> {
151    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
152        let Pretty(move_call) = self;
153        let SuiProgrammableMoveCall {
154            package,
155            module,
156            function,
157            type_arguments,
158            arguments,
159        } = move_call;
160
161        write!(
162            f,
163            "MoveCall:\n ┌\n │ Function:  {} \n │ Module:    {}\n │ Package:   {}",
164            function, module, package
165        )?;
166
167        if !type_arguments.is_empty() {
168            write!(f, "\n │ Type Arguments: \n │   ")?;
169            write_sep(f, type_arguments, "\n │   ")?;
170        }
171        if !arguments.is_empty() {
172            write!(f, "\n │ Arguments: \n │   ")?;
173            write_sep(f, arguments.iter().map(Pretty), "\n │   ")?;
174        }
175
176        write!(f, "\n └")
177    }
178}
179
180impl Display for Pretty<'_, SuiArgument> {
181    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
182        let Pretty(argument) = self;
183
184        let output = match argument {
185            SuiArgument::GasCoin => "GasCoin".to_string(),
186            SuiArgument::Input(i) => format!("Input  {}", i),
187            SuiArgument::Result(i) => format!("Result {}", i),
188            SuiArgument::NestedResult(j, k) => format!("Nested Result {}: {}", j, k),
189        };
190        write!(f, "{}", output)
191    }
192}
193
194/// Originally from `sui_types::transaction::write_sep`.
195pub fn write_sep<T: Display>(
196    f: &mut Formatter<'_>,
197    items: impl IntoIterator<Item = T>,
198    sep: &str,
199) -> std::fmt::Result {
200    let mut xs = items.into_iter();
201    let Some(x) = xs.next() else {
202        return Ok(());
203    };
204    write!(f, "{x}")?;
205    for x in xs {
206        write!(f, "{sep}{x}")?;
207    }
208    Ok(())
209}