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(
47 Eq,
48 Clone,
49 PartialEq,
50 TypeInfo,
51 MaxEncodedLen,
52 Encode,
53 Decode,
54 DecodeWithMemTracking,
55 PartialOrd,
56 Ord,
57)]
58#[byte_string(debug)]
59#[byte_string(to_hex_string)]
60#[cfg_attr(feature = "std", byte_string(decode_hex))]
61#[cfg_attr(feature = "serde", byte_string(hex_serialize, hex_deserialize))]
62pub struct SizedByteString<const N: usize>(pub [u8; N]);
63
64impl<const N: usize> From<[u8; N]> for SizedByteString<N> {
65 fn from(value: [u8; N]) -> Self {
66 Self(value)
67 }
68}
69
70impl<const N: usize> TryFrom<Vec<u8>> for SizedByteString<N> {
71 type Error = <[u8; N] as TryFrom<Vec<u8>>>::Error;
72
73 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
74 Ok(SizedByteString(value.try_into()?))
75 }
76}
77
78impl<const N: usize> Default for SizedByteString<N> {
79 fn default() -> Self {
80 Self([0; N])
81 }
82}
83
84#[derive(TypeInfo, Encode, DecodeWithMemTracking, MaxEncodedLen)]
86#[scale_info(skip_type_params(T))]
87#[derive_where(Clone, PartialEq, Eq, Default, PartialOrd, Ord)]
88pub struct BoundedString<T: Get<u32>>(BoundedVec<u8, T>);
89
90#[macro_export]
92macro_rules! bounded_str {
93 ($($arg:expr)+) => {
94 sidechain_domain::byte_string::BoundedString::try_from(format!($($arg)+).as_str()).unwrap()
95 };
96}
97
98impl<T: Get<u32>> Decode for BoundedString<T> {
99 fn decode<I: parity_scale_codec::Input>(
100 input: &mut I,
101 ) -> Result<Self, parity_scale_codec::Error> {
102 let bounded_vec: BoundedVec<u8, T> = Decode::decode(input)?;
103
104 core::str::from_utf8(bounded_vec.as_slice())
106 .map_err(|_err| parity_scale_codec::Error::from("UTF-8 decode failed"))?;
107
108 Ok(Self(bounded_vec))
109 }
110}
111
112impl<'a, T: Get<u32>> Deserialize<'a> for BoundedString<T> {
113 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
114 where
115 D: serde::Deserializer<'a>,
116 {
117 Ok(Self(
118 BoundedVec::try_from(
119 alloc::string::String::deserialize(deserializer)?.as_bytes().to_vec(),
120 )
121 .map_err(|_| D::Error::custom("Size limit exceeded"))?,
122 ))
123 }
124}
125
126impl<T: Get<u32>> Serialize for BoundedString<T> {
127 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
128 where
129 S: serde::Serializer,
130 {
131 let str = alloc::string::String::from_utf8(self.0.to_vec())
132 .map_err(|_| S::Error::custom("String is not valid UTF-8"))?;
133 serializer.serialize_str(&str)
134 }
135}
136
137impl<T: Get<u32>> Display for BoundedString<T> {
138 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
139 f.write_str(
140 &alloc::string::String::from_utf8(self.0.to_vec()).map_err(|_| core::fmt::Error)?,
141 )
142 }
143}
144
145impl<T: Get<u32>> Debug for BoundedString<T> {
146 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
147 f.write_str(&alloc::format!("BoundedString<{}>({})", T::get(), self))
148 }
149}
150
151impl<T: Get<u32>> TryFrom<&str> for BoundedString<T> {
152 type Error = alloc::string::String;
153
154 fn try_from(value: &str) -> Result<Self, Self::Error> {
155 Ok(Self(BoundedVec::try_from(value.as_bytes().to_vec()).map_err(|_| value.to_string())?))
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162
163 #[test]
164 fn decode_valid_utf8_string() {
165 let original = "hello world".encode();
166
167 let decoded = BoundedString::<sp_core::ConstU32<32>>::decode(&mut &*original).unwrap();
168 assert_eq!(original, decoded.encode());
169 }
170
171 #[test]
172 fn fail_to_decode_invalid_utf8_string() {
173 let original = vec![0xC0, 0x80, 0xE0, 0xFF].encode(); assert_eq!(
175 BoundedString::<sp_core::ConstU32<32>>::decode(&mut &*original),
176 Err(parity_scale_codec::Error::from("UTF-8 decode failed"))
177 );
178
179 use parity_scale_codec::DecodeWithMemLimit;
180
181 assert_eq!(
183 BoundedString::<sp_core::ConstU32<32>>::decode_with_mem_limit(&mut &*original, 100),
184 Err(parity_scale_codec::Error::from("UTF-8 decode failed"))
185 );
186 }
187}