#![allow(unused_variables)]
use crate::diagnostics::{Error as DiagnosticError, Result};
use crate::eval::value::{
Value, PrimitiveProcedure, PrimitiveImpl, ThreadSafeEnvironment
};
use crate::effects::Effect;
use std::sync::Arc;
use std::collections::HashMap;
#[cfg(target_os = "linux")]
use nix::sys::epoll::{Epoll, EpollCreateFlags, EpollEvent, EpollFlags, EpollTimeout};
#[cfg(target_os = "linux")]
use nix::unistd::{pipe, read, write};
#[cfg(target_os = "linux")]
use nix::fcntl::{fcntl, FcntlArg, OFlag};
#[cfg(all(target_os = "macos", feature = "advanced-io"))]
use nix::sys::event::{KEvent, EventFilter, FilterFlag, EventFlag, Kqueue};
#[cfg(windows)]
use winapi::um::ioapiset::{CreateIoCompletionPort, GetQueuedCompletionStatus};
#[cfg(windows)]
use winapi::um::winnt::{HANDLE, INVALID_HANDLE_VALUE};
#[cfg(windows)]
use winapi::um::minwinbase::OVERLAPPED;
use mio::{Events, Poll, Token, Waker};
use std::time::Duration;
#[derive(Debug)]
pub enum PlatformHandle {
#[cfg(target_os = "linux")]
Epoll {
epoll_fd: i32,
events: Vec<EpollEvent>,
},
#[cfg(all(target_os = "macos", feature = "advanced-io"))]
Kqueue {
kq_fd: Kqueue,
events: Vec<KEvent>,
},
#[cfg(windows)]
Iocp {
handle: HANDLE,
overlapped: Vec<OVERLAPPED>,
},
Mio {
poll: Poll,
events: Events,
waker: Arc<Waker>,
},
}
#[derive(Debug, Clone, Copy)]
pub enum IoOperation {
Read,
Write,
Accept,
Connect,
Send,
Receive,
}
#[derive(Debug)]
pub struct IoCompletion {
pub operation: IoOperation,
pub bytes_transferred: usize,
pub result: std::io::Result<()>,
pub user_data: u64,
}
unsafe impl Send for HighPerformanceIo {}
unsafe impl Sync for HighPerformanceIo {}
#[derive(Debug)]
pub struct HighPerformanceIo {
pub handle: PlatformHandle,
pub pending_operations: HashMap<u64, IoOperation>,
pub next_operation_id: u64,
}
impl HighPerformanceIo {
pub fn new() -> std::io::Result<Self> {
let handle = Self::create_platform_handle()?;
Ok(HighPerformanceIo {
handle,
pending_operations: HashMap::new(),
next_operation_id: 1,
})
}
#[cfg(target_os = "linux")]
fn create_platform_handle() -> std::io::Result<PlatformHandle> {
match Epoll::new(EpollCreateFlags::empty()) {
Ok(epoll) => Ok(PlatformHandle::Epoll {
epoll_fd: epoll.as_raw_fd(),
events: Vec::with_capacity(32),
}),
Err(e) => {
eprintln!("Failed to create epoll, falling back to mio: {}", e);
Self::create_mio_handle()
}
}
}
#[cfg(all(target_os = "macos", feature = "advanced-io"))]
fn create_platform_handle() -> std::io::Result<PlatformHandle> {
match Kqueue::new() {
Ok(kq) => Ok(PlatformHandle::Kqueue {
kq_fd: kq,
events: Vec::with_capacity(32),
}),
Err(e) => {
eprintln!("Failed to create kqueue, falling back to mio: {e}");
Self::create_mio_handle()
}
}
}
#[cfg(all(target_os = "macos", not(feature = "advanced-io")))]
fn create_platform_handle() -> std::io::Result<PlatformHandle> {
Self::create_mio_handle()
}
#[cfg(windows)]
fn create_platform_handle() -> std::io::Result<PlatformHandle> {
unsafe {
let handle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, std::ptr::null_mut(), 0, 0);
if handle.is_null() {
eprintln!("Failed to create IOCP, falling back to mio");
Self::create_mio_handle()
} else {
Ok(PlatformHandle::Iocp {
handle,
overlapped: Vec::new(),
})
}
}
}
#[cfg(not(any(target_os = "linux", target_os = "macos", windows)))]
fn create_platform_handle() -> std::io::Result<PlatformHandle> {
Self::create_mio_handle()
}
fn create_mio_handle() -> std::io::Result<PlatformHandle> {
let poll = Poll::new()?;
let events = Events::with_capacity(32);
let waker = Arc::new(Waker::new(poll.registry(), Token(0))?);
Ok(PlatformHandle::Mio {
poll,
events,
waker,
})
}
pub fn submit_operation(&mut self, operation: IoOperation, user_data: Option<u64>) -> u64 {
let op_id = user_data.unwrap_or_else(|| {
let id = self.next_operation_id;
self.next_operation_id += 1;
id
});
self.pending_operations.insert(op_id, operation);
op_id
}
pub fn poll_completions(&mut self, timeout: Option<Duration>) -> std::io::Result<Vec<IoCompletion>> {
match &mut self.handle {
#[cfg(target_os = "linux")]
PlatformHandle::Epoll { epoll_fd, events } => {
let fd = *epoll_fd;
Self::poll_epoll_static(fd, events, timeout, &mut self.pending_operations)
}
#[cfg(all(target_os = "macos", feature = "advanced-io"))]
PlatformHandle::Kqueue { kq_fd, events } => {
Self::poll_kqueue_static(kq_fd, events, timeout, &mut self.pending_operations)
}
#[cfg(windows)]
PlatformHandle::Iocp { handle, .. } => {
let h = *handle;
Self::poll_iocp_static(h, timeout, &mut self.pending_operations)
}
PlatformHandle::Mio { poll, events, .. } => {
Self::poll_mio_static(poll, events, timeout, &mut self.pending_operations)
}
}
}
#[cfg(target_os = "linux")]
fn poll_epoll_static(epoll_fd: i32, events: &mut Vec<EpollEvent>, timeout: Option<Duration>, pending_operations: &mut HashMap<u64, IoOperation>) -> std::io::Result<Vec<IoCompletion>> {
events.clear();
events.resize(32, EpollEvent::empty());
let timeout_ms = timeout.map(|d| d.as_millis() as i32).unwrap_or(-1);
match nix::sys::epoll::epoll_wait(epoll_fd, events, timeout_ms) {
Ok(num_events) => {
let mut completions = Vec::new();
for i in 0..num_events {
let event = &events[i];
let user_data = event.data();
if let Some(operation) = pending_operations.remove(&user_data) {
completions.push(IoCompletion {
operation,
bytes_transferred: 0, result: Ok(()),
user_data,
});
}
}
Ok(completions)
}
Err(e) => Err(std::io::Error::from(e)),
}
}
#[cfg(all(target_os = "macos", feature = "advanced-io"))]
fn poll_kqueue_static(kq_fd: &Kqueue, events: &mut Vec<KEvent>, timeout: Option<Duration>, pending_operations: &mut HashMap<u64, IoOperation>) -> std::io::Result<Vec<IoCompletion>> {
events.clear();
events.resize(32, KEvent::new(0, EventFilter::EVFILT_READ, EventFlag::empty(), FilterFlag::empty(), 0, 0));
let timeout_spec = timeout.map(|d| {
libc::timespec {
tv_sec: d.as_secs() as libc::time_t,
tv_nsec: d.subsec_nanos() as libc::c_long,
}
});
match kq_fd.kevent(&[], events, timeout_spec) {
Ok(num_events) => {
let mut completions = Vec::new();
for event in &events[0..num_events] {
let user_data = event.udata() as u64;
if let Some(operation) = pending_operations.remove(&user_data) {
completions.push(IoCompletion {
operation,
bytes_transferred: event.data() as usize,
result: Ok(()),
user_data,
});
}
}
Ok(completions)
}
Err(e) => Err(std::io::Error::from(e)),
}
}
#[cfg(windows)]
fn poll_iocp_static(handle: HANDLE, timeout: Option<Duration>, pending_operations: &mut HashMap<u64, IoOperation>) -> std::io::Result<Vec<IoCompletion>> {
use std::ptr;
use winapi::shared::minwindef::{DWORD, ULONG_PTR};
let timeout_ms = timeout.map(|d| d.as_millis() as DWORD).unwrap_or(winapi::um::winbase::INFINITE);
let mut bytes_transferred: DWORD = 0;
let mut completion_key: ULONG_PTR = 0;
let mut overlapped: *mut OVERLAPPED = ptr::null_mut();
unsafe {
let result = GetQueuedCompletionStatus(
handle,
&mut bytes_transferred,
&mut completion_key,
&mut overlapped,
timeout_ms,
);
if result != 0 {
let user_data = completion_key as u64;
if let Some(operation) = pending_operations.remove(&user_data) {
Ok(vec![IoCompletion {
operation,
bytes_transferred: bytes_transferred as usize,
result: Ok(()),
user_data,
}])
} else {
Ok(vec![])
}
} else {
let error = std::io::Error::last_os_error();
if error.kind() == std::io::ErrorKind::TimedOut {
Ok(vec![])
} else {
Err(error)
}
}
}
}
fn poll_mio_static(poll: &mut Poll, events: &mut Events, timeout: Option<Duration>, pending_operations: &mut HashMap<u64, IoOperation>) -> std::io::Result<Vec<IoCompletion>> {
events.clear();
poll.poll(events, timeout)?;
let mut completions = Vec::new();
for event in events.iter() {
let token = event.token().0 as u64;
if let Some(operation) = pending_operations.remove(&token) {
completions.push(IoCompletion {
operation,
bytes_transferred: 0, result: Ok(()),
user_data: token,
});
}
}
Ok(completions)
}
}
pub fn create_platform_io_bindings(env: &Arc<ThreadSafeEnvironment>) {
bind_high_performance_operations(env);
bind_platform_detection(env);
bind_platform_fs_features(env);
bind_event_systems(env);
}
fn bind_high_performance_operations(env: &Arc<ThreadSafeEnvironment>) {
env.define("create-high-performance-io".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "create-high-performance-io".to_string(),
arity_min: 0,
arity_max: Some(1),
implementation: PrimitiveImpl::RustFn(primitive_create_high_performance_io),
effects: vec![Effect::IO],
})));
env.define("submit-io-operation".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "submit-io-operation".to_string(),
arity_min: 2,
arity_max: Some(4),
implementation: PrimitiveImpl::RustFn(primitive_submit_io_operation),
effects: vec![Effect::IO],
})));
env.define("poll-io-completions".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "poll-io-completions".to_string(),
arity_min: 1,
arity_max: Some(2),
implementation: PrimitiveImpl::RustFn(primitive_poll_io_completions),
effects: vec![Effect::IO],
})));
env.define("batch-io-operations".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "batch-io-operations".to_string(),
arity_min: 2,
arity_max: Some(3),
implementation: PrimitiveImpl::RustFn(primitive_batch_io_operations),
effects: vec![Effect::IO],
})));
}
fn bind_platform_detection(env: &Arc<ThreadSafeEnvironment>) {
env.define("platform-name".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "platform-name".to_string(),
arity_min: 0,
arity_max: Some(0),
implementation: PrimitiveImpl::RustFn(primitive_platform_name),
effects: vec![Effect::Pure],
})));
env.define("platform-capabilities".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "platform-capabilities".to_string(),
arity_min: 0,
arity_max: Some(0),
implementation: PrimitiveImpl::RustFn(primitive_platform_capabilities),
effects: vec![Effect::Pure],
})));
env.define("io-backend-available?".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "io-backend-available?".to_string(),
arity_min: 1,
arity_max: Some(1),
implementation: PrimitiveImpl::RustFn(primitive_io_backend_available_p),
effects: vec![Effect::Pure],
})));
}
fn bind_platform_fs_features(env: &Arc<ThreadSafeEnvironment>) {
env.define("platform-file-attributes".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "platform-file-attributes".to_string(),
arity_min: 1,
arity_max: Some(1),
implementation: PrimitiveImpl::RustFn(primitive_platform_file_attributes),
effects: vec![Effect::IO],
})));
env.define("set-platform-file-attributes".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "set-platform-file-attributes".to_string(),
arity_min: 2,
arity_max: Some(2),
implementation: PrimitiveImpl::RustFn(primitive_set_platform_file_attributes),
effects: vec![Effect::IO],
})));
env.define("file-system-info".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "file-system-info".to_string(),
arity_min: 1,
arity_max: Some(1),
implementation: PrimitiveImpl::RustFn(primitive_file_system_info),
effects: vec![Effect::IO],
})));
}
fn bind_event_systems(env: &Arc<ThreadSafeEnvironment>) {
env.define("create-event-watcher".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "create-event-watcher".to_string(),
arity_min: 0,
arity_max: Some(1),
implementation: PrimitiveImpl::RustFn(primitive_create_event_watcher),
effects: vec![Effect::IO],
})));
env.define("watch-file-events".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "watch-file-events".to_string(),
arity_min: 2,
arity_max: Some(3),
implementation: PrimitiveImpl::RustFn(primitive_watch_file_events),
effects: vec![Effect::IO],
})));
env.define("poll-events".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "poll-events".to_string(),
arity_min: 1,
arity_max: Some(2),
implementation: PrimitiveImpl::RustFn(primitive_poll_events),
effects: vec![Effect::IO],
})));
}
pub fn primitive_create_high_performance_io(args: &[Value]) -> Result<Value> {
if args.len() > 1 {
return Err(Box::new(DiagnosticError::runtime_error(
format!("create-high-performance-io expects 0 or 1 arguments, got {}", args.len()),
None,
)));
}
let backend = if args.len() == 1 {
extract_string(&args[0], "create-high-performance-io")?
} else {
"auto".to_string()
};
match HighPerformanceIo::new() {
Ok(hp_io) => Ok(Value::opaque(Box::new(hp_io))),
Err(e) => Err(Box::new(DiagnosticError::runtime_error(
format!("Cannot create high-performance I/O: {e}"),
None,
))),
}
}
pub fn primitive_submit_io_operation(args: &[Value]) -> Result<Value> {
if args.len() < 2 || args.len() > 4 {
return Err(Box::new(DiagnosticError::runtime_error(
format!("submit-io-operation expects 2 to 4 arguments, got {}", args.len()),
None,
)));
}
let operation_str = extract_string(&args[1], "submit-io-operation")?;
let operation = match operation_str.as_str() {
"read" => IoOperation::Read,
"write" => IoOperation::Write,
"accept" => IoOperation::Accept,
"connect" => IoOperation::Connect,
"send" => IoOperation::Send,
"receive" => IoOperation::Receive,
_ => {
return Err(Box::new(DiagnosticError::runtime_error(
format!("Unknown I/O operation: {operation_str}"),
None,
)));
}
};
let user_data = if args.len() > 2 {
Some(extract_integer(&args[2], "submit-io-operation")? as u64)
} else {
None
};
match &args[0] {
Value::Opaque(opaque_data) => {
if let Some(hp_io) = opaque_data.downcast_ref::<HighPerformanceIo>() {
Ok(Value::integer(1)) } else {
Err(Box::new(DiagnosticError::runtime_error(
"submit-io-operation requires high-performance I/O handle".to_string(),
None,
)))
}
}
_ => Err(Box::new(DiagnosticError::runtime_error(
"submit-io-operation requires high-performance I/O handle".to_string(),
None,
))),
}
}
pub fn primitive_poll_io_completions(args: &[Value]) -> Result<Value> {
if args.is_empty() || args.len() > 2 {
return Err(Box::new(DiagnosticError::runtime_error(
format!("poll-io-completions expects 1 or 2 arguments, got {}", args.len()),
None,
)));
}
let timeout_ms = if args.len() > 1 {
Some(extract_integer(&args[1], "poll-io-completions")? as u64)
} else {
None
};
match &args[0] {
Value::Opaque(opaque_data) => {
if let Some(_hp_io) = opaque_data.downcast_ref::<HighPerformanceIo>() {
Ok(Value::Nil) } else {
Err(Box::new(DiagnosticError::runtime_error(
"poll-io-completions requires high-performance I/O handle".to_string(),
None,
)))
}
}
_ => Err(Box::new(DiagnosticError::runtime_error(
"poll-io-completions requires high-performance I/O handle".to_string(),
None,
))),
}
}
pub fn primitive_batch_io_operations(_args: &[Value]) -> Result<Value> {
Err(Box::new(DiagnosticError::runtime_error(
"batch-io-operations not yet implemented".to_string(),
None,
)))
}
pub fn primitive_platform_name(_args: &[Value]) -> Result<Value> {
let platform = if cfg!(target_os = "linux") {
"linux"
} else if cfg!(target_os = "macos") {
"macos"
} else if cfg!(target_os = "windows") {
"windows"
} else if cfg!(target_os = "freebsd") {
"freebsd"
} else if cfg!(target_os = "openbsd") {
"openbsd"
} else if cfg!(target_os = "netbsd") {
"netbsd"
} else {
"unknown"
};
Ok(Value::string(platform.to_string()))
}
pub fn primitive_platform_capabilities(_args: &[Value]) -> Result<Value> {
#[allow(clippy::mutable_key_type)]
let mut capabilities = HashMap::new();
capabilities.insert(
Value::Symbol(crate::utils::intern_symbol("io-backends")),
{
let mut backends = Vec::new();
backends.push(Value::string("mio".to_string()));
#[cfg(target_os = "linux")]
{
backends.push(Value::string("epoll".to_string()));
backends.push(Value::string("io_uring".to_string()));
}
#[cfg(target_os = "macos")]
{
backends.push(Value::string("kqueue".to_string()));
}
#[cfg(windows)]
{
backends.push(Value::string("iocp".to_string()));
}
list_to_value(backends)
}
);
capabilities.insert(
Value::Symbol(crate::utils::intern_symbol("async-support")),
Value::boolean(cfg!(feature = "async"))
);
capabilities.insert(
Value::Symbol(crate::utils::intern_symbol("compression-support")),
Value::boolean(cfg!(feature = "compression"))
);
capabilities.insert(
Value::Symbol(crate::utils::intern_symbol("tls-support")),
Value::boolean(cfg!(feature = "tls"))
);
capabilities.insert(
Value::Symbol(crate::utils::intern_symbol("unix-sockets")),
Value::boolean(cfg!(unix))
);
capabilities.insert(
Value::Symbol(crate::utils::intern_symbol("memory-mapping")),
Value::boolean(true) );
Ok(Value::Hashtable(Arc::new(std::sync::RwLock::new(capabilities))))
}
pub fn primitive_io_backend_available_p(args: &[Value]) -> Result<Value> {
if args.len() != 1 {
return Err(Box::new(DiagnosticError::runtime_error(
format!("io-backend-available? expects 1 argument, got {}", args.len()),
None,
)));
}
let backend = extract_string(&args[0], "io-backend-available?")?;
let available = match backend.as_str() {
"mio" => true,
"epoll" => cfg!(target_os = "linux"),
"io_uring" => cfg!(target_os = "linux"), "kqueue" => cfg!(target_os = "macos"),
"iocp" => cfg!(windows),
_ => false,
};
Ok(Value::boolean(available))
}
pub fn primitive_platform_file_attributes(args: &[Value]) -> Result<Value> {
if args.len() != 1 {
return Err(Box::new(DiagnosticError::runtime_error(
format!("platform-file-attributes expects 1 argument, got {}", args.len()),
None,
)));
}
let path = extract_string(&args[0], "platform-file-attributes")?;
match std::fs::metadata(&path) {
Ok(metadata) => {
#[allow(clippy::mutable_key_type)]
let mut attributes = HashMap::new();
#[cfg(unix)]
{
use std::os::unix::fs::MetadataExt;
#[cfg(target_os = "macos")]
attributes.insert(
Value::Symbol(crate::utils::intern_symbol("unix-mode")),
Value::integer(metadata.mode() as i64)
);
attributes.insert(
Value::Symbol(crate::utils::intern_symbol("unix-uid")),
Value::integer(metadata.uid() as i64)
);
attributes.insert(
Value::Symbol(crate::utils::intern_symbol("unix-gid")),
Value::integer(metadata.gid() as i64)
);
attributes.insert(
Value::Symbol(crate::utils::intern_symbol("unix-inode")),
Value::integer(metadata.ino() as i64)
);
attributes.insert(
Value::Symbol(crate::utils::intern_symbol("unix-device")),
Value::integer(metadata.dev() as i64)
);
attributes.insert(
Value::Symbol(crate::utils::intern_symbol("unix-nlink")),
Value::integer(metadata.nlink() as i64)
);
}
#[cfg(windows)]
{
use std::os::windows::fs::MetadataExt;
attributes.insert(
Value::Symbol(crate::utils::intern_symbol("windows-attributes")),
Value::integer(metadata.file_attributes() as i64)
);
attributes.insert(
Value::Symbol(crate::utils::intern_symbol("windows-creation-time")),
Value::integer(metadata.creation_time() as i64)
);
attributes.insert(
Value::Symbol(crate::utils::intern_symbol("windows-last-access-time")),
Value::integer(metadata.last_access_time() as i64)
);
attributes.insert(
Value::Symbol(crate::utils::intern_symbol("windows-last-write-time")),
Value::integer(metadata.last_write_time() as i64)
);
}
Ok(Value::Hashtable(Arc::new(std::sync::RwLock::new(attributes))))
}
Err(e) => Err(Box::new(DiagnosticError::runtime_error(
format!("Cannot get attributes for '{path}': {e}"),
None,
))),
}
}
pub fn primitive_set_platform_file_attributes(_args: &[Value]) -> Result<Value> {
Err(Box::new(DiagnosticError::runtime_error(
"set-platform-file-attributes not yet implemented".to_string(),
None,
)))
}
pub fn primitive_file_system_info(_args: &[Value]) -> Result<Value> {
Err(Box::new(DiagnosticError::runtime_error(
"file-system-info not yet implemented".to_string(),
None,
)))
}
pub fn primitive_create_event_watcher(_args: &[Value]) -> Result<Value> {
Err(Box::new(DiagnosticError::runtime_error(
"create-event-watcher not yet implemented".to_string(),
None,
)))
}
pub fn primitive_watch_file_events(_args: &[Value]) -> Result<Value> {
Err(Box::new(DiagnosticError::runtime_error(
"watch-file-events not yet implemented".to_string(),
None,
)))
}
pub fn primitive_poll_events(_args: &[Value]) -> Result<Value> {
Err(Box::new(DiagnosticError::runtime_error(
"poll-events not yet implemented".to_string(),
None,
)))
}
fn extract_string(value: &Value, operation: &str) -> Result<String> {
match value {
Value::Literal(crate::ast::Literal::String(s)) => Ok(s.clone()),
_ => Err(Box::new(DiagnosticError::runtime_error(
format!("{operation} requires string arguments"),
None,
))),
}
}
fn extract_integer(value: &Value, operation: &str) -> Result<i64> {
match value {
Value::Literal(lit) => {
if let Some(i) = lit.to_i64() {
Ok(i)
} else {
Err(Box::new(DiagnosticError::runtime_error(
format!("{operation} requires integer arguments"),
None,
)))
}
}
_ => Err(Box::new(DiagnosticError::runtime_error(
format!("{operation} requires integer arguments"),
None,
))),
}
}
fn list_to_value(values: Vec<Value>) -> Value {
values.into_iter().rev().fold(Value::Nil, |acc, val| {
Value::Pair(Arc::new(val), Arc::new(acc))
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_platform_detection() {
let result = primitive_platform_name(&[]);
assert!(result.is_ok());
if let Ok(Value::Literal(crate::ast::Literal::String(platform))) = result {
assert!(!platform.is_empty());
println!("Detected platform: {}", platform);
} else {
panic!("Expected string result");
}
}
#[test]
fn test_platform_capabilities() {
let result = primitive_platform_capabilities(&[]);
assert!(result.is_ok());
if let Ok(Value::Hashtable(capabilities)) = result {
let cap_map = capabilities.read().unwrap();
assert!(cap_map.contains_key(&Value::Symbol(crate::utils::intern_symbol("io-backends"))));
assert!(cap_map.contains_key(&Value::Symbol(crate::utils::intern_symbol("async-support"))));
} else {
panic!("Expected hashtable result");
}
}
#[test]
fn test_io_backend_availability() {
let args = vec![Value::string("mio".to_string())];
let result = primitive_io_backend_available_p(&args);
assert!(result.is_ok());
if let Ok(Value::Literal(crate::ast::Literal::Boolean(available))) = result {
assert!(available); } else {
panic!("Expected boolean result");
}
}
#[test]
fn test_high_performance_io_creation() {
let result = primitive_create_high_performance_io(&[]);
assert!(result.is_ok());
if let Ok(Value::Opaque(_)) = result {
} else {
panic!("Expected opaque handle result");
}
}
}