1use std::fmt::Write;
4
5use once_cell::sync::Lazy;
6
7const 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
199pub 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}