gost_56042/
string_types.rs1use core::{fmt::Display, ops::Deref};
2
3use alloc::boxed::Box;
4
5#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
7pub struct ExactSizeString<const N: usize>(Box<str>);
8
9impl<const N: usize> ExactSizeString<N> {
10 pub fn new(val: impl Into<Box<str>>) -> Option<Self> {
14 let val = val.into();
15
16 if val.chars().count() == N {
17 Some(Self(val))
18 } else {
19 None
20 }
21 }
22
23 pub fn new_strip(val: impl Into<Box<str>>) -> Option<Self> {
29 let val = val.into();
30
31 match val.chars().count().cmp(&N) {
32 core::cmp::Ordering::Less => None,
33 core::cmp::Ordering::Equal => Some(Self(val)),
34 core::cmp::Ordering::Greater => Some(Self(val.chars().take(N).collect())),
35 }
36 }
37
38 pub fn new_unchecked(val: impl Into<Box<str>>) -> Self {
42 let val = val.into();
43
44 debug_assert_eq!(val.chars().count(), N);
45 Self(val)
46 }
47}
48
49impl<const N: usize> Display for ExactSizeString<N> {
50 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
51 self.0.fmt(f)
52 }
53}
54
55impl<const N: usize> Deref for ExactSizeString<N> {
56 type Target = str;
57
58 fn deref(&self) -> &Self::Target {
59 &self.0
60 }
61}
62
63#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
65pub struct MaxSizeString<const N: usize>(Box<str>);
66
67impl<const N: usize> MaxSizeString<N> {
68 pub fn new(val: impl Into<Box<str>>) -> Option<Self> {
72 let val = val.into();
73 if val.chars().count() <= N {
74 Some(Self(val))
75 } else {
76 None
77 }
78 }
79
80 pub fn new_strip(val: impl Into<Box<str>>) -> Self {
84 let val = val.into();
85 match val.chars().count().cmp(&N) {
86 core::cmp::Ordering::Less | core::cmp::Ordering::Equal => Self(val),
87 core::cmp::Ordering::Greater => Self(val.chars().take(N).collect()),
88 }
89 }
90
91 pub fn new_unchecked(val: impl Into<Box<str>>) -> Self {
95 let val = val.into();
96
97 debug_assert!(val.chars().count() <= N);
98 Self(val)
99 }
100}
101
102impl<const N: usize> Display for MaxSizeString<N> {
103 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
104 self.0.fmt(f)
105 }
106}
107
108impl<const N: usize> Deref for MaxSizeString<N> {
109 type Target = str;
110
111 fn deref(&self) -> &Self::Target {
112 &self.0
113 }
114}
115
116pub trait StringExt {
117 fn to_exact_size<const N: usize>(self) -> Option<ExactSizeString<N>>;
118 fn to_max_size<const N: usize>(self) -> Option<MaxSizeString<N>>;
119}
120
121impl StringExt for &str {
122 fn to_exact_size<const N: usize>(self) -> Option<ExactSizeString<N>> {
123 ExactSizeString::new(self)
124 }
125
126 fn to_max_size<const N: usize>(self) -> Option<MaxSizeString<N>> {
127 MaxSizeString::new(self)
128 }
129}