sidechain_domain/
byte_string.rs1use alloc::string::ToString;
4use alloc::vec::Vec;
5use byte_string_derive::byte_string;
6use core::fmt::{Debug, Display};
7use core::ops::Deref;
8use derive_where::derive_where;
9use parity_scale_codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
10use scale_info::TypeInfo;
11use serde::de::Error as DeError;
12use serde::ser::Error as SerError;
13use serde::{Deserialize, Serialize};
14use sp_core::Get;
15use sp_core::bounded::BoundedVec;
16
17#[derive(Eq, Clone, PartialEq, TypeInfo, Default, Encode, Decode, PartialOrd, Ord)]
20#[byte_string(debug)]
21#[cfg_attr(feature = "std", byte_string(to_hex_string, decode_hex))]
22#[cfg_attr(feature = "serde", byte_string(hex_serialize, hex_deserialize))]
23pub struct ByteString(pub Vec<u8>);
24
25impl From<&[u8]> for ByteString {
26 fn from(bytes: &[u8]) -> Self {
27 Self(bytes.to_vec())
28 }
29}
30
31impl From<Vec<u8>> for ByteString {
32 fn from(vec: Vec<u8>) -> Self {
33 Self(vec)
34 }
35}
36
37impl Deref for ByteString {
38 type Target = [u8];
39
40 fn deref(&self) -> &Self::Target {
41 &self.0
42 }
43}
44
45#[derive(Eq, Clone, PartialEq, TypeInfo, MaxEncodedLen, Encode, Decode, DecodeWithMemTracking)]
47#[byte_string(debug)]
48#[byte_string(to_hex_string)]
49#[cfg_attr(feature = "std", byte_string(decode_hex))]
50#[cfg_attr(feature = "serde", byte_string(hex_serialize, hex_deserialize))]
51pub struct SizedByteString<const N: usize>(pub [u8; N]);
52
53impl<const N: usize> From<[u8; N]> for SizedByteString<N> {
54 fn from(value: [u8; N]) -> Self {
55 Self(value)
56 }
57}
58
59impl<const N: usize> TryFrom<Vec<u8>> for SizedByteString<N> {
60 type Error = <[u8; N] as TryFrom<Vec<u8>>>::Error;
61
62 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
63 Ok(SizedByteString(value.try_into()?))
64 }
65}
66
67impl<const N: usize> Default for SizedByteString<N> {
68 fn default() -> Self {
69 Self([0; N])
70 }
71}
72
73#[derive(TypeInfo, Encode, DecodeWithMemTracking, MaxEncodedLen)]
75#[scale_info(skip_type_params(T))]
76#[derive_where(Clone, PartialEq, Eq, Default, PartialOrd, Ord)]
77pub struct BoundedString<T: Get<u32>>(BoundedVec<u8, T>);
78
79#[macro_export]
81macro_rules! bounded_str {
82 ($($arg:expr)+) => {
83 sidechain_domain::byte_string::BoundedString::try_from(format!($($arg)+).as_str()).unwrap()
84 };
85}
86
87impl<T: Get<u32>> Decode for BoundedString<T> {
88 fn decode<I: parity_scale_codec::Input>(
89 input: &mut I,
90 ) -> Result<Self, parity_scale_codec::Error> {
91 let bounded_vec: BoundedVec<u8, T> = Decode::decode(input)?;
92
93 core::str::from_utf8(bounded_vec.as_slice())
95 .map_err(|_err| parity_scale_codec::Error::from("UTF-8 decode failed"))?;
96
97 Ok(Self(bounded_vec))
98 }
99}
100
101impl<'a, T: Get<u32>> Deserialize<'a> for BoundedString<T> {
102 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
103 where
104 D: serde::Deserializer<'a>,
105 {
106 Ok(Self(
107 BoundedVec::try_from(
108 alloc::string::String::deserialize(deserializer)?.as_bytes().to_vec(),
109 )
110 .map_err(|_| D::Error::custom("Size limit exceeded"))?,
111 ))
112 }
113}
114
115impl<T: Get<u32>> Serialize for BoundedString<T> {
116 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
117 where
118 S: serde::Serializer,
119 {
120 let str = alloc::string::String::from_utf8(self.0.to_vec())
121 .map_err(|_| S::Error::custom("String is not valid UTF-8"))?;
122 serializer.serialize_str(&str)
123 }
124}
125
126impl<T: Get<u32>> Display for BoundedString<T> {
127 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
128 f.write_str(
129 &alloc::string::String::from_utf8(self.0.to_vec()).map_err(|_| core::fmt::Error)?,
130 )
131 }
132}
133
134impl<T: Get<u32>> Debug for BoundedString<T> {
135 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
136 f.write_str(&alloc::format!("BoundedString<{}>({})", T::get(), self))
137 }
138}
139
140impl<T: Get<u32>> TryFrom<&str> for BoundedString<T> {
141 type Error = alloc::string::String;
142
143 fn try_from(value: &str) -> Result<Self, Self::Error> {
144 Ok(Self(BoundedVec::try_from(value.as_bytes().to_vec()).map_err(|_| value.to_string())?))
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151
152 #[test]
153 fn decode_valid_utf8_string() {
154 let original = "hello world".encode();
155
156 let decoded = BoundedString::<sp_core::ConstU32<32>>::decode(&mut &*original).unwrap();
157 assert_eq!(original, decoded.encode());
158 }
159
160 #[test]
161 fn fail_to_decode_invalid_utf8_string() {
162 let original = vec![0xC0, 0x80, 0xE0, 0xFF].encode(); assert_eq!(
164 BoundedString::<sp_core::ConstU32<32>>::decode(&mut &*original),
165 Err(parity_scale_codec::Error::from("UTF-8 decode failed"))
166 );
167
168 use parity_scale_codec::DecodeWithMemLimit;
169
170 assert_eq!(
172 BoundedString::<sp_core::ConstU32<32>>::decode_with_mem_limit(&mut &*original, 100),
173 Err(parity_scale_codec::Error::from("UTF-8 decode failed"))
174 );
175 }
176}