ad_astra/exports/
string.rs1use std::{cell::RefCell, mem::take};
36
37use crate::{
38 export,
39 exports::utils::Stringifier,
40 runtime::{
41 ops::{ScriptConcat, ScriptDisplay, ScriptPartialEq},
42 Arg,
43 Cell,
44 Downcast,
45 Origin,
46 Provider,
47 RuntimeError,
48 RuntimeResult,
49 ScriptType,
50 TypeHint,
51 Upcast,
52 },
53};
54
55#[export(include)]
57pub(crate) type StringType = str;
58
59impl<'a> Downcast<'a> for &'a str {
60 fn downcast(origin: Origin, provider: Provider<'a>) -> RuntimeResult<Self> {
61 let mut type_match = provider.type_match();
62
63 if type_match.is::<str>() {
64 return provider.to_borrowed(&origin)?.borrow_str(origin);
65 }
66
67 return Err(type_match.mismatch(origin));
68 }
69
70 #[inline(always)]
71 fn hint() -> TypeHint {
72 TypeHint::Type(StringType::type_meta())
73 }
74}
75
76impl<'a> Downcast<'a> for Box<str> {
77 fn downcast(origin: Origin, provider: Provider<'a>) -> RuntimeResult<Self> {
78 let mut type_match = provider.type_match();
79
80 if type_match.is::<str>() {
81 return Ok(provider.to_owned().take_string(origin)?.into_boxed_str());
82 }
83
84 return Err(type_match.mismatch(origin));
85 }
86
87 #[inline(always)]
88 fn hint() -> TypeHint {
89 TypeHint::Type(StringType::type_meta())
90 }
91}
92
93impl<'a> Upcast<'a> for &'a str {
94 type Output = &'a str;
95
96 #[inline(always)]
97 fn upcast(_origin: Origin, this: Self) -> RuntimeResult<Self::Output> {
98 Ok(this)
99 }
100
101 #[inline(always)]
102 fn hint() -> TypeHint {
103 TypeHint::Type(StringType::type_meta())
104 }
105}
106
107impl<'a> Upcast<'a> for Box<str> {
108 type Output = String;
109
110 #[inline(always)]
111 fn upcast(_origin: Origin, this: Self) -> RuntimeResult<Self::Output> {
112 Ok(this.into_string())
113 }
114
115 #[inline(always)]
116 fn hint() -> TypeHint {
117 TypeHint::Type(StringType::type_meta())
118 }
119}
120
121#[export(include)]
122impl ScriptDisplay for str {}
123
124#[export(include)]
125impl ScriptConcat for str {
126 type Result = str;
127
128 fn script_concat(origin: Origin, items: &mut [Arg]) -> RuntimeResult<Cell> {
129 let mut result = String::new();
130
131 for item in items {
132 if item.data.is_nil() {
133 continue;
134 }
135
136 let cell = take(&mut item.data);
137
138 let stringifier = Stringifier {
139 origin: item.origin,
140 cell: &cell,
141 error: RefCell::new(None),
142 fallback_to_type: false,
143 };
144
145 let string = stringifier.to_string();
146
147 if let Some(error) = stringifier.error.take() {
148 return Err(error);
149 }
150
151 result.push_str(&string);
152 }
153
154 Cell::give(origin, result)
155 }
156}
157
158#[export(include)]
159impl ScriptPartialEq for str {
160 type RHS = str;
161
162 fn script_eq(_origin: Origin, mut lhs: Arg, mut rhs: Arg) -> RuntimeResult<bool> {
163 let lhs = lhs.data.borrow_str(lhs.origin)?;
164 let rhs = rhs.data.borrow_str(rhs.origin)?;
165
166 Ok(lhs == rhs)
167 }
168}
169
170impl<'a> Downcast<'a> for char {
171 fn downcast(origin: Origin, provider: Provider<'a>) -> RuntimeResult<Self> {
172 let mut type_match = provider.type_match();
173
174 if type_match.is::<str>() {
175 let string = provider.to_owned().take_string(origin)?;
176 let mut chars = string.chars();
177
178 let first = match chars.next() {
179 Some(ch) => ch,
180 None => {
181 return Err(RuntimeError::OutOfBounds {
182 access_origin: origin,
183 index: 0,
184 length: 0,
185 })
186 }
187 };
188
189 if chars.next().is_some() {
190 return Err(RuntimeError::NonSingleton {
191 access_origin: origin,
192 actual: string.len(),
193 });
194 }
195
196 return Ok(first);
197 }
198
199 return Err(type_match.mismatch(origin));
200 }
201
202 #[inline(always)]
203 fn hint() -> TypeHint {
204 TypeHint::Type(StringType::type_meta())
205 }
206}
207
208impl<'a> Upcast<'a> for char {
209 type Output = String;
210
211 #[inline]
212 fn upcast(_origin: Origin, this: Self) -> RuntimeResult<Self::Output> {
213 Ok(String::from(this))
214 }
215
216 #[inline(always)]
217 fn hint() -> TypeHint {
218 TypeHint::Type(StringType::type_meta())
219 }
220}
221
222impl<'a> Downcast<'a> for String {
223 fn downcast(origin: Origin, provider: Provider<'a>) -> RuntimeResult<Self> {
224 let mut type_match = provider.type_match();
225
226 if type_match.is::<str>() {
227 return provider.to_owned().take_string(origin);
228 }
229
230 if type_match.cell().ty().prototype().implements_display() {
231 let stringifier = Stringifier {
232 origin,
233 cell: &provider.to_owned(),
234 error: RefCell::new(None),
235 fallback_to_type: false,
236 };
237
238 let string = stringifier.to_string();
239
240 if let Some(error) = stringifier.error.take() {
241 return Err(error);
242 }
243
244 return Ok(string);
245 }
246
247 return Err(type_match.mismatch(origin));
248 }
249
250 #[inline(always)]
251 fn hint() -> TypeHint {
252 TypeHint::Type(StringType::type_meta())
253 }
254}
255
256impl<'a> Upcast<'a> for String {
257 type Output = Self;
258
259 #[inline(always)]
260 fn upcast(_origin: Origin, this: Self) -> RuntimeResult<Self::Output> {
261 Ok(this)
262 }
263
264 #[inline(always)]
265 fn hint() -> TypeHint {
266 TypeHint::Family(StringType::type_meta().family())
267 }
268}
269
270impl<'a> Upcast<'a> for &'a String {
271 type Output = &'a str;
272
273 #[inline(always)]
274 fn upcast(_origin: Origin, this: Self) -> RuntimeResult<Self::Output> {
275 Ok(this.as_str())
276 }
277
278 #[inline(always)]
279 fn hint() -> TypeHint {
280 TypeHint::Type(StringType::type_meta())
281 }
282}
283
284impl<'a> Upcast<'a> for &'a mut String {
285 type Output = &'a str;
286
287 #[inline(always)]
288 fn upcast(_origin: Origin, this: Self) -> RuntimeResult<Self::Output> {
289 Ok(this.as_str())
290 }
291
292 #[inline(always)]
293 fn hint() -> TypeHint {
294 TypeHint::Type(StringType::type_meta())
295 }
296}