casper_client/cli/json_args/
help.rs

1//! Functions for use in help commands.
2
3use std::fmt::Write;
4
5use once_cell::sync::Lazy;
6
7// The default terminal width used by Clap.
8const MAX_INFO_LINE_LENGTH: usize = 100;
9
10struct InfoAndExamples {
11    info: &'static str,
12    examples: Vec<&'static str>,
13}
14
15static ALL_INFO_AND_EXAMPLES: Lazy<Vec<InfoAndExamples>> = Lazy::new(|| {
16    vec![
17        InfoAndExamples {
18            info: "CLType Bool is represented as a JSON Bool, e.g.",
19            examples: vec![r#"{"name":"entry_point_name","type":"Bool","value":false}"#],
20        },
21        InfoAndExamples {
22            info: "CLTypes I32, I64, U8, U32 and U64 are represented as a JSON Number, e.g.",
23            examples: vec![
24                r#"{"name":"entry_point_name","type":"I32","value":-1}"#,
25                r#"{"name":"entry_point_name","type":"I64","value":-2}"#,
26                r#"{"name":"entry_point_name","type":"U8","value":1}"#,
27                r#"{"name":"entry_point_name","type":"U32","value":2}"#,
28                r#"{"name":"entry_point_name","type":"U64","value":3}"#,
29            ],
30        },
31        InfoAndExamples {
32            info: "CLTypes U128, U256 and U512 are represented as a JSON String of the decimal \
33                value, or can be represented as a Number if the value is not more than u64::MAX \
34                (18446744073709551615), e.g.",
35            examples: vec![
36                r#"{"name":"entry_point_name","type":"U128","value":1}"#,
37                r#"{"name":"entry_point_name","type":"U128","value":"20000000000000000000"}"#,
38                r#"{"name":"entry_point_name","type":"U256","value":2}"#,
39                r#"{"name":"entry_point_name","type":"U256","value":"20000000000000000000"}"#,
40                r#"{"name":"entry_point_name","type":"U512","value":3}"#,
41                r#"{"name":"entry_point_name","type":"U512","value":"20000000000000000000"}"#,
42            ],
43        },
44        InfoAndExamples {
45            info: "CLType Unit is represented as a JSON null, e.g.",
46            examples: vec![r#"{"name":"entry_point_name","type":"Unit","value":null}"#],
47        },
48        InfoAndExamples {
49            info: "CLType String is represented as a JSON String, e.g.",
50            examples: vec![r#"{"name":"entry_point_name","type":"String","value":"a"}"#],
51        },
52        InfoAndExamples {
53            info: "CLType Key is represented as a JSON String (where the value is a properly \
54                formatted string representation of a Key) or may also be represented as a JSON \
55                Object of the form {\"<KEY VARIANT>\":\"<KEY AS FORMATTED STRING>\"}, e.g.",
56            examples: vec![
57                r#"{"name":"entry_point_name","type":"Key","value":"account-hash-201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201"}"#,
58                r#"{"name":"entry_point_name","type":"Key","value":{"Account":"account-hash-201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201"}}"#,
59                r#"{"name":"entry_point_name","type":"Key","value":"hash-201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201"}"#,
60                r#"{"name":"entry_point_name","type":"Key","value":{"Hash":"hash-201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201"}}"#,
61                r#"{"name":"entry_point_name","type":"Key","value":"uref-201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201-000"}"#,
62                r#"{"name":"entry_point_name","type":"Key","value":{"URef":"uref-201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201-000"}}"#,
63                r#"{"name":"entry_point_name","type":"Key","value":"transfer-201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201"}"#,
64                r#"{"name":"entry_point_name","type":"Key","value":{"Transfer":"transfer-201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201"}}"#,
65                r#"{"name":"entry_point_name","type":"Key","value":"deploy-201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201"}"#,
66                r#"{"name":"entry_point_name","type":"Key","value":{"DeployInfo":"deploy-201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201"}}"#,
67                r#"{"name":"entry_point_name","type":"Key","value":"era-1"}"#,
68                r#"{"name":"entry_point_name","type":"Key","value":{"EraInfo":"era-1"}}"#,
69                r#"{"name":"entry_point_name","type":"Key","value":"balance-201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201"}"#,
70                r#"{"name":"entry_point_name","type":"Key","value":{"Balance":"balance-201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201"}}"#,
71                r#"{"name":"entry_point_name","type":"Key","value":"bid-201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201"}"#,
72                r#"{"name":"entry_point_name","type":"Key","value":{"Bid":"bid-201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201"}}"#,
73                r#"{"name":"entry_point_name","type":"Key","value":"withdraw-201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201"}"#,
74                r#"{"name":"entry_point_name","type":"Key","value":{"Withdraw":"withdraw-201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201"}}"#,
75                r#"{"name":"entry_point_name","type":"Key","value":"unbond-201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201"}"#,
76                r#"{"name":"entry_point_name","type":"Key","value":{"Unbond":"unbond-201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201"}}"#,
77                r#"{"name":"entry_point_name","type":"Key","value":"dictionary-201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201"}"#,
78                r#"{"name":"entry_point_name","type":"Key","value":{"Dictionary":"dictionary-201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201"}}"#,
79                r#"{"name":"entry_point_name","type":"Key","value":"system-entity-registry-0000000000000000000000000000000000000000000000000000000000000000"}"#,
80                r#"{"name":"entry_point_name","type":"Key","value":{"SystemEntityRegistry":"system-entity-registry-0000000000000000000000000000000000000000000000000000000000000000"}}"#,
81                r#"{"name":"entry_point_name","type":"Key","value":"chainspec-registry-1111111111111111111111111111111111111111111111111111111111111111"}"#,
82                r#"{"name":"entry_point_name","type":"Key","value":{"ChainspecRegistry":"chainspec-registry-1111111111111111111111111111111111111111111111111111111111111111"}}"#,
83            ],
84        },
85        InfoAndExamples {
86            info:
87                "CLTypes URef and PublicKey are represented as a JSON String where the value is a \
88                properly formatted string representation of the respective type, e.g.",
89            examples: vec![
90                r#"{"name":"entry_point_name","type":"URef","value":"uref-201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201-007"}"#,
91                r#"{"name":"entry_point_name","type":"PublicKey","value":"017279ea868d185a40ed32ec076807c070de9c0fe986f5418c2aa71478f1e8ddf8"}"#,
92                r#"{"name":"entry_point_name","type":"PublicKey","value":"02030963b980a774f9bf4fded595007b60045ca9593fe6d47296e4e1aaa2745c90d2"}"#,
93            ],
94        },
95        InfoAndExamples {
96            info: "CLType Option<T> is represented as a JSON null for None, or the JSON type \
97                appropriate for the wrapped type T, e.g.",
98            examples: vec![
99                r#"{"name":"entry_point_name","type":{"Option":"U64"},"value":999}"#,
100                r#"{"name":"entry_point_name","type":{"Option":"String"},"value":null}"#,
101            ],
102        },
103        InfoAndExamples {
104            info: "CLType List<T> is represented as a JSON Array where every element has a type \
105                suitable to represent T.  For the special case of List<U8>, it can be represented \
106                as a hex-encoded String, e.g.",
107            examples: vec![
108                r#"{"name":"entry_point_name","type":{"List":{"Option":"U256"}},"value":[1,null,"3"]}"#,
109                r#"{"name":"entry_point_name","type":{"List":"U8"},"value":"0102ff"}"#,
110            ],
111        },
112        InfoAndExamples {
113            info:
114                "CLType ByteArray is represented as a JSON String (hex-encoded) or more verbosely \
115                by an Array of Numbers, e.g.",
116            examples: vec![
117                r#"{"name":"entry_point_name","type":{"ByteArray":3},"value":"0114ff"}"#,
118                r#"{"name":"entry_point_name","type":{"ByteArray":3},"value":[1,20,255]}"#,
119            ],
120        },
121        InfoAndExamples {
122            info:
123                "CLType Result<T, E> is represented as a JSON Object with exactly one entry named \
124                either \"Ok\" or \"Err\" where the Object's value is suitable to represent T or E \
125                respectively, e.g.",
126            examples: vec![
127                r#"{"name":"entry_point_name","type":{"Result":{"ok":"Bool","err":"U8"}},"value":{"Ok":true}}"#,
128                r#"{"name":"entry_point_name","type":{"Result":{"ok":"Bool","err":"U8"}},"value":{"Err":1}}"#,
129            ],
130        },
131        InfoAndExamples {
132            info: "CLType Map<K, V> is represented as a JSON Array of Objects of the form \
133                {\"key\":<K-VALUE>,\"value\":<V-VALUE>}.  For the special case where K is String \
134                or a numerical type, the Map can be represented as a single JSON Object, with each \
135                entry having the name of the given key as a String, e.g.",
136            examples: vec![
137                r#"{"name":"entry_point_name","type":{"Map":{"key":"U8","value":"Bool"}},"value":[{"key":1,"value":true},{"key":2,"value":false}]}"#,
138                r#"{"name":"entry_point_name","type":{"Map":{"key":"U8","value":"Bool"}},"value":{"1":true,"2":false}}"#,
139            ],
140        },
141        InfoAndExamples {
142            info: "CLTypes Tuple1, Tuple2 and Tuple3 are represented as a JSON Array, e.g.",
143            examples: vec![
144                r#"{"name":"entry_point_name","type":{"Tuple1":["Bool"]},"value":[true]}"#,
145                r#"{"name":"entry_point_name","type":{"Tuple2":["Bool","U8"]},"value":[true,128]}"#,
146                r#"{"name":"entry_point_name","type":{"Tuple3":["Bool","U8","String"]},"value":[true,128,"a"]}"#,
147            ],
148        },
149    ]
150});
151
152static HELP: Lazy<String> = Lazy::new(|| {
153    let mut help = r#"The value must be a JSON Array of JSON Objects of the form
154{"name":<String>,"type":<VALUE>,"value":<VALUE>}
155
156For example, to provide the following session args:
157* The value "square" to an entry point named "shape" taking a CLType::String
158* The tuple value (100,100) to an entry point named "dimensions" taking a CLType::Tuple2<CLType::U32, CLType::U32>
159* The value "blue" to an entry point named "color" taking a CLType::Option<CLType::String>
160the following input would be used:
161'[{"name":"shape","type":"String","value":"square"},{"name":"dimensions","type":{"Tuple2":["U32","U32"]},"value":[100,100]},{"name":"color","type":{"Option":"String"},"value":"blue"}]'
162
163Details for each CLType variant:
164"#.to_string();
165
166    ALL_INFO_AND_EXAMPLES.iter().for_each(|elt| {
167        let mut line_number = 0;
168        let mut current_line_length = 0;
169        for word in elt.info.split_whitespace() {
170            if current_line_length + word.len() + 1 > MAX_INFO_LINE_LENGTH
171                && current_line_length != 0
172            {
173                help += "\n";
174                line_number += 1;
175                current_line_length = 0;
176            }
177            if current_line_length == 0 {
178                let bullet_or_space = if line_number == 0 { '*' } else { ' ' };
179                let _ = write!(help, "{} {}", bullet_or_space, word);
180                current_line_length += word.len() + 2;
181            } else {
182                let _ = write!(help, " {}", word);
183                current_line_length += word.len() + 1;
184            }
185        }
186
187        help += "\n";
188
189        elt.examples.iter().for_each(|example| {
190            let _ = writeln!(help, "  {}", example);
191        });
192        help += "\n";
193    });
194
195    help += "Note that CLType Any cannot be represented as JSON.\n";
196    help
197});
198
199/// Returns a string listing examples of the format required when passing in payment code or
200/// session code args.
201pub fn info_and_examples() -> &'static str {
202    &HELP
203}
204
205#[cfg(test)]
206mod tests {
207    use casper_types::NamedArg;
208
209    use super::*;
210    use crate::cli::json_args::JsonArg;
211
212    #[test]
213    fn should_parse_examples() {
214        for example in ALL_INFO_AND_EXAMPLES.iter().flat_map(|elt| &elt.examples) {
215            let parsed: JsonArg = serde_json::from_str(example).unwrap();
216            NamedArg::try_from(parsed)
217                .unwrap_or_else(|error| panic!("unexpected error: {}", error));
218        }
219    }
220}