@@ -110,12 +110,20 @@ impl PartialEq<[u8; CONTRACT_ID_BYTES]> for ContractId {
110
110
}
111
111
}
112
112
113
+ /// Debug implementation for [`ContractId`]
114
+ ///
115
+ /// This implementation uses the normal display implementation.
113
116
impl core:: fmt:: Debug for ContractId {
114
117
fn fmt ( & self , f : & mut core:: fmt:: Formatter ) -> core:: fmt:: Result {
115
118
core:: fmt:: Display :: fmt ( self , f)
116
119
}
117
120
}
118
121
122
+ /// Display implementation for [`ContractId`]
123
+ ///
124
+ /// This implementation will display the hexadecimal representation of the bytes
125
+ /// of the [`ContractId`]. If the alternate flag is set, it will also display
126
+ /// the `0x` prefix.
119
127
impl core:: fmt:: Display for ContractId {
120
128
fn fmt ( & self , f : & mut core:: fmt:: Formatter ) -> core:: fmt:: Result {
121
129
if f. alternate ( ) {
@@ -127,3 +135,75 @@ impl core::fmt::Display for ContractId {
127
135
Ok ( ( ) )
128
136
}
129
137
}
138
+
139
+ impl TryFrom < String > for ContractId {
140
+ type Error = core:: fmt:: Error ;
141
+
142
+ /// Tries to convert a hexadecimal string into a [`ContractId`]
143
+ ///
144
+ /// The string can be prefixed with `0x` or not.
145
+ fn try_from ( value : String ) -> core:: result:: Result < Self , Self :: Error > {
146
+ let value = value. trim_start_matches ( "0x" ) ;
147
+ let decoded = hex:: decode ( value) . map_err ( |_| core:: fmt:: Error ) ?;
148
+ let bytes: [ u8 ; CONTRACT_ID_BYTES ] =
149
+ decoded. try_into ( ) . map_err ( |_| core:: fmt:: Error ) ?;
150
+
151
+ Ok ( ContractId :: from_bytes ( bytes) )
152
+ }
153
+ }
154
+
155
+ #[ cfg( test) ]
156
+ mod tests {
157
+ use alloc:: { format, string:: ToString } ;
158
+
159
+ use rand:: rngs:: StdRng ;
160
+ use rand:: { Rng , SeedableRng } ;
161
+
162
+ use super :: * ;
163
+
164
+ const CONTRACT_ID_STR : & str =
165
+ "0000000000000000000000000000000000000000000000000000000000000000" ;
166
+ const CONTRACT_ID_STR_PRETTY : & str =
167
+ "0x0000000000000000000000000000000000000000000000000000000000000000" ;
168
+
169
+ #[ test]
170
+ fn contract_id_display ( ) {
171
+ let contract_id = ContractId :: from_bytes ( [ 0u8 ; CONTRACT_ID_BYTES ] ) ;
172
+ assert_eq ! ( format!( "{}" , contract_id) , CONTRACT_ID_STR ) ;
173
+
174
+ let contract_id = ContractId :: from_bytes ( [ 0u8 ; CONTRACT_ID_BYTES ] ) ;
175
+ assert_eq ! ( format!( "{:#?}" , contract_id) , CONTRACT_ID_STR_PRETTY ) ;
176
+ }
177
+
178
+ #[ test]
179
+ fn contract_id_debug ( ) {
180
+ let contract_id = ContractId :: from_bytes ( [ 0u8 ; CONTRACT_ID_BYTES ] ) ;
181
+ assert_eq ! ( format!( "{}" , contract_id) , CONTRACT_ID_STR ) ;
182
+ }
183
+
184
+ #[ test]
185
+ fn contract_id_to_from_string ( ) {
186
+ let mut rng = StdRng :: seed_from_u64 ( 1618 ) ;
187
+ let contract_id = ContractId :: from_bytes ( rng. gen ( ) ) ;
188
+
189
+ let string = contract_id. to_string ( ) ;
190
+
191
+ assert_eq ! ( string. starts_with( "0x" ) , false ) ;
192
+ assert_eq ! ( string. len( ) , CONTRACT_ID_BYTES * 2 ) ;
193
+
194
+ let contract_id_from_string = ContractId :: try_from ( string) . unwrap ( ) ;
195
+
196
+ assert_eq ! ( contract_id, contract_id_from_string) ;
197
+ }
198
+
199
+ #[ test]
200
+ fn contract_id_try_from_invalid_string ( ) {
201
+ let too_short = ContractId :: try_from ( "0x" . to_string ( ) ) . is_err ( ) ;
202
+
203
+ let too_long =
204
+ ContractId :: try_from ( format ! ( "{}0" , CONTRACT_ID_STR ) ) . is_err ( ) ;
205
+
206
+ assert ! ( too_short) ;
207
+ assert ! ( too_long) ;
208
+ }
209
+ }
0 commit comments