1use std::{
36 any::type_name,
37 ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
38 ptr::{addr_of, addr_of_mut},
39 sync::Arc,
40};
41
42use crate::{
43 export,
44 exports::utils::transparent_upcast,
45 runtime::{
46 ops::{ScriptClone, ScriptDebug, ScriptHash, ScriptPartialEq},
47 Arg,
48 Cell,
49 Downcast,
50 NumericOperationKind,
51 Origin,
52 Provider,
53 RuntimeError,
54 RuntimeResult,
55 ScriptType,
56 TypeHint,
57 Upcast,
58 },
59};
60
61#[export(include)]
66#[export(name "range")]
67pub(crate) type RangeType = Range<usize>;
68
69impl<'a> Downcast<'a> for RangeType {
70 fn downcast(origin: Origin, provider: Provider<'a>) -> RuntimeResult<Self> {
71 let mut type_match = provider.type_match();
72
73 if type_match.is::<Self>() {
74 return provider.to_owned().take(origin);
75 }
76
77 Err(type_match.mismatch(origin))
78 }
79
80 #[inline(always)]
81 fn hint() -> TypeHint {
82 TypeHint::Type(Self::type_meta())
83 }
84}
85
86impl<'a> Downcast<'a> for &'a RangeType {
87 #[inline]
88 fn downcast(origin: Origin, provider: Provider<'a>) -> RuntimeResult<Self> {
89 let mut type_match = provider.type_match();
90
91 if type_match.is::<RangeType>() {
92 return provider.to_borrowed(&origin)?.borrow_ref(origin);
93 }
94
95 Err(type_match.mismatch(origin))
96 }
97
98 #[inline(always)]
99 fn hint() -> TypeHint {
100 TypeHint::Type(RangeType::type_meta())
101 }
102}
103
104impl<'a> Downcast<'a> for &'a mut RangeType {
105 #[inline]
106 fn downcast(origin: Origin, provider: Provider<'a>) -> RuntimeResult<Self> {
107 let mut type_match = provider.type_match();
108
109 if type_match.is::<RangeType>() {
110 return provider.to_borrowed(&origin)?.borrow_mut(origin);
111 }
112
113 Err(type_match.mismatch(origin))
114 }
115
116 #[inline(always)]
117 fn hint() -> TypeHint {
118 TypeHint::Type(RangeType::type_meta())
119 }
120}
121
122transparent_upcast!(RangeType);
123
124#[export(include)]
125impl ScriptClone for RangeType {}
126
127#[export(include)]
128impl ScriptHash for RangeType {}
129
130#[export(include)]
131impl ScriptDebug for RangeType {}
132
133#[export(include)]
134impl ScriptPartialEq for RangeType {
135 type RHS = Self;
136
137 fn script_eq(_origin: Origin, mut lhs: Arg, mut rhs: Arg) -> RuntimeResult<bool> {
138 let lhs = lhs.data.borrow_ref::<Self>(lhs.origin)?;
139
140 let mut type_match = rhs.data.type_match();
141
142 if type_match.is::<Self>() {
143 let rhs = rhs.data.borrow_ref::<Self>(rhs.origin)?;
144
145 return Ok(lhs == rhs);
146 }
147
148 if type_match.belongs_to::<usize>() {
149 let singleton =
150 <usize as Downcast>::downcast(rhs.origin, Provider::Borrowed(&mut rhs.data))?;
151
152 return match singleton == usize::MAX {
153 true => Ok(false),
154
155 false => Ok(lhs.start == singleton && lhs.end == singleton + 1),
156 };
157 }
158
159 Err(type_match.mismatch(rhs.origin))
160 }
161}
162
163trait RangeImpl {
164 fn start(origin: Origin, lhs: Arg) -> RuntimeResult<Cell>;
165 fn end(origin: Origin, lhs: Arg) -> RuntimeResult<Cell>;
166}
167
168#[export(include)]
169impl RangeImpl for RangeType {
170 #[export(component RangeType)]
171 fn start(origin: Origin, lhs: Arg) -> RuntimeResult<Cell> {
172 unsafe fn by_ref(range: *const RangeType) -> *const usize {
173 unsafe { addr_of!((*range).start) }
175 }
176
177 unsafe fn by_mut(range: *mut RangeType) -> *mut usize {
178 unsafe { addr_of_mut!((*range).start) }
180 }
181
182 lhs.data
183 .map_ptr::<Self, usize>(origin, Some(by_ref), Some(by_mut))
184 }
185
186 #[export(component RangeType)]
187 fn end(origin: Origin, lhs: Arg) -> RuntimeResult<Cell> {
188 unsafe fn by_ref(range: *const RangeType) -> *const usize {
189 unsafe { addr_of!((*range).end) }
191 }
192
193 unsafe fn by_mut(range: *mut RangeType) -> *mut usize {
194 unsafe { addr_of_mut!((*range).end) }
196 }
197
198 lhs.data
199 .map_ptr::<Self, usize>(origin, Some(by_ref), Some(by_mut))
200 }
201}
202
203impl<'a> Downcast<'a> for RangeFrom<usize> {
204 #[inline]
205 fn downcast(origin: Origin, provider: Provider<'a>) -> RuntimeResult<Self> {
206 let range = provider.to_owned().take::<RangeType>(origin)?;
207
208 if range.end != usize::MAX {
209 return Err(RuntimeError::RangeCast {
210 access_origin: origin,
211 from: range,
212 to: type_name::<RangeFrom<usize>>(),
213 });
214 }
215
216 Ok(RangeFrom { start: range.start })
217 }
218
219 #[inline(always)]
220 fn hint() -> TypeHint {
221 TypeHint::Type(RangeType::type_meta())
222 }
223}
224
225impl<'a> Upcast<'a> for RangeFrom<usize> {
226 type Output = Box<RangeType>;
227
228 #[inline(always)]
229 fn upcast(_origin: Origin, this: Self) -> RuntimeResult<Self::Output> {
230 Ok(Box::new(this.start..usize::MAX))
231 }
232
233 #[inline(always)]
234 fn hint() -> TypeHint {
235 TypeHint::Type(RangeType::type_meta())
236 }
237}
238
239impl<'a> Downcast<'a> for RangeFull {
240 #[inline]
241 fn downcast(origin: Origin, provider: Provider<'a>) -> RuntimeResult<Self> {
242 let range = provider.to_owned().take::<RangeType>(origin)?;
243
244 if range.start != 0 || range.end != usize::MAX {
245 return Err(RuntimeError::RangeCast {
246 access_origin: origin,
247 from: range,
248 to: type_name::<RangeFrom<usize>>(),
249 });
250 }
251
252 Ok(RangeFull)
253 }
254
255 #[inline(always)]
256 fn hint() -> TypeHint {
257 TypeHint::Type(RangeType::type_meta())
258 }
259}
260
261impl<'a> Upcast<'a> for RangeFull {
262 type Output = Box<RangeType>;
263
264 #[inline(always)]
265 fn upcast(_origin: Origin, _this: Self) -> RuntimeResult<Self::Output> {
266 Ok(Box::new(0..usize::MAX))
267 }
268
269 #[inline(always)]
270 fn hint() -> TypeHint {
271 TypeHint::Type(RangeType::type_meta())
272 }
273}
274
275impl<'a> Downcast<'a> for RangeInclusive<usize> {
276 #[inline]
277 fn downcast(origin: Origin, provider: Provider<'a>) -> RuntimeResult<Self> {
278 let mut type_match = provider.type_match();
279
280 if type_match.is::<RangeType>() {
281 let range = provider.to_owned().take::<RangeType>(origin)?;
282
283 let start = range.start;
284
285 let end = match start.checked_add(1) {
286 Some(bound) => bound,
287
288 None => {
289 return Err(RuntimeError::NumericOperation {
290 invoke_origin: origin,
291 kind: NumericOperationKind::Add,
292 lhs: (usize::type_meta(), Arc::new(start)),
293 rhs: Some((usize::type_meta(), Arc::new(1))),
294 target: usize::type_meta(),
295 })
296 }
297 };
298
299 return Ok(start..=end);
300 }
301
302 if type_match.belongs_to::<usize>() {
303 let start = <usize as Downcast>::downcast(origin, provider)?;
304
305 return Ok(start..=start);
306 }
307
308 Err(type_match.mismatch(origin))
309 }
310
311 #[inline(always)]
312 fn hint() -> TypeHint {
313 TypeHint::Type(RangeType::type_meta())
314 }
315}
316
317impl<'a> Upcast<'a> for RangeInclusive<usize> {
318 type Output = Box<RangeType>;
319
320 #[inline]
321 fn upcast(origin: Origin, this: Self) -> RuntimeResult<Self::Output> {
322 let start = *this.start();
323
324 let end = match start.checked_add(1) {
325 Some(bound) => bound,
326
327 None => {
328 return Err(RuntimeError::NumericOperation {
329 invoke_origin: origin,
330 kind: NumericOperationKind::Add,
331 lhs: (usize::type_meta(), Arc::new(start)),
332 rhs: Some((usize::type_meta(), Arc::new(1))),
333 target: usize::type_meta(),
334 })
335 }
336 };
337
338 Ok(Box::new(start..end))
339 }
340
341 #[inline(always)]
342 fn hint() -> TypeHint {
343 TypeHint::Type(RangeType::type_meta())
344 }
345}
346
347impl<'a> Downcast<'a> for RangeTo<usize> {
348 #[inline]
349 fn downcast(origin: Origin, provider: Provider<'a>) -> RuntimeResult<Self> {
350 let range = provider.to_owned().take::<RangeType>(origin)?;
351
352 if range.start != 0 {
353 return Err(RuntimeError::RangeCast {
354 access_origin: origin,
355 from: range,
356 to: type_name::<RangeTo<usize>>(),
357 });
358 }
359
360 Ok(..range.end)
361 }
362
363 #[inline(always)]
364 fn hint() -> TypeHint {
365 TypeHint::Type(RangeType::type_meta())
366 }
367}
368
369impl<'a> Upcast<'a> for RangeTo<usize> {
370 type Output = Box<RangeType>;
371
372 #[inline(always)]
373 fn upcast(_origin: Origin, this: Self) -> RuntimeResult<Self::Output> {
374 Ok(Box::new(0..this.end))
375 }
376
377 #[inline(always)]
378 fn hint() -> TypeHint {
379 TypeHint::Type(RangeType::type_meta())
380 }
381}
382
383impl<'a> Downcast<'a> for RangeToInclusive<usize> {
384 #[inline]
385 fn downcast(origin: Origin, provider: Provider<'a>) -> RuntimeResult<Self> {
386 let range = provider.to_owned().take::<RangeType>(origin)?;
387
388 if range.start != 0 {
389 return Err(RuntimeError::RangeCast {
390 access_origin: origin,
391 from: range,
392 to: type_name::<RangeToInclusive<usize>>(),
393 });
394 }
395
396 let end = match range.end.checked_add(1) {
397 Some(bound) => bound,
398
399 None => {
400 return Err(RuntimeError::NumericOperation {
401 invoke_origin: origin,
402 kind: NumericOperationKind::Add,
403 lhs: (usize::type_meta(), Arc::new(range.end)),
404 rhs: Some((usize::type_meta(), Arc::new(1))),
405 target: usize::type_meta(),
406 })
407 }
408 };
409
410 Ok(..=end)
411 }
412
413 #[inline(always)]
414 fn hint() -> TypeHint {
415 TypeHint::Type(RangeType::type_meta())
416 }
417}