ink_revive_types/
hex_serde.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18use alloc::{
19    format,
20    string::String,
21    vec::Vec,
22};
23use alloy_core::hex;
24use serde::{
25    Deserialize,
26    Deserializer,
27    Serializer,
28};
29
30pub trait HexCodec: Sized {
31    type Error;
32    fn to_hex(&self) -> String;
33    fn from_hex(s: String) -> Result<Self, Self::Error>;
34}
35
36macro_rules! impl_hex_codec {
37    ($($t:ty),*) => {
38        $(
39            impl HexCodec for $t {
40                type Error = core::num::ParseIntError;
41                fn to_hex(&self) -> String {
42                    format!("0x{:x}", self)
43                }
44                fn from_hex(s: String) -> Result<Self, Self::Error> {
45                    <$t>::from_str_radix(s.trim_start_matches("0x"), 16)
46                }
47            }
48        )*
49    };
50}
51
52impl_hex_codec!(u8, u32);
53
54impl<const T: usize> HexCodec for [u8; T] {
55    type Error = hex::FromHexError;
56    fn to_hex(&self) -> String {
57        format!("0x{}", hex::encode(self))
58    }
59    fn from_hex(s: String) -> Result<Self, Self::Error> {
60        let data = hex::decode(s.trim_start_matches("0x"))?;
61        data.try_into()
62            .map_err(|_| hex::FromHexError::InvalidStringLength)
63    }
64}
65
66impl HexCodec for Vec<u8> {
67    type Error = hex::FromHexError;
68    fn to_hex(&self) -> String {
69        format!("0x{}", hex::encode(self))
70    }
71    fn from_hex(s: String) -> Result<Self, Self::Error> {
72        hex::decode(s.trim_start_matches("0x"))
73    }
74}
75
76pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
77where
78    S: Serializer,
79    T: HexCodec,
80{
81    let s = value.to_hex();
82    serializer.serialize_str(&s)
83}
84
85pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
86where
87    D: Deserializer<'de>,
88    T: HexCodec,
89    <T as HexCodec>::Error: core::fmt::Debug,
90{
91    let s = String::deserialize(deserializer)?;
92    let value =
93        T::from_hex(s).map_err(|e| serde::de::Error::custom(format!("{:?}", e)))?;
94    Ok(value)
95}