foundry_common_fmt/
dynamic.rs
1use super::{format_int_exp, format_uint_exp};
2use alloy_dyn_abi::{DynSolType, DynSolValue};
3use alloy_primitives::hex;
4use std::fmt;
5
6struct DynValueFormatter {
8 raw: bool,
9}
10
11impl DynValueFormatter {
12 fn value(&self, value: &DynSolValue, f: &mut fmt::Formatter<'_>) -> fmt::Result {
14 match value {
15 DynSolValue::Address(inner) => write!(f, "{inner}"),
16 DynSolValue::Function(inner) => write!(f, "{inner}"),
17 DynSolValue::Bytes(inner) => f.write_str(&hex::encode_prefixed(inner)),
18 DynSolValue::FixedBytes(word, size) => {
19 f.write_str(&hex::encode_prefixed(&word[..*size]))
20 }
21 DynSolValue::Uint(inner, _) => {
22 if self.raw {
23 write!(f, "{inner}")
24 } else {
25 f.write_str(&format_uint_exp(*inner))
26 }
27 }
28 DynSolValue::Int(inner, _) => {
29 if self.raw {
30 write!(f, "{inner}")
31 } else {
32 f.write_str(&format_int_exp(*inner))
33 }
34 }
35 DynSolValue::Array(values) | DynSolValue::FixedArray(values) => {
36 f.write_str("[")?;
37 self.list(values, f)?;
38 f.write_str("]")
39 }
40 DynSolValue::Tuple(values) => self.tuple(values, f),
41 DynSolValue::String(inner) => {
42 if self.raw {
43 write!(f, "{}", inner.escape_debug())
44 } else {
45 write!(f, "{inner:?}") }
47 }
48 DynSolValue::Bool(inner) => write!(f, "{inner}"),
49 DynSolValue::CustomStruct { name, prop_names, tuple } => {
50 if self.raw {
51 return self.tuple(tuple, f);
52 }
53
54 f.write_str(name)?;
55
56 if prop_names.len() == tuple.len() {
57 f.write_str("({ ")?;
58
59 for (i, (prop_name, value)) in std::iter::zip(prop_names, tuple).enumerate() {
60 if i > 0 {
61 f.write_str(", ")?;
62 }
63 f.write_str(prop_name)?;
64 f.write_str(": ")?;
65 self.value(value, f)?;
66 }
67
68 f.write_str(" })")
69 } else {
70 self.tuple(tuple, f)
71 }
72 }
73 }
74 }
75
76 fn list(&self, values: &[DynSolValue], f: &mut fmt::Formatter<'_>) -> fmt::Result {
78 for (i, value) in values.iter().enumerate() {
79 if i > 0 {
80 f.write_str(", ")?;
81 }
82 self.value(value, f)?;
83 }
84 Ok(())
85 }
86
87 fn tuple(&self, values: &[DynSolValue], f: &mut fmt::Formatter<'_>) -> fmt::Result {
89 f.write_str("(")?;
90 self.list(values, f)?;
91 f.write_str(")")
92 }
93}
94
95struct DynValueDisplay<'a> {
97 value: &'a DynSolValue,
99 formatter: DynValueFormatter,
101}
102
103impl<'a> DynValueDisplay<'a> {
104 #[inline]
106 fn new(value: &'a DynSolValue, raw: bool) -> Self {
107 Self { value, formatter: DynValueFormatter { raw } }
108 }
109}
110
111impl fmt::Display for DynValueDisplay<'_> {
112 #[inline]
113 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114 self.formatter.value(self.value, f)
115 }
116}
117
118pub fn parse_tokens<'a, I: IntoIterator<Item = (&'a DynSolType, &'a str)>>(
120 params: I,
121) -> alloy_dyn_abi::Result<Vec<DynSolValue>> {
122 params.into_iter().map(|(param, value)| DynSolType::coerce_str(param, value)).collect()
123}
124
125pub fn format_tokens(tokens: &[DynSolValue]) -> impl Iterator<Item = String> + '_ {
127 tokens.iter().map(format_token)
128}
129
130pub fn format_tokens_raw(tokens: &[DynSolValue]) -> impl Iterator<Item = String> + '_ {
132 tokens.iter().map(format_token_raw)
133}
134
135pub fn format_token(value: &DynSolValue) -> String {
137 DynValueDisplay::new(value, false).to_string()
138}
139
140pub fn format_token_raw(value: &DynSolValue) -> String {
146 DynValueDisplay::new(value, true).to_string()
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152 use alloy_primitives::{address, U256};
153
154 #[test]
155 fn parse_hex_uint() {
156 let ty = DynSolType::Uint(256);
157
158 let values = parse_tokens(std::iter::once((&ty, "100"))).unwrap();
159 assert_eq!(values, [DynSolValue::Uint(U256::from(100), 256)]);
160
161 let val: U256 = U256::from(100u64);
162 let hex_val = format!("0x{val:x}");
163 let values = parse_tokens(std::iter::once((&ty, hex_val.as_str()))).unwrap();
164 assert_eq!(values, [DynSolValue::Uint(U256::from(100), 256)]);
165 }
166
167 #[test]
168 fn format_addr() {
169 assert_eq!(
171 format_token(&DynSolValue::Address(address!(
172 "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
173 ))),
174 "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
175 );
176
177 assert_ne!(
179 format_token(&DynSolValue::Address(address!(
180 "0xFb6916095cA1Df60bb79ce92cE3EA74c37c5d359"
181 ))),
182 "0xFb6916095cA1Df60bb79ce92cE3EA74c37c5d359"
183 );
184 }
185}