1use crate::real_std::{
3 ffi::OsStr,
4 fs, io,
5 marker::PhantomData,
6 path::{self, Path},
7 result::Result as StdResult,
8 str::FromStr,
9 string::String as StdString,
10 sync::Mutex,
11};
12
13use crate::base::types::ArcType;
14
15use crate::{
16 api::{
17 generic::{self, A, S},
18 primitive, Array, Getable, Opaque, OpaqueRef, Pushable, Pushed, RuntimeResult, ValueRef,
19 VmType, WithVM, IO,
20 },
21 gc::{DataDef, Trace, WriteOnly},
22 stack::{ExternState, StackFrame},
23 types::VmInt,
24 value::{GcStr, Repr, ValueArray},
25 vm::{Status, Thread},
26 Error, ExternModule, Result, Variants,
27};
28
29#[doc(hidden)]
30pub mod array {
31 use super::*;
32 use crate::thread::ThreadInternal;
33
34 pub fn len(array: Array<generic::A>) -> VmInt {
35 array.len() as VmInt
36 }
37
38 pub(crate) fn index<'vm>(
39 array: OpaqueRef<'vm, [generic::A]>,
40 index: VmInt,
41 ) -> RuntimeResult<OpaqueRef<'vm, generic::A>, String> {
42 match array.get(index) {
43 Some(value) => RuntimeResult::Return(value),
44 None => RuntimeResult::Panic(format!("Index {} is out of range", index)),
45 }
46 }
47
48 pub(crate) fn slice<'vm>(
49 array: Array<'vm, generic::A>,
50 start: usize,
51 end: usize,
52 ) -> RuntimeResult<Array<'vm, generic::A>, Error> {
53 if start > end {
54 return RuntimeResult::Panic(Error::Message(format!(
55 "slice index starts at {} but ends at {}",
56 start, end
57 )));
58 }
59
60 if end > array.len() {
61 return RuntimeResult::Panic(Error::Message(format!(
62 "index {} is out of range for array of length {}",
63 end,
64 array.len()
65 )));
66 }
67
68 #[derive(Trace)]
69 #[gluon(gluon_vm)]
70 struct Slice<'a> {
71 start: usize,
72 end: usize,
73 array: &'a ValueArray,
74 }
75
76 unsafe impl<'a> DataDef for Slice<'a> {
77 type Value = ValueArray;
78
79 fn size(&self) -> usize {
80 ValueArray::size_of(self.array.repr(), self.end - self.start)
81 }
82
83 fn initialize<'w>(self, mut result: WriteOnly<'w, ValueArray>) -> &'w mut ValueArray {
84 unsafe {
85 let result = &mut *result.as_mut_ptr();
86 result.set_repr(self.array.repr());
87 result.initialize(
88 self.array
89 .iter()
90 .skip(self.start)
91 .take(self.end - self.start),
92 );
93 result
94 }
95 }
96 }
97
98 let mut context = array.vm().context();
99 let result = context.alloc(Slice {
100 start,
101 end,
102 array: &array.get_array(),
103 });
104
105 let value = match result {
106 Ok(value) => value,
107 Err(err) => return RuntimeResult::Panic(err),
108 };
109
110 RuntimeResult::Return(Getable::from_value(array.vm_(), Variants::from(value)))
111 }
112
113 pub(crate) fn append<'vm>(
114 lhs: Array<'vm, generic::A>,
115 rhs: Array<'vm, generic::A>,
116 ) -> RuntimeResult<Array<'vm, generic::A>, Error> {
117 #[derive(Trace)]
118 #[gluon(gluon_vm)]
119 struct Append<'b> {
120 lhs: &'b ValueArray,
121 rhs: &'b ValueArray,
122 }
123 impl<'b> Append<'b> {
124 fn repr(&self) -> Repr {
125 if self.lhs.len() == 0 {
128 self.rhs.repr()
129 } else {
130 self.lhs.repr()
131 }
132 }
133 }
134
135 unsafe impl<'b> DataDef for Append<'b> {
136 type Value = ValueArray;
137 fn size(&self) -> usize {
138 let len = self.lhs.len() + self.rhs.len();
139 ValueArray::size_of(self.repr(), len)
140 }
141 fn initialize<'w>(self, mut result: WriteOnly<'w, ValueArray>) -> &'w mut ValueArray {
142 unsafe {
143 let result = &mut *result.as_mut_ptr();
144 result.set_repr(self.repr());
145 result.initialize(self.lhs.iter().chain(self.rhs.iter()));
146 result
147 }
148 }
149 }
150 let vm = lhs.vm();
151 let mut context = vm.context();
152 let value = {
153 let result = context.alloc(Append {
154 lhs: &lhs.get_array(),
155 rhs: &rhs.get_array(),
156 });
157 match result {
158 Ok(x) => x,
159 Err(err) => return RuntimeResult::Panic(err),
160 }
161 };
162 RuntimeResult::Return(Getable::from_value(lhs.vm_(), Variants::from(value)))
163 }
164}
165
166mod int {
167 use super::*;
168 use crate::types::VmInt;
169
170 pub(crate) fn rem(dividend: VmInt, divisor: VmInt) -> RuntimeResult<VmInt, String> {
171 if divisor != 0 {
172 RuntimeResult::Return(dividend % divisor)
173 } else {
174 RuntimeResult::Panic(format!(
175 "attempted to calculate remainder of {} divided by 0",
176 dividend
177 ))
178 }
179 }
180
181 pub(crate) fn rem_euclid(dividend: VmInt, divisor: VmInt) -> RuntimeResult<VmInt, String> {
182 if divisor != 0 {
183 RuntimeResult::Return(dividend.rem_euclid(divisor))
184 } else {
185 RuntimeResult::Panic(format!(
186 "attempted to calculate euclidean remainder of {} divided by 0",
187 dividend
188 ))
189 }
190 }
191
192 pub(crate) fn wrapping_rem(dividend: VmInt, divisor: VmInt) -> RuntimeResult<VmInt, String> {
193 if divisor != 0 {
194 RuntimeResult::Return(dividend.wrapping_rem(divisor))
195 } else {
196 RuntimeResult::Panic(format!(
197 "attempted to calculate wrapping remainder of {} divided by 0",
198 dividend
199 ))
200 }
201 }
202
203 pub(crate) fn wrapping_rem_euclid(
204 dividend: VmInt,
205 divisor: VmInt,
206 ) -> RuntimeResult<VmInt, String> {
207 if divisor != 0 {
208 RuntimeResult::Return(dividend.wrapping_rem_euclid(divisor))
209 } else {
210 RuntimeResult::Panic(format!(
211 "attempted to calculate wrapping euclidean remainder of {} divided by 0",
212 dividend
213 ))
214 }
215 }
216
217 pub(crate) fn overflowing_rem(
218 dividend: VmInt,
219 divisor: VmInt,
220 ) -> RuntimeResult<(VmInt, bool), String> {
221 if divisor != 0 {
222 RuntimeResult::Return(dividend.overflowing_rem(divisor))
223 } else {
224 RuntimeResult::Panic(format!(
225 "attempted to calculate overflowing remainder of {} divided by 0",
226 dividend
227 ))
228 }
229 }
230
231 pub(crate) fn overflowing_rem_euclid(
232 dividend: VmInt,
233 divisor: VmInt,
234 ) -> RuntimeResult<(VmInt, bool), String> {
235 if divisor != 0 {
236 RuntimeResult::Return(dividend.overflowing_rem_euclid(divisor))
237 } else {
238 RuntimeResult::Panic(format!(
239 "attempted to calculate overflowing euclidean remainder of {} divided by 0",
240 dividend
241 ))
242 }
243 }
244}
245
246mod string {
247 use super::*;
248 use crate::value::ValueStr;
249
250 pub(crate) fn append(lhs: WithVM<&str>, rhs: &str) -> RuntimeResult<Pushed<String>, Error> {
251 #[derive(Trace)]
252 #[gluon(gluon_vm)]
253 struct StrAppend<'b> {
254 lhs: &'b str,
255 rhs: &'b str,
256 }
257
258 unsafe impl<'b> DataDef for StrAppend<'b> {
259 type Value = ValueStr;
260 fn size(&self) -> usize {
261 use crate::real_std::mem::size_of;
262 size_of::<ValueStr>() + (self.lhs.len() + self.rhs.len()) * size_of::<u8>()
263 }
264 fn initialize<'w>(self, mut result: WriteOnly<'w, ValueStr>) -> &'w mut ValueStr {
265 unsafe {
266 let result = &mut *result.as_mut_ptr();
267 result.as_mut_array().set_repr(Repr::Byte);
268 result.as_mut_array().unsafe_array_mut::<u8>().initialize(
269 self.lhs
270 .as_bytes()
271 .iter()
272 .chain(self.rhs.as_bytes())
273 .cloned(),
274 );
275 result
276 }
277 }
278 }
279
280 let vm = lhs.vm;
281 let lhs = lhs.value;
282
283 let mut context = vm.current_context();
284 let mut context = context.context();
285 let value = match alloc!(context, StrAppend { lhs: lhs, rhs: rhs }) {
286 Ok(x) => x,
287 Err(err) => return RuntimeResult::Panic(err),
288 };
289 context.stack.push(Variants::from(value));
290 RuntimeResult::Return(Pushed::default())
291 }
292
293 pub(crate) fn append_char(
294 lhs: WithVM<&str>,
295 rhs: char,
296 ) -> RuntimeResult<Pushed<String>, Error> {
297 append(lhs, rhs.encode_utf8(&mut [0; 4]))
298 }
299
300 pub(crate) fn from_char(c: WithVM<char>) -> RuntimeResult<Pushed<String>, Error> {
301 append_char(
302 WithVM {
303 vm: c.vm,
304 value: "",
305 },
306 c.value,
307 )
308 }
309
310 pub fn split_at(s: &str, index: usize) -> RuntimeResult<(&str, &str), String> {
311 if !s.is_char_boundary(index) {
312 let mut iter = s.chars();
314 for _ in iter.by_ref().take(256) {}
315 RuntimeResult::Panic(format!(
316 "index {} in `{}` does not lie on a character \
317 boundary",
318 index,
319 &s[..(s.len() - iter.as_str().len())]
320 ))
321 } else {
322 RuntimeResult::Return(s.split_at(index))
323 }
324 }
325
326 pub fn slice(s: &str, start: usize, end: usize) -> RuntimeResult<&str, String> {
327 if s.is_char_boundary(start) && s.is_char_boundary(end) {
328 RuntimeResult::Return(&s[start..end])
329 } else {
330 let mut iter = s.chars();
332 for _ in iter.by_ref().take(256) {}
333 RuntimeResult::Panic(format!(
334 "index {} and/or {} in `{}` does not lie on a character \
335 boundary",
336 start,
337 end,
338 &s[..(s.len() - iter.as_str().len())]
339 ))
340 }
341 }
342
343 pub fn from_utf8<'a>(array: OpaqueRef<'a, [u8]>) -> StdResult<OpaqueRef<'a, str>, ()> {
344 Ok(Opaque::from_value(Variants::from(GcStr::from_utf8(
345 array.get_array(),
346 )?)))
347 }
348
349 pub fn char_at(s: &str, index: usize) -> RuntimeResult<char, String> {
350 if s.is_char_boundary(index) {
351 if let Some(c) = s[index..].chars().next() {
352 return RuntimeResult::Return(c);
353 }
354 }
355 let mut iter = s.chars();
356 for _ in iter.by_ref().take(256) {}
357 RuntimeResult::Panic(format!(
358 "index {} in `{}` does not lie on a character boundary",
359 index,
360 &s[..(s.len() - iter.as_str().len())]
361 ))
362 }
363}
364
365fn parse<T>(s: &str) -> StdResult<T, ()>
366where
367 T: FromStr,
368{
369 s.parse().map_err(|_| ())
370}
371
372fn show_int(i: VmInt) -> String {
373 format!("{}", i)
374}
375
376fn show_float(f: f64) -> String {
377 format!("{}", f)
378}
379
380fn show_char(c: char) -> String {
381 format!("{:?}", c)
382}
383
384fn show_byte(c: u8) -> String {
385 format!("{}", c)
386}
387
388extern "C" fn error(_: &Thread) -> Status {
389 Status::Error
392}
393
394extern "C" fn discriminant_value(thread: &Thread) -> Status {
395 let mut context = thread.current_context();
396 let tag = {
397 let stack = StackFrame::<ExternState>::current(context.stack());
398 let value = stack.get_variant(0).unwrap();
399 match value.as_ref() {
400 ValueRef::Data(data) => data.tag(),
401 _ => 0,
402 }
403 };
404 tag.vm_push(&mut context).unwrap();
405 Status::Ok
406}
407
408#[allow(non_camel_case_types)]
409mod std {
410
411 macro_rules! bit_const_inner {
412 ($typ: ty, $($trait_: ident :: $name: ident,)*) => {
413 $(
414 #[allow(non_upper_case_globals)]
415 pub const $name: fn(l: $typ, r: $typ) -> $typ = ::std::ops::$trait_::$name;
416 )*
417 }
418 }
419
420 macro_rules! bit_const {
421 ($typ: ty) => {
422 bit_const_inner! {
423 $typ,
424 BitAnd::bitand,
425 BitOr::bitor,
426 BitXor::bitxor,
427 Shl::shl,
428 Shr::shr,
429 }
430 };
431 }
432
433 pub use crate::primitives as prim;
434
435 pub mod string {
436 pub type prim = str;
437 }
438 pub mod char {
439 pub type prim = char;
440 }
441 pub mod array {
442 pub use crate::primitives::array as prim;
443 }
444
445 pub mod byte {
446 pub type prim = u8;
447
448 bit_const! { u8 }
449 }
450 pub mod int {
451 use crate::types::VmInt;
452
453 pub type prim = VmInt;
454
455 bit_const! { VmInt }
456
457 #[allow(non_upper_case_globals)]
458 pub const arithmetic_shr: fn(l: VmInt, r: VmInt) -> VmInt = shr;
459 #[allow(non_upper_case_globals)]
460 pub const logical_shr: fn(l: u64, r: u64) -> u64 = ::std::ops::Shr::shr;
461 }
462 pub mod float {
463 pub type prim = f64;
464 }
465 pub mod path {
466 pub type prim = ::std::path::Path;
467 }
468 pub mod effect {
469 pub mod st {
470 pub mod string {
471 pub use crate::primitives::st_string as prim;
472 }
473 }
474 }
475}
476
477#[allow(non_camel_case_types)]
478pub fn load_float(thread: &Thread) -> Result<ExternModule> {
479 use crate::real_std::f64;
480
481 ExternModule::new(
482 thread,
483 record! {
484 digits => f64::DIGITS,
485 epsilon => f64::EPSILON,
486 infinity => f64::INFINITY,
487 mantissa_digits => f64::MANTISSA_DIGITS,
488 max_ => f64::MAX,
489 max_10_exp => f64::MAX_10_EXP,
490 max_exp => f64::MAX_EXP,
491 min_ => f64::MIN,
492 min_10_exp => f64::MIN_10_EXP,
493 min_exp => f64::MIN_EXP,
494 min_positive => f64::MIN_POSITIVE,
495 nan => f64::NAN,
496 neg_infinity => f64::NEG_INFINITY,
497 e => f64::consts::E,
498 pi => f64::consts::PI,
499 radix => f64::RADIX,
500 is_nan => primitive!(1, std::float::prim::is_nan),
501 is_infinite => primitive!(1, std::float::prim::is_infinite),
502 is_finite => primitive!(1, std::float::prim::is_finite),
503 is_normal => primitive!(1, std::float::prim::is_normal),
504 floor => primitive!(1, std::float::prim::floor),
505 ceil => primitive!(1, std::float::prim::ceil),
506 round => primitive!(1, std::float::prim::round),
507 trunc => primitive!(1, std::float::prim::trunc),
508 fract => primitive!(1, std::float::prim::fract),
509 abs => primitive!(1, std::float::prim::abs),
510 signum => primitive!(1, std::float::prim::signum),
511 is_sign_positive => primitive!(1, std::float::prim::is_sign_positive),
512 is_sign_negative => primitive!(1, std::float::prim::is_sign_negative),
513 mul_add => primitive!(3, std::float::prim::mul_add),
514 recip => primitive!(1, std::float::prim::recip),
515 rem => primitive!(2, "std::float::prim::rem", |a: f64, b: f64| a % b),
516 rem_euclid => primitive!(2, std::float::prim::rem_euclid),
517 powi => primitive!(2, std::float::prim::powi),
518 powf => primitive!(2, std::float::prim::powf),
519 sqrt => primitive!(1, std::float::prim::sqrt),
520 exp => primitive!(1, std::float::prim::exp),
521 exp2 => primitive!(1, std::float::prim::exp2),
522 ln => primitive!(1, std::float::prim::ln),
523 log2 => primitive!(1, std::float::prim::log2),
524 log10 => primitive!(1, std::float::prim::log10),
525 to_degrees => primitive!(1, std::float::prim::to_degrees),
526 to_radians => primitive!(1, std::float::prim::to_radians),
527 max => primitive!(2, std::float::prim::max),
528 min => primitive!(2, std::float::prim::min),
529 cbrt => primitive!(1, std::float::prim::cbrt),
530 hypot => primitive!(2, std::float::prim::hypot),
531 sin => primitive!(1, std::float::prim::sin),
532 cos => primitive!(1, std::float::prim::cos),
533 tan => primitive!(1, std::float::prim::tan),
534 acos => primitive!(1, std::float::prim::acos),
535 atan => primitive!(1, std::float::prim::atan),
536 atan2 => primitive!(2, std::float::prim::atan2),
537 sin_cos => primitive!(1, std::float::prim::sin_cos),
538 exp_m1 => primitive!(1, std::float::prim::exp_m1),
539 ln_1p => primitive!(1, std::float::prim::ln_1p),
540 sinh => primitive!(1, std::float::prim::sinh),
541 cosh => primitive!(1, std::float::prim::cosh),
542 tanh => primitive!(1, std::float::prim::tanh),
543 acosh => primitive!(1, std::float::prim::acosh),
544 atanh => primitive!(1, std::float::prim::atanh),
545 from_int => primitive!(1, "std.float.prim.from_int", |i: VmInt| i as f64),
546 parse => primitive!(1, "std.float.prim.parse", parse::<f64>),
547 },
548 )
549}
550
551#[allow(non_camel_case_types)]
552pub fn load_byte(vm: &Thread) -> Result<ExternModule> {
553 ExternModule::new(
554 vm,
555 record! {
556 min_value => std::byte::prim::min_value(),
557 max_value => std::byte::prim::max_value(),
558 shl => primitive!(2, std::byte::shl),
559 shr => primitive!(2, std::byte::shr),
560 bitxor => primitive!(2, std::byte::bitxor),
561 bitand => primitive!(2, std::byte::bitand),
562 bitor => primitive!(2, std::byte::bitor),
563 count_ones => primitive!(1, std::byte::prim::count_ones),
564 count_zeros => primitive!(1, std::byte::prim::count_zeros),
565 leading_zeros => primitive!(1, std::byte::prim::leading_zeros),
566 trailing_zeros => primitive!(1, std::byte::prim::trailing_zeros),
567 rotate_left => primitive!(2, std::byte::prim::rotate_left),
568 rotate_right => primitive!(2, std::byte::prim::rotate_right),
569 swap_bytes => primitive!(1, std::byte::prim::swap_bytes),
570 from_be => primitive!(1, std::byte::prim::from_be),
571 from_le => primitive!(1, std::byte::prim::from_le),
572 to_be => primitive!(1, std::byte::prim::to_be),
573 to_le => primitive!(1, std::byte::prim::to_le),
574 pow => primitive!(2, std::byte::prim::pow),
575 saturating_add => primitive!(2, std::byte::prim::saturating_add),
576 saturating_sub => primitive!(2, std::byte::prim::saturating_sub),
577 saturating_mul => primitive!(2, std::byte::prim::saturating_mul),
578 wrapping_add => primitive!(2, std::byte::prim::wrapping_add),
579 wrapping_sub => primitive!(2, std::byte::prim::wrapping_sub),
580 wrapping_mul => primitive!(2, std::byte::prim::wrapping_mul),
581 wrapping_div => primitive!(2, std::byte::prim::wrapping_div),
582 overflowing_add => primitive!(2, std::byte::prim::overflowing_add),
583 overflowing_sub => primitive!(2, std::byte::prim::overflowing_sub),
584 overflowing_mul => primitive!(2, std::byte::prim::overflowing_mul),
585 overflowing_div => primitive!(2, std::byte::prim::overflowing_div),
586 from_int => primitive!(1, "std.byte.prim.from_int", |i: VmInt| i as u8),
587 parse => primitive!(1, "std.byte.prim.parse", parse::<u8>),
588 },
589 )
590}
591
592#[allow(non_camel_case_types)]
593pub fn load_int(vm: &Thread) -> Result<ExternModule> {
594 ExternModule::new(
595 vm,
596 record! {
597 min_value => std::int::prim::min_value(),
598 max_value => std::int::prim::max_value(),
599 from_str_radix => primitive!(
600 2,
601 "std.int.prim.from_str_radix",
602 |src, radix| std::int::prim::from_str_radix(src, radix).map_err(|_| ())
603 ),
604 shl => primitive!(2, std::int::shl),
605 arithmetic_shr => primitive!(2, std::int::arithmetic_shr),
606 logical_shr => primitive!(2, std::int::logical_shr),
607 bitxor => primitive!(2, std::int::bitxor),
608 bitand => primitive!(2, std::int::bitand),
609 bitor => primitive!(2, std::int::bitor),
610 count_ones => primitive!(1, std::int::prim::count_ones),
611 count_zeros => primitive!(1, std::int::prim::count_zeros),
612 leading_zeros => primitive!(1, std::int::prim::leading_zeros),
613 trailing_zeros => primitive!(1, std::int::prim::trailing_zeros),
614 rotate_left => primitive!(2, std::int::prim::rotate_left),
615 rotate_right => primitive!(2, std::int::prim::rotate_right),
616 swap_bytes => primitive!(1, std::int::prim::swap_bytes),
617 from_be => primitive!(1, std::int::prim::from_be),
618 from_le => primitive!(1, std::int::prim::from_le),
619 to_be => primitive!(1, std::int::prim::to_be),
620 to_le => primitive!(1, std::int::prim::to_le),
621 pow => primitive!(2, std::int::prim::pow),
622 abs => primitive!(1, std::int::prim::abs),
623 rem => primitive!(2, "std::int::prim::rem", int::rem),
624 rem_euclid => primitive!(2, "std::int::prim::rem_euclid", int::rem_euclid),
625 checked_rem => primitive!(2, std::int::prim::checked_rem),
626 checked_rem_euclid => primitive!(2, std::int::prim::checked_rem_euclid),
627 saturating_add => primitive!(2, std::int::prim::saturating_add),
628 saturating_sub => primitive!(2, std::int::prim::saturating_sub),
629 saturating_mul => primitive!(2, std::int::prim::saturating_mul),
630 wrapping_add => primitive!(2, std::int::prim::wrapping_add),
631 wrapping_sub => primitive!(2, std::int::prim::wrapping_sub),
632 wrapping_mul => primitive!(2, std::int::prim::wrapping_mul),
633 wrapping_div => primitive!(2, std::int::prim::wrapping_div),
634 wrapping_abs => primitive!(1, std::int::prim::wrapping_abs),
635 wrapping_rem => primitive!(2, "std::int::prim::wrapping_rem", int::wrapping_rem),
636 wrapping_rem_euclid => primitive!(2, "std::int::prim::wrapping_rem", int::wrapping_rem_euclid),
637 wrapping_negate => primitive!(1, "std.int.prim.wrapping_negate", std::int::prim::wrapping_neg),
638 overflowing_add => primitive!(2, std::int::prim::overflowing_add),
639 overflowing_sub => primitive!(2, std::int::prim::overflowing_sub),
640 overflowing_mul => primitive!(2, std::int::prim::overflowing_mul),
641 overflowing_div => primitive!(2, std::int::prim::overflowing_div),
642 overflowing_abs => primitive!(1, std::int::prim::overflowing_abs),
643 overflowing_rem => primitive!(2, "std::int::prim::overflowing_rem", int::overflowing_rem),
644 overflowing_rem_euclid => primitive!(2, "std::int::prim::overflowing_rem_euclid", int::overflowing_rem_euclid),
645 overflowing_negate => primitive!(1, "std.int.prim.overflowing_negate", std::int::prim::overflowing_neg),
646 signum => primitive!(1, std::int::prim::signum),
647 is_positive => primitive!(1, std::int::prim::is_positive),
648 is_negative => primitive!(1, std::int::prim::is_negative),
649 from_byte => primitive!(1, "std.int.prim.from_byte", |b: u8| b as VmInt),
650 from_float => primitive!(1, "std.int.prim.from_float", |f: f64| f as VmInt),
651 parse => primitive!(1, "std.int.prim.parse", parse::<VmInt>)
652 },
653 )
654}
655
656#[allow(non_camel_case_types)]
657pub fn load_array(vm: &Thread) -> Result<ExternModule> {
658 ExternModule::new(
659 vm,
660 record! {
661 type Array a => Array<A>,
662 len => primitive!(1, std::array::prim::len),
663 index => primitive!(2, std::array::prim::index),
664 append => primitive!(2, std::array::prim::append),
665 slice => primitive!(3, std::array::prim::slice)
666 },
667 )
668}
669
670pub fn load_string(vm: &Thread) -> Result<ExternModule> {
671 ExternModule::new(
672 vm,
673 record! {
674 len => primitive!(1, std::string::prim::len),
675 is_empty => primitive!(1, std::string::prim::is_empty),
676 is_char_boundary => primitive!(2, std::string::prim::is_char_boundary),
677 as_bytes => primitive!(1, std::string::prim::as_bytes),
678 split_at => primitive!(2, "std.string.prim.split_at", string::split_at),
679 contains => primitive!(2, std::string::prim::contains::<&str>),
680 starts_with => primitive!(2, std::string::prim::starts_with::<&str>),
681 ends_with => primitive!(2, std::string::prim::ends_with::<&str>),
682 find => primitive!(2, std::string::prim::find::<&str>),
683 rfind => primitive!(2, std::string::prim::rfind::<&str>),
684 trim => primitive!(1, std::string::prim::trim),
685 trim_start => primitive!(1, std::string::prim::trim_start),
686 trim_start_matches => primitive!(2, std::string::prim::trim_start_matches::<&str>),
687 trim_end => primitive!(1, std::string::prim::trim_end),
688 trim_end_matches => primitive!(2, std::string::prim::trim_end_matches::<&str>),
689 append => primitive!(2, "std.string.prim.append", string::append),
690 append_char => primitive!(2, "std.string.prim.append_char", string::append_char),
691 from_char => primitive!(1, "std.string.prim.from_char", string::from_char),
692 slice => primitive!(3, "std.string.prim.slice", string::slice),
693 from_utf8 => primitive!(
694 1,
695 "std.string.prim.from_utf8",
696 string::from_utf8
697 ),
698 char_at => primitive!(2, "std.string.prim.char_at", string::char_at)
699 },
700 )
701}
702
703impl<'a> VmType for path::Component<'a> {
704 type Type = Component<'static>;
705 fn make_type(vm: &Thread) -> ArcType {
706 Component::make_type(vm)
707 }
708}
709
710#[derive(Pushable, VmType)]
711#[gluon(vm_type = "std.path.types.Component")]
712#[gluon(gluon_vm)]
713pub enum Component<'a> {
714 Prefix,
715 RootDir,
716 CurDir,
717 ParentDir,
718 Normal(&'a OsStr),
719}
720
721#[derive(Userdata, Debug, VmType)]
722#[gluon(vm_type = "std.fs.Metadata")]
723#[gluon(gluon_vm)]
724pub struct Metadata(fs::Metadata);
725
726unsafe impl Trace for Metadata {
727 impl_trace! { self, _gc, { } }
728}
729
730#[derive(Userdata, Debug, VmType)]
731#[gluon(vm_type = "std.fs.DirEntry")]
732#[gluon(gluon_vm)]
733pub struct DirEntry(fs::DirEntry);
734
735unsafe impl Trace for DirEntry {
736 impl_trace! { self, _gc, { } }
737}
738
739pub fn load_fs(vm: &Thread) -> Result<ExternModule> {
740 vm.register_type::<Metadata>("std.fs.Metadata", &[])?;
741 vm.register_type::<DirEntry>("std.fs.DirEntry", &[])?;
742
743 ExternModule::new(
744 vm,
745 record! {
746 type Metadata => Metadata,
747 type DirEntry => DirEntry,
748
749 read_dir => primitive!(1, "std.fs.prim.read_dir", |p: &Path| {
750 IO::from(fs::read_dir(p).and_then(|iter| iter.map(|result| result.map(DirEntry)).collect::<io::Result<Vec<_>>>()))
751 }),
752
753 dir_entry => record! {
754 path => primitive!(1, "std.fs.prim.dir_entry.path", |m: &DirEntry| m.0.path()),
755 metadata => primitive!(1, "std.fs.prim.dir_entry.metadata", |m: &DirEntry| IO::from(m.0.metadata().map(Metadata))),
756 file_name => primitive!(1, "std.fs.prim.dir_entry.file_name", |m: &DirEntry| m.0.file_name()),
757 },
758
759 metadata => record! {
760 is_dir => primitive!(1, "std.fs.prim.metadata.is_dir", |m: &Metadata| m.0.is_dir()),
761 is_file => primitive!(1, "std.fs.prim.metadata.is_file", |m: &Metadata| m.0.is_file()),
762 len => primitive!(1, "std.fs.prim.metadata.len", |m: &Metadata| m.0.len()),
763 },
764 },
765 )
766}
767
768pub fn load_path(vm: &Thread) -> Result<ExternModule> {
769 ExternModule::new(
770 vm,
771 record! {
772 is_absolute => primitive!(1, std::path::prim::is_absolute),
773 is_relative => primitive!(1, std::path::prim::is_relative),
774 has_root => primitive!(1, std::path::prim::has_root),
775 parent => primitive!(1, std::path::prim::parent),
776 ancestors => primitive!(1, "std.path.prim.ancestors", |p: &Path| p.ancestors().collect::<Vec<_>>()),
777 file_name => primitive!(1, std::path::prim::file_name),
778 strip_prefix => primitive!(2, "std.path.prim.strip_prefix", |p: &Path, b: &Path| p.strip_prefix(b).ok()),
779 starts_with => primitive!(2, "std.path.prim.starts_with", |p: &Path, b: &Path| p.starts_with(b)),
780 ends_with => primitive!(2, "std.path.prim.ends_with", |p: &Path, b: &Path| p.ends_with(b)),
781 file_stem => primitive!(1, std::path::prim::file_stem),
782 extension => primitive!(1, std::path::prim::extension),
783 join => primitive!(2, "std.path.prim.join", std::path::prim::join::<&Path>),
784 with_file_name => primitive!(2, std::path::prim::with_file_name::<&Path>),
785 with_extension => primitive!(2, std::path::prim::with_extension::<&Path>),
786 components => primitive!(1, "std.path.prim.components", |p: &Path| {
787 p.components()
788 .map(|c| match c {
789 path::Component::Prefix(..) => Component::Prefix,
790 path::Component::RootDir => Component::RootDir,
791 path::Component::CurDir => Component::CurDir,
792 path::Component::ParentDir => Component::ParentDir,
793 path::Component::Normal(p) => Component::Normal(p),
794 })
795 .collect::<Vec<_>>()
796 }),
797 metadata => primitive!(1, "std.path.prim.metadata", |p: &Path| IO::from(p.metadata().map(Metadata))),
798 symlink_metadata => primitive!(1, "std.path.prim.symlink_metadata", |p: &Path| IO::from(p.symlink_metadata().map(Metadata))),
799 canonicalize => primitive!(1, "std.path.prim.canonicalize", |p: &Path| IO::from(p.canonicalize())),
800 read_link => primitive!(1, "std.path.prim.read_link", |p: &Path| IO::from(p.read_link())),
801 read_dir => primitive!(
802 1,
803 "std.path.prim.read_dir",
804 |p: &Path| IO::from(
805 p.read_dir()
806 .and_then(|iter| iter.map(|result| Ok(result?.path())).collect::<StdResult<Vec<_>, _>>())
807 .map_err(|err| Error::Message(err.to_string()))
808 )
809 ),
810 exists => primitive!(1, "std.path.prim.exists", |p: &Path| IO::Value(p.exists())),
811 is_file => primitive!(1, "std.path.prim.is_file", |p: &Path| IO::Value(p.is_file())),
812 is_dir => primitive!(1, "std.path.prim.is_file", |p: &Path| IO::Value(p.is_dir())),
813 },
814 )
815}
816
817#[allow(non_camel_case_types)]
818pub fn load_char(vm: &Thread) -> Result<ExternModule> {
819 ExternModule::new(
820 vm,
821 record! {
822 from_int => primitive!(1, "std.char.prim.from_int", ::std::char::from_u32),
823 to_int => primitive!(1, "std.char.prim.to_int", |c: char| c as u32),
824 is_digit => primitive!(2, std::char::prim::is_digit),
825 to_digit => primitive!(2, std::char::prim::to_digit),
826 len_utf8 => primitive!(1, std::char::prim::len_utf8),
827 len_utf16 => primitive!(1, std::char::prim::len_utf16),
828 is_alphabetic => primitive!(1, std::char::prim::is_alphabetic),
829 is_lowercase => primitive!(1, std::char::prim::is_lowercase),
830 is_uppercase => primitive!(1, std::char::prim::is_uppercase),
831 is_whitespace => primitive!(1, std::char::prim::is_whitespace),
832 is_alphanumeric => primitive!(1, std::char::prim::is_alphanumeric),
833 is_control => primitive!(1, std::char::prim::is_control),
834 is_numeric => primitive!(1, std::char::prim::is_numeric),
835 },
836 )
837}
838
839pub mod st_string {
840 use super::*;
841
842 pub(crate) fn len(buf: &StringBuf<S>) -> usize {
843 buf.0.lock().unwrap().len()
844 }
845
846 pub(crate) fn slice(
847 buf: &StringBuf<S>,
848 start: usize,
849 end: usize,
850 ) -> RuntimeResult<String, String> {
851 string::slice(&buf.0.lock().unwrap(), start, end).map(|s| s.to_string())
852 }
853
854 pub(crate) fn pop(buf: &StringBuf<S>) -> Option<char> {
855 buf.0.lock().unwrap().pop()
856 }
857
858 pub(crate) fn push_str(buf: &StringBuf<S>, s: &str) {
859 buf.0.lock().unwrap().push_str(s)
860 }
861}
862
863#[derive(Debug, Default, VmType, Userdata, Trace)]
864#[gluon(vm_type = "std.effect.st.string.StringBuf")]
865#[gluon(gluon_vm)]
866pub(crate) struct StringBuf<S>(Mutex<String>, PhantomData<S>);
867
868pub fn load_string_buf(vm: &Thread) -> Result<ExternModule> {
869 vm.register_type::<StringBuf<S>>("std.effect.st.string.StringBuf", &["s"])?;
870
871 ExternModule::new(
872 vm,
873 record! {
874 type StringBuf s => StringBuf<S>,
875 len => primitive!(1, std::effect::st::string::prim::len),
876 new => primitive!(1, "std.effect.st.string.new", |()| StringBuf(Default::default(), PhantomData::<S>)),
877 slice => primitive!(3, std::effect::st::string::prim::slice),
878 pop => primitive!(1, std::effect::st::string::prim::pop),
879 push_str => primitive!(2, std::effect::st::string::prim::push_str)
880 },
881 )
882}
883
884#[allow(non_camel_case_types, deprecated)]
885pub fn load<'vm>(vm: &'vm Thread) -> Result<ExternModule> {
886 ExternModule::new(
887 vm,
888 record! {
889 show_int => primitive!(1, std::prim::show_int),
890 show_float => primitive!(1, std::prim::show_float),
891 show_byte => primitive!(1, std::prim::show_byte),
892 show_char => primitive!(1, std::prim::show_char),
893 string_compare => primitive!(2, "std.prim.string_compare", str::cmp),
894 string_eq => primitive!(2, "std.prim.string_eq", <str as PartialEq>::eq),
895 error => primitive::<fn(StdString) -> Pushed<A>>("std.prim.error", std::prim::error),
896 discriminant_value => primitive::<fn(OpaqueRef<'vm, A>) -> VmInt>(
897 "std.prim.discriminant_value",
898 std::prim::discriminant_value
899 ),
900 },
901 )
902}