gost_56042/
string_types.rs

1use core::{fmt::Display, ops::Deref};
2
3use alloc::boxed::Box;
4
5/// Строка с фиксированным размером, который равен ```N```
6#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
7pub struct ExactSizeString<const N: usize>(Box<str>);
8
9impl<const N: usize> ExactSizeString<N> {
10    /// Проверяется размер входной строки.
11    ///
12    /// Если размер входной строки не равен ```N```, то вернется ```None```.
13    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    /// Проверяется размер входной строки.
24    ///
25    /// Если строка имеет размер больше ```N```, то она обрезается до размера N.
26    ///
27    /// Если строка меньше ```N```, то вернется ```None```.
28    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    /// Создается ```ExactSizeString<N>``` без проверки.
39    ///
40    /// В реализации используется ```debug_assertion``` для проверки размера входной строки в `Debug` режиме.
41    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/// Строка с фиксированным размером, который меньше или равен ```N```
64#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
65pub struct MaxSizeString<const N: usize>(Box<str>);
66
67impl<const N: usize> MaxSizeString<N> {
68    /// Проверяется размер входной строки.
69    ///
70    /// Если размер входной строки больше ```N```, то вернется ```None```.
71    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    /// Проверяется размер входной строки.
81    ///
82    /// Если размер входной строки больше ```N```, то она обрезается до ```N``` символов.
83    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    /// Создается ```MaxSizeString<N>``` без проверки.
92    ///
93    /// В реализации используется ```debug_assertion``` для проверки размера входной строки в `Debug` режиме.
94    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}