1use molecule::prelude::Entity;
7use schemars::{JsonSchema, Schema, SchemaGenerator};
8use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
9use serde_with::{serde_as, serde_conv, DeserializeAs, SerializeAs};
10
11pub fn from_hex<'de, D, E>(deserializer: D) -> Result<E, D::Error>
12where
13 D: Deserializer<'de>,
14 E: TryFrom<Vec<u8>>,
15 E::Error: core::fmt::Debug,
16{
17 String::deserialize(deserializer)
18 .and_then(|string| {
19 let hex_str = string
20 .strip_prefix("0x")
21 .or_else(|| string.strip_prefix("0X"))
22 .unwrap_or(&string);
23 hex::decode(hex_str).map_err(|err| {
24 Error::custom(format!(
25 "failed to decode hex string {}: {:?}",
26 &string, err
27 ))
28 })
29 })
30 .and_then(|vec| {
31 vec.try_into().map_err(|err| {
32 Error::custom(format!("failed to convert vector into type: {:?}", err))
33 })
34 })
35}
36
37fn to_hex_with_prefix<E, S>(e: E, serializer: S, with_prefix: bool) -> Result<S::Ok, S::Error>
38where
39 E: AsRef<[u8]>,
40 S: Serializer,
41{
42 let hex_str = hex::encode(e.as_ref());
43 let prefix = if with_prefix { "0x" } else { "" };
44 serializer.serialize_str(&format!("{}{}", prefix, hex_str))
45}
46
47pub struct SliceHex;
48
49impl<T> SerializeAs<T> for SliceHex
50where
51 T: AsRef<[u8]>,
52{
53 fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
54 where
55 S: Serializer,
56 {
57 to_hex_with_prefix(source, serializer, true)
58 }
59}
60
61impl<'de, T> DeserializeAs<'de, T> for SliceHex
62where
63 T: TryFrom<Vec<u8>>,
64 T::Error: core::fmt::Debug,
65{
66 fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
67 where
68 D: Deserializer<'de>,
69 {
70 from_hex(deserializer)
71 }
72}
73
74pub struct EntityHex;
75
76impl<T> SerializeAs<T> for EntityHex
77where
78 T: Entity,
79{
80 fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
81 where
82 S: Serializer,
83 {
84 to_hex_with_prefix(source.as_slice(), serializer, true)
85 }
86}
87
88impl<'de, T> DeserializeAs<'de, T> for EntityHex
89where
90 T: Entity,
91{
92 fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
93 where
94 D: Deserializer<'de>,
95 {
96 let v: Vec<u8> = from_hex(deserializer)?;
97 T::from_slice(&v).map_err(Error::custom)
98 }
99}
100
101macro_rules! uint_as_hex {
102 ($name:ident, $ty:ty) => {
103 serde_conv!(
104 pub $name,
105 $ty,
106 |u: &$ty| format!("0x{:x}", u),
107 |hex: String| -> Result<$ty, String> {
108 let bytes = hex.as_bytes();
109 if bytes.len() < 3 || &bytes[..2] != b"0x" {
110 return Err(format!("uint hex string does not start with 0x: {}", hex));
111 }
112 if bytes.len() > 3 && &bytes[2..3] == b"0" {
113 return Err(format!(
114 "uint hex string starts with redundant leading zeros: {}",
115 hex
116 ));
117 };
118 <$ty>::from_str_radix(&hex[2..], 16)
119 .map_err(|err| format!("failed to parse uint hex {}: {:?}", hex, err))
120 }
121 );
122 };
123}
124
125uint_as_hex!(U128Hex, u128);
126uint_as_hex!(U64Hex, u64);
127uint_as_hex!(U32Hex, u32);
128
129#[derive(Copy, Clone, Debug, PartialEq, Eq)]
134pub struct HexU32(pub u32);
135
136impl serde::Serialize for HexU32 {
137 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
138 serializer.serialize_str(&format!("0x{:x}", self.0))
139 }
140}
141
142impl<'de> serde::Deserialize<'de> for HexU32 {
143 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
144 let hex: String = String::deserialize(deserializer)?;
145 let bytes = hex.as_bytes();
146 if bytes.len() < 3 || &bytes[..2] != b"0x" {
147 return Err(D::Error::custom(format!(
148 "uint hex string does not start with 0x: {}",
149 hex
150 )));
151 }
152 if bytes.len() > 3 && &bytes[2..3] == b"0" {
153 return Err(D::Error::custom(format!(
154 "uint hex string starts with redundant leading zeros: {}",
155 hex
156 )));
157 }
158 u32::from_str_radix(&hex[2..], 16)
159 .map(HexU32)
160 .map_err(|err| D::Error::custom(format!("failed to parse uint hex {}: {:?}", hex, err)))
161 }
162}
163
164impl From<u32> for HexU32 {
165 fn from(v: u32) -> Self {
166 HexU32(v)
167 }
168}
169
170impl From<HexU32> for u32 {
171 fn from(v: HexU32) -> Self {
172 v.0
173 }
174}
175
176impl JsonSchema for HexU32 {
177 fn schema_name() -> std::borrow::Cow<'static, str> {
178 "HexU32".into()
179 }
180
181 fn json_schema(generator: &mut SchemaGenerator) -> Schema {
182 let mut schema = String::json_schema(generator);
183 schema.insert("pattern".into(), "^0x(0|[1-9a-fA-F][0-9a-fA-F]*)$".into());
184 schema
185 }
186}
187
188pub struct SliceHexNoPrefix;
189
190impl<T> SerializeAs<T> for SliceHexNoPrefix
191where
192 T: AsRef<[u8]>,
193{
194 fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
195 where
196 S: Serializer,
197 {
198 to_hex_with_prefix(source, serializer, false)
199 }
200}
201
202impl<'de, T> DeserializeAs<'de, T> for SliceHexNoPrefix
203where
204 T: TryFrom<Vec<u8>>,
205 T::Error: core::fmt::Debug,
206{
207 fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
208 where
209 D: Deserializer<'de>,
210 {
211 from_hex(deserializer)
212 }
213}
214
215#[serde_as]
221#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Serialize, Deserialize)]
222pub struct Pubkey(#[serde_as(as = "SliceHexNoPrefix")] pub [u8; 33]);
223
224impl Pubkey {
225 pub fn from_slice(bytes: &[u8]) -> Result<Self, String> {
227 if bytes.len() != 33 {
228 return Err(format!(
229 "invalid pubkey length: expected 33 bytes, got {}",
230 bytes.len()
231 ));
232 }
233 let mut arr = [0u8; 33];
234 arr.copy_from_slice(bytes);
235 Ok(Pubkey(arr))
236 }
237
238 pub fn as_bytes(&self) -> &[u8; 33] {
240 &self.0
241 }
242}
243
244impl core::fmt::Debug for Pubkey {
245 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
246 write!(f, "Pubkey({})", hex::encode(self.0))
247 }
248}
249
250impl core::fmt::Display for Pubkey {
251 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
252 write!(f, "{}", hex::encode(self.0))
253 }
254}
255
256impl core::str::FromStr for Pubkey {
257 type Err = String;
258
259 fn from_str(s: &str) -> Result<Self, Self::Err> {
260 let hex_str = s
261 .strip_prefix("0x")
262 .or_else(|| s.strip_prefix("0X"))
263 .unwrap_or(s);
264 let bytes =
265 hex::decode(hex_str).map_err(|e| format!("invalid pubkey hex '{}': {}", s, e))?;
266 Pubkey::from_slice(&bytes)
267 }
268}
269
270impl JsonSchema for Pubkey {
271 fn schema_name() -> std::borrow::Cow<'static, str> {
272 "Pubkey".into()
273 }
274
275 fn json_schema(generator: &mut SchemaGenerator) -> Schema {
276 let mut schema = String::json_schema(generator);
277 schema.insert("pattern".into(), "^[0-9a-fA-F]{66}$".into());
278 schema
279 }
280}
281
282#[serde_as]
288#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Serialize, Deserialize)]
289pub struct Privkey(#[serde_as(as = "SliceHexNoPrefix")] pub [u8; 32]);
290
291impl Privkey {
292 pub fn from_slice(bytes: &[u8]) -> Result<Self, String> {
294 if bytes.len() != 32 {
295 return Err(format!(
296 "invalid privkey length: expected 32 bytes, got {}",
297 bytes.len()
298 ));
299 }
300 let mut arr = [0u8; 32];
301 arr.copy_from_slice(bytes);
302 Ok(Privkey(arr))
303 }
304
305 pub fn as_bytes(&self) -> &[u8; 32] {
307 &self.0
308 }
309}
310
311impl From<[u8; 32]> for Privkey {
312 fn from(value: [u8; 32]) -> Self {
313 Self(value)
314 }
315}
316
317impl From<Privkey> for [u8; 32] {
318 fn from(value: Privkey) -> Self {
319 value.0
320 }
321}
322
323impl core::fmt::Debug for Privkey {
324 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
325 write!(f, "Privkey(<redacted>)")
326 }
327}
328
329impl core::fmt::Display for Privkey {
330 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
331 write!(f, "{}", hex::encode(self.0))
332 }
333}
334
335impl core::str::FromStr for Privkey {
336 type Err = String;
337
338 fn from_str(s: &str) -> Result<Self, Self::Err> {
339 let hex_str = s
340 .strip_prefix("0x")
341 .or_else(|| s.strip_prefix("0X"))
342 .unwrap_or(s);
343 let bytes =
344 hex::decode(hex_str).map_err(|e| format!("invalid privkey hex '{}': {}", s, e))?;
345 Privkey::from_slice(&bytes)
346 }
347}
348
349impl JsonSchema for Privkey {
350 fn schema_name() -> std::borrow::Cow<'static, str> {
351 "Privkey".into()
352 }
353
354 fn json_schema(generator: &mut SchemaGenerator) -> Schema {
355 let mut schema = String::json_schema(generator);
356 schema.insert("pattern".into(), "^[0-9a-fA-F]{64}$".into());
357 schema
358 }
359}
360
361#[serde_as]
366#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
367pub struct Hash256(#[serde_as(as = "SliceHex")] pub [u8; 32]);
368
369impl Hash256 {
370 pub fn from_slice(bytes: &[u8]) -> Result<Self, String> {
372 if bytes.len() != 32 {
373 return Err(format!(
374 "invalid hash256 length: expected 32 bytes, got {}",
375 bytes.len()
376 ));
377 }
378 let mut arr = [0u8; 32];
379 arr.copy_from_slice(bytes);
380 Ok(Hash256(arr))
381 }
382
383 pub fn as_bytes(&self) -> &[u8; 32] {
385 &self.0
386 }
387}
388
389impl core::fmt::Debug for Hash256 {
390 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
391 write!(f, "Hash256(0x{})", hex::encode(self.0))
392 }
393}
394
395impl core::fmt::Display for Hash256 {
396 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
397 write!(f, "0x{}", hex::encode(self.0))
398 }
399}
400
401impl core::str::FromStr for Hash256 {
402 type Err = String;
403
404 fn from_str(s: &str) -> Result<Self, Self::Err> {
405 let hex_str = s
406 .strip_prefix("0x")
407 .or_else(|| s.strip_prefix("0X"))
408 .unwrap_or(s);
409 let bytes =
410 hex::decode(hex_str).map_err(|e| format!("invalid hash256 hex '{}': {}", s, e))?;
411 Hash256::from_slice(&bytes)
412 }
413}
414
415impl JsonSchema for Hash256 {
416 fn schema_name() -> std::borrow::Cow<'static, str> {
417 "Hash256".into()
418 }
419
420 fn json_schema(generator: &mut SchemaGenerator) -> Schema {
421 let mut schema = String::json_schema(generator);
422 schema.insert("pattern".into(), "^0x[0-9a-fA-F]{64}$".into());
423 schema
424 }
425}
426
427pub mod duration_hex {
429 use core::time::Duration;
430 use serde::{Deserialize, Deserializer, Serializer};
431
432 pub fn serialize<S>(duration: &Duration, serializer: S) -> Result<S::Ok, S::Error>
433 where
434 S: Serializer,
435 {
436 let nanos = duration.as_secs();
437 serializer.serialize_str(&format!("0x{:x}", nanos))
438 }
439
440 pub fn deserialize<'de, D>(deserializer: D) -> Result<Duration, D::Error>
441 where
442 D: Deserializer<'de>,
443 {
444 let hex_str = String::deserialize(deserializer)?;
445 let seconds = u64::from_str_radix(&hex_str[2..], 16).map_err(|err| {
446 serde::de::Error::custom(format!(
447 "failed to parse duration hex {}: {:?}",
448 hex_str, err
449 ))
450 })?;
451
452 Ok(Duration::from_secs(seconds))
453 }
454}
455
456#[macro_export]
460macro_rules! define_rpc_flags {
461 (
462 $(#[$struct_meta:meta])*
463 pub struct $name:ident($ty:ty) {
464 $($(#[$flag_meta:meta])* const $flag_name:ident = $flag_value:expr;)*
465 }
466 ) => {
467 $(#[$struct_meta])*
468 pub struct $name(pub $ty);
469
470 impl $name {
471 $(pub const $flag_name: $ty = $flag_value;)*
472
473 #[allow(clippy::wrong_self_convention)]
474 fn to_strings(self) -> Vec<String> {
475 let mut names = Vec::new();
476 $(
477 if self.0 & Self::$flag_name != 0 {
478 names.push(stringify!($flag_name).to_string());
479 }
480 )*
481 names
482 }
483
484 fn from_string(s: &str) -> Option<Self> {
485 let mut flags: $ty = 0;
486 for name in s.split('|') {
487 let name = name.trim();
488 match name {
489 $(stringify!($flag_name) => flags |= Self::$flag_name,)*
490 _ => return None,
491 }
492 }
493 Some($name(flags))
494 }
495 }
496
497 impl serde::Serialize for $name {
498 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
499 let names = self.clone().to_strings();
500 if names.is_empty() {
501 serializer.serialize_str("")
502 } else {
503 serializer.serialize_str(&names.join("|"))
504 }
505 }
506 }
507
508 impl<'de> serde::Deserialize<'de> for $name {
509 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
510 let s = String::deserialize(deserializer)?;
511 if s.is_empty() {
512 Ok($name(0))
513 } else {
514 $name::from_string(&s)
515 .ok_or_else(|| serde::de::Error::custom(format!("Invalid {}: {}", stringify!($name), s)))
516 }
517 }
518 }
519
520 impl From<$ty> for $name {
521 fn from(v: $ty) -> Self {
522 $name(v)
523 }
524 }
525
526 impl From<$name> for $ty {
527 fn from(v: $name) -> Self {
528 v.0
529 }
530 }
531
532 impl schemars::JsonSchema for $name {
533 fn schema_name() -> std::borrow::Cow<'static, str> {
534 stringify!($name).into()
535 }
536
537 fn json_schema(_generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
538 let flag_names: Vec<String> = vec![
539 $(stringify!($flag_name).to_string(),)*
540 ];
541 let single = flag_names.join("|");
542 let pattern = format!("^(({single})(\\s*\\|\\s*({single}))*)?$");
543 schemars::json_schema!({
544 "type": "string",
545 "pattern": pattern,
546 })
547 }
548 }
549 };
550}