#![allow(non_snake_case)] mod glue; use core::alloc::Layout; use core::ffi::c_void; use core::mem::MaybeUninit; use glue::Metadata; use libc; use roc_std::{RocList, RocStr}; use std::ffi::CStr; use std::os::raw::c_char; use std::time::Duration; extern "C" { #[link_name = "roc__mainForHost_1_exposed_generic"] fn roc_main(output: *mut u8); #[link_name = "roc__mainForHost_size"] fn roc_main_size() -> i64; #[link_name = "roc__mainForHost_1__Fx_caller"] fn call_Fx(flags: *const u8, closure_data: *const u8, output: *mut u8); #[allow(dead_code)] #[link_name = "roc__mainForHost_1__Fx_size"] fn size_Fx() -> i64; #[link_name = "roc__mainForHost_1__Fx_result_size"] fn size_Fx_result() -> i64; } #[no_mangle] pub unsafe extern "C" fn roc_alloc(size: usize, _alignment: u32) -> *mut c_void { libc::malloc(size) } #[no_mangle] pub unsafe extern "C" fn roc_realloc( c_ptr: *mut c_void, new_size: usize, _old_size: usize, _alignment: u32, ) -> *mut c_void { libc::realloc(c_ptr, new_size) } #[no_mangle] pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { libc::free(c_ptr) } #[no_mangle] pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { match tag_id { 0 => { let slice = CStr::from_ptr(c_ptr as *const c_char); let string = slice.to_str().unwrap(); eprintln!("Roc hit a panic: {}", string); std::process::exit(1); } _ => todo!(), } } #[no_mangle] pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void { libc::memcpy(dst, src, n) } #[no_mangle] pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void { libc::memset(dst, c, n) } #[no_mangle] pub extern "C" fn rust_main() -> i32 { let size = unsafe { roc_main_size() } as usize; let layout = Layout::array::(size).unwrap(); unsafe { // TODO allocate on the stack if it's under a certain size let buffer = std::alloc::alloc(layout); roc_main(buffer); let result = call_the_closure(buffer); std::alloc::dealloc(buffer, layout); result }; // Exit code 0 } unsafe fn call_the_closure(closure_data_ptr: *const u8) -> i64 { let size = size_Fx_result() as usize; let layout = Layout::array::(size).unwrap(); let buffer = std::alloc::alloc(layout) as *mut u8; call_Fx( // This flags pointer will never get dereferenced MaybeUninit::uninit().as_ptr(), closure_data_ptr as *const u8, buffer as *mut u8, ); std::alloc::dealloc(buffer, layout); 0 } #[no_mangle] pub extern "C" fn roc_fx_getLine() -> RocStr { use std::io::{self, BufRead}; let stdin = io::stdin(); let line1 = stdin.lock().lines().next().unwrap().unwrap(); RocStr::from(line1.as_str()) } #[no_mangle] pub extern "C" fn roc_fx_putLine(line: &RocStr) { let string = line.as_str(); println!("{}", string); } #[no_mangle] pub extern "C" fn roc_fx_sendRequest(roc_request: &glue::Request) -> glue::Response { let mut builder = reqwest::blocking::ClientBuilder::new(); if roc_request.timeout.discriminant() == glue::discriminant_TimeoutConfig::TimeoutMilliseconds { let ms: &u64 = unsafe { roc_request.timeout.as_TimeoutMilliseconds() }; builder = builder.timeout(Duration::from_millis(*ms)); } let url = roc_request.url.as_str(); match reqwest::blocking::get(url) { Ok(response) => { let bytes = response.bytes().unwrap_or_default(); let body: RocList = RocList::from_iter(bytes.into_iter()); let status = response.status(); let status_str = status.canonical_reason().unwrap_or_else(|| status.as_str()); let metadata = Metadata { headers: RocList::empty(), // TODO statusText: RocStr::from(status_str), url: RocStr::from(url), statusCode: status.as_u16(), }; glue::Response::GoodStatus(metadata, body) } Err(err) => { if err.is_timeout() { glue::Response::Timeout } else if let Some(status) = err.status() { let body = RocList::empty(); // TODO let status_str = status.canonical_reason().unwrap_or_else(|| status.as_str()); let metadata = Metadata { headers: RocList::empty(), // TODO statusText: RocStr::from(status_str), url: RocStr::from(url), statusCode: status.as_u16(), }; glue::Response::BadStatus(metadata, body) } else if err.is_request() { glue::Response::BadUrl(RocStr::from(url)) } else { glue::Response::NetworkError } } } }