Skip to main content

g_string/
conversion.rs

1#[cfg(feature = "alloc")]
2extern crate alloc;
3
4#[cfg(feature = "alloc")]
5use alloc::{borrow::ToOwned, string::String};
6
7use core::str::FromStr;
8
9use crate::{GString, Validator, error::GStringError};
10
11/// &str -> GString
12impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool> FromStr
13    for GString<V, MIN, MAX, ASCII_ONLY>
14{
15    type Err = GStringError<V::Err>;
16
17    fn from_str(s: &str) -> Result<Self, Self::Err> {
18        Self::try_new(s)
19    }
20}
21
22/// GString AS &str
23impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool> AsRef<str>
24    for GString<V, MIN, MAX, ASCII_ONLY>
25{
26    fn as_ref(&self) -> &str {
27        self.as_str()
28    }
29}
30
31/// String -> GString
32#[cfg(feature = "alloc")]
33impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool> TryFrom<String>
34    for GString<V, MIN, MAX, ASCII_ONLY>
35{
36    type Error = GStringError<V::Err>;
37
38    fn try_from(value: String) -> Result<Self, Self::Error> {
39        Self::try_new(&value)
40    }
41}
42
43/// GString -> String
44#[cfg(feature = "alloc")]
45impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool>
46    From<GString<V, MIN, MAX, ASCII_ONLY>> for String
47{
48    fn from(value: GString<V, MIN, MAX, ASCII_ONLY>) -> Self {
49        value.as_str().to_owned()
50    }
51}
52
53/// &str -> GString (try_into)
54impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool> TryFrom<&str>
55    for GString<V, MIN, MAX, ASCII_ONLY>
56{
57    type Error = GStringError<V::Err>;
58
59    fn try_from(value: &str) -> Result<Self, Self::Error> {
60        Self::from_str(value)
61    }
62}
63
64/// GString AS &\[u8\]
65impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool> AsRef<[u8]>
66    for GString<V, MIN, MAX, ASCII_ONLY>
67{
68    fn as_ref(&self) -> &[u8] {
69        self.as_bytes()
70    }
71}
72
73#[cfg(feature = "alloc")]
74impl<'a, V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool>
75    TryFrom<alloc::borrow::Cow<'a, str>> for GString<V, MIN, MAX, ASCII_ONLY>
76{
77    type Error = GStringError<V::Err>;
78
79    fn try_from(value: alloc::borrow::Cow<'a, str>) -> Result<Self, Self::Error> {
80        Self::from_str(&value)
81    }
82}
83
84impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool>
85    GString<V, MIN, MAX, ASCII_ONLY>
86{
87    /// Construct GString from iterator of `AsRef<str>`.
88    ///
89    /// # Examples
90    /// ```rust
91    /// use g_string::GString;
92    ///
93    /// let result: GString = GString::try_from_iter(["12", "3a"]).unwrap();
94    /// assert_eq!(result, "123a");
95    /// ```
96    pub fn try_from_iter<I, S>(iter: I) -> Result<Self, GStringError<V::Err>>
97    where
98        I: IntoIterator<Item = S>,
99        S: AsRef<str>,
100    {
101        let mut buf = [0u8; MAX];
102        let mut len = 0;
103
104        for s in iter {
105            let s = s.as_ref();
106            let bytes = s.as_bytes();
107
108            let end = len + bytes.len();
109
110            if end > MAX {
111                return Err(GStringError::TooLong(MAX));
112            }
113
114            buf[len..end].copy_from_slice(bytes);
115
116            len = end;
117        }
118
119        // SAFETY:
120        // concatenation of valid UTF-8 strings is valid UTF-8
121        let candidate = unsafe { core::str::from_utf8_unchecked(&buf[..len]) };
122
123        Self::try_new(candidate)
124    }
125
126    /// Construct GString from iterator of chars
127    ///
128    /// # Examples
129    /// ```rust
130    /// use g_string::GString;
131    ///
132    /// let result: GString = GString::try_from_chars(['a', 'b', 'c']).unwrap();
133    /// assert_eq!(result, "abc");
134    /// ```
135    pub fn try_from_chars<I>(iter: I) -> Result<Self, GStringError<V::Err>>
136    where
137        I: IntoIterator<Item = char>,
138    {
139        let mut buf = [0u8; MAX];
140        let mut len = 0;
141
142        for ch in iter {
143            let mut tmp = [0u8; 4];
144            let encoded = ch.encode_utf8(&mut tmp);
145
146            let bytes = encoded.as_bytes();
147            let end = len + bytes.len();
148
149            if end > MAX {
150                return Err(GStringError::TooLong(MAX));
151            }
152
153            buf[len..end].copy_from_slice(bytes);
154
155            len = end;
156        }
157
158        // SAFETY:
159        // buf always comes from UTF-8 encoded char
160        let candidate = unsafe { core::str::from_utf8_unchecked(&buf[..len]) };
161
162        Self::try_new(candidate)
163    }
164}