havok_types/
cstring.rs
1use crate::{NULL_STR, StringPtr, lib::*};
2
3#[cfg_attr(feature = "json_schema", derive(schemars::JsonSchema))]
27#[cfg_attr(feature = "json_schema", schemars(transparent))]
28#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
29#[cfg_attr(feature = "serde", serde(transparent))]
30#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
31pub struct CString<'a> {
32 #[cfg_attr(feature = "serde", serde(borrow))]
33 inner: Option<Cow<'a, str>>,
34}
35
36impl<'a> CString<'a> {
37 #[inline]
39 pub const fn new(inner: Option<Cow<'a, str>>) -> Self {
40 Self { inner }
41 }
42
43 #[inline]
45 pub fn into_inner(self) -> Option<Cow<'a, str>> {
46 self.inner
47 }
48
49 #[inline]
51 pub const fn get_ref(&self) -> &Option<Cow<'a, str>> {
52 &self.inner
53 }
54
55 #[allow(clippy::should_implement_trait)]
57 #[inline]
58 pub const fn from_str(s: &'a str) -> Self {
59 Self {
60 inner: Some(Cow::Borrowed(s)),
61 }
62 }
63
64 #[inline]
66 pub const fn from_option(s: Option<Cow<'a, str>>) -> Self {
67 Self { inner: s }
68 }
69
70 #[inline]
74 pub const fn is_null(&self) -> bool {
75 self.get_ref().is_none()
76 }
77
78 #[inline]
82 pub fn should_write_binary(&self) -> bool {
83 match self.get_ref() {
84 Some(s) => {
85 if s.is_empty() || s == NULL_STR {
86 return false;
87 };
88 true
89 }
90 _ => false,
91 }
92 }
93
94 #[inline]
96 pub fn as_str(&self) -> &str {
97 self.inner.as_ref().map_or(NULL_STR, |s| s.as_ref())
98 }
99}
100
101impl fmt::Display for CString<'_> {
102 #[inline]
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104 write!(f, "{}", self.as_str())
105 }
106}
107
108impl PartialEq<str> for CString<'_> {
109 #[inline]
110 fn eq(&self, other: &str) -> bool {
111 self.as_str() == other
112 }
113}
114
115impl PartialEq<&str> for CString<'_> {
116 #[inline]
117 fn eq(&self, other: &&str) -> bool {
118 self.as_str() == *other
119 }
120}
121
122impl PartialEq<String> for CString<'_> {
123 #[inline]
124 fn eq(&self, other: &String) -> bool {
125 self.as_str() == other.as_str()
126 }
127}
128
129impl<'a> From<&'a str> for CString<'a> {
130 #[inline]
131 fn from(value: &'a str) -> Self {
132 Self::from_str(value)
133 }
134}
135
136impl<'a> From<CString<'a>> for StringPtr<'a> {
137 #[inline]
138 fn from(value: CString<'a>) -> Self {
139 Self::from_option(value.into_inner())
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146 use std::borrow::Cow;
147
148 #[test]
149 fn test_is_null() {
150 let cstring = CString::new(None);
151 assert!(cstring.is_null());
152
153 let cstring_with_str = CString::from_str("test");
154 assert!(!cstring_with_str.is_null());
155 }
156
157 #[test]
158 fn test_should_write_binary() {
159 let cstring = CString::new(None);
160 assert!(!cstring.should_write_binary());
161
162 let empty_cstring = CString::from_str("");
163 assert!(!empty_cstring.should_write_binary());
164
165 let null_str_cstring = CString::from_str(NULL_STR);
166 assert!(!null_str_cstring.should_write_binary());
167
168 let valid_cstring = CString::from_str("valid");
169 assert!(valid_cstring.should_write_binary());
170 }
171
172 #[test]
173 fn test_display() {
174 let null_cstring = CString::new(None);
175 assert_eq!(null_cstring, NULL_STR);
176
177 let cstring = CString::from_str("display test");
178 assert_eq!(cstring, "display test");
179 }
180
181 #[test]
182 fn test_from_str_conversion() {
183 let cstring: CString = "test string".into();
184 assert_eq!(cstring.get_ref(), &Some(Cow::Borrowed("test string")));
185 }
186
187 #[test]
188 fn test_to_string_ptr() {
189 let cstring = CString::from_str("test");
190 let string_ptr: StringPtr = cstring.clone().into();
191 assert_eq!(string_ptr.get_ref(), cstring.get_ref());
192 }
193
194 #[cfg(feature = "serde")]
195 #[test]
196 fn test_serialization() {
197 let cstring = CString::from_str("serialize me");
198 let serialized = serde_json::to_string(&cstring).unwrap();
199 assert_eq!(serialized, "\"serialize me\"");
200
201 let null_cstring = CString::new(None);
202 let serialized_null = serde_json::to_string(&null_cstring).unwrap();
203 assert_eq!(serialized_null, "null");
204 }
205
206 #[cfg(feature = "serde")]
207 #[test]
208 fn test_deserialization() {
209 let json_data = "\"deserialize me\"";
210 let deserialized: CString = serde_json::from_str(json_data).unwrap();
211 assert_eq!(
212 deserialized.get_ref(),
213 &Some(Cow::Borrowed("deserialize me"))
214 );
215
216 let json_null = "null";
217 let deserialized_null: CString = serde_json::from_str(json_null).unwrap();
218 assert!(deserialized_null.is_null());
219 }
220}