jam_std_common/util/
bounded_string.rs1use bounded_collections::{BoundedVec, ConstU32};
2use codec::{Decode, Encode, MaxEncodedLen};
3
4#[derive(Clone, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Encode)]
6pub struct BoundedString<const N: u32>(String);
7
8impl<const N: u32> std::fmt::Debug for BoundedString<N> {
9 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
10 self.0.fmt(f)
11 }
12}
13
14impl<const N: u32> std::fmt::Display for BoundedString<N> {
15 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16 self.0.fmt(f)
17 }
18}
19
20impl<const N: u32> std::ops::Deref for BoundedString<N> {
21 type Target = str;
22
23 fn deref(&self) -> &Self::Target {
24 &self.0
25 }
26}
27
28impl<const N: u32> Decode for BoundedString<N> {
29 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
30 let v = BoundedVec::<u8, ConstU32<N>>::decode(input)?;
31 String::from_utf8(v.into_inner()).map_err(|_| "Invalid UTF-8".into()).map(Self)
32 }
33}
34
35impl<const N: u32> MaxEncodedLen for BoundedString<N> {
36 fn max_encoded_len() -> usize {
37 BoundedVec::<u8, ConstU32<N>>::max_encoded_len()
38 }
39}
40
41pub trait IntoTruncated {
42 fn into_truncated<const N: u32>(self) -> BoundedString<N>;
45}
46
47impl IntoTruncated for String {
48 fn into_truncated<const N: u32>(mut self) -> BoundedString<N> {
49 if self.len() > (N as usize) {
50 while self.len() > (N.saturating_sub(3) as usize) {
51 self.pop();
52 }
53 while self.len() < (N as usize) {
54 self.push('.');
55 }
56 debug_assert!(self.len() <= (N as usize));
57 }
58 BoundedString(self)
59 }
60}
61
62pub trait Truncated {
63 fn truncated<const N: u32>(&self) -> BoundedString<N>;
66}
67
68impl<T: ToString + ?Sized> Truncated for T {
69 fn truncated<const N: u32>(&self) -> BoundedString<N> {
70 self.to_string().into_truncated()
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn truncation() {
80 debug_assert_eq!("abc".truncated(), BoundedString::<4>("abc".into()));
81 debug_assert_eq!("abc".truncated(), BoundedString::<3>("abc".into()));
82 debug_assert_eq!("abcd".truncated(), BoundedString::<3>("...".into()));
83 debug_assert_eq!("abc".truncated(), BoundedString::<2>("..".into()));
84 debug_assert_eq!("abc".truncated(), BoundedString::<1>(".".into()));
85 debug_assert_eq!("abc".truncated(), BoundedString::<0>("".into()));
86 debug_assert_eq!("abcdefg".truncated(), BoundedString::<6>("abc...".into()));
87 }
88}