use crate::channel;

/// Initialize the channel library, should be run at the start of main() in your guest plugin
#[no_mangle]
pub extern "C" fn hyperchannel_init() {
    crate::hypercall::start();
}

/// Uninitialize the channel library, should be run at the end of main() in your guest plugin
#[no_mangle]
pub extern "C" fn hyperchannel_uninit() {
    crate::hypercall::stop();
}

/// Read from a channel descriptor into a buffer
///
/// Returns: the number of bytes read into the buffer.
#[no_mangle]
pub unsafe extern "C" fn channel_read(channel: u32, out: *mut u8, out_len: usize) -> usize {
    channel::read(channel, std::slice::from_raw_parts_mut(out, out_len))
}

/// Write a buffer to a given channel descriptor
#[no_mangle]
pub unsafe extern "C" fn channel_write(channel: u32, buf: *const u8, buf_len: usize) {
    channel::write(channel, std::slice::from_raw_parts(buf, buf_len))
}

/// Gets the main channel for a plugin of a given name
///
/// Returns: the number of bytes read into the buffer, or -1 if the plugin wasn't found
#[no_mangle]
pub unsafe extern "C" fn get_main_channel(name: *const u8, len: usize) -> i32 {
    crate::get_main_raw_channel(std::str::from_utf8(std::slice::from_raw_parts(name, len)).unwrap())
        .map(|channel| channel.0 as i32)
        .unwrap_or(-1)
}

/// Get a new channel not associated with any specific plugin
///
/// Returns: the channel, or -1 if an error occurs
#[no_mangle]
pub unsafe extern "C" fn get_new_channel() -> i32 {
    crate::get_new_channel()
        .map(|channel| channel.0 as i32)
        .unwrap_or(-1)
}

/// Output a debug string to the hypervisor
#[no_mangle]
pub unsafe extern "C" fn output_debug_string(s: *const u8, len: usize) {
    crate::debug_output(std::str::from_utf8(std::slice::from_raw_parts(s, len)).unwrap())
}
