skedge 0.1.3

Ergonomic single-process job scheduling for Rust programs.
Documentation
//! The C foreign-function interface allows any CFFI-compatible language to utilize skedge.

use crate::{Job, Scheduler};
use libc::{c_char, c_uint};
use std::ffi::CString;

/// Helper function to free strings generated by Rust.
/// Clients need to call this to ensure proper cleanup.
/// It is recommended to do so in a way such that your binding performs this automatically.
/// See the [Rust FFI Omnibus](http://jakegoulding.com/rust-ffi-omnibus/string_return/) for examples.
/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
#[allow(clippy::module_name_repetitions)]
#[no_mangle]
pub unsafe extern "C" fn ffi_string_free(s: *mut c_char) {
	{
		if s.is_null() {
			// nothing to do
			return;
		}
		// Otherwise, trigger the Rust destructor when it goes out of scope
		CString::from_raw(s)
	};
}

/// Instantiate a new Scheduler, returning a raw pointer
/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
#[no_mangle]
pub unsafe extern "C" fn scheduler_new() -> *mut Scheduler {
	Box::into_raw(Box::new(Scheduler::new()))
}

/// Free the scheduler
/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
#[no_mangle]
pub unsafe extern "C" fn scheduler_free(ptr: *mut Scheduler) {
	if ptr.is_null() {
		return;
	}
	// Capture it - moves into this function, which then drops at the end
	Box::from_raw(ptr);
}

/// Start configuring a job
/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
#[no_mangle]
pub unsafe extern "C" fn every(interval: c_uint) -> *mut Job {
	Box::into_raw(Box::new(Job::new(interval)))
}

/// Start configuring a job with interval 1
/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
#[no_mangle]
pub unsafe extern "C" fn every_single() -> *mut Job {
	Box::into_raw(Box::new(Job::new(1)))
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn run(
	job: *mut Job,
	scheduler: *mut Scheduler,
	work: extern "C" fn() -> (),
) {
	let job = {
		assert!(!job.is_null());
		Box::from_raw(job)
	};
	let scheduler = {
		assert!(!scheduler.is_null());
		&mut *scheduler
	};

	job.run_extern(scheduler, work)
		.unwrap_or_else(|e| eprintln!("Error: {e}"));
}

/// Run pending scheduler jobs
/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn run_pending(ptr: *mut Scheduler) {
	let scheduler = {
		assert!(!ptr.is_null());
		&mut *ptr
	};

	scheduler
		.run_pending()
		.unwrap_or_else(|e| eprintln!("Error: {e}"));
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn seconds(ptr: *mut Job) -> *mut Job {
	let job = {
		assert!(!ptr.is_null());
		Box::from_raw(ptr)
	};
	Box::into_raw(Box::new(job.seconds().unwrap_or_else(|e| {
		eprintln!("Error: {e}");
		std::process::exit(1);
	})))
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn second(ptr: *mut Job) -> *mut Job {
	let job = {
		assert!(!ptr.is_null());
		Box::from_raw(ptr)
	};
	Box::into_raw(Box::new(job.second().unwrap_or_else(|e| {
		eprintln!("Error: {e}");
		std::process::exit(1);
	})))
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn minutes(ptr: *mut Job) -> *mut Job {
	let job = {
		assert!(!ptr.is_null());
		Box::from_raw(ptr)
	};
	Box::into_raw(Box::new(job.minutes().unwrap_or_else(|e| {
		eprintln!("Error: {e}");
		std::process::exit(1);
	})))
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn minute(ptr: *mut Job) -> *mut Job {
	let job = {
		assert!(!ptr.is_null());
		Box::from_raw(ptr)
	};
	Box::into_raw(Box::new(job.minute().unwrap_or_else(|e| {
		eprintln!("Error: {e}");
		std::process::exit(1);
	})))
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn hours(ptr: *mut Job) -> *mut Job {
	let job = {
		assert!(!ptr.is_null());
		Box::from_raw(ptr)
	};
	Box::into_raw(Box::new(job.hours().unwrap_or_else(|e| {
		eprintln!("Error: {e}");
		std::process::exit(1);
	})))
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn hour(ptr: *mut Job) -> *mut Job {
	let job = {
		assert!(!ptr.is_null());
		Box::from_raw(ptr)
	};
	Box::into_raw(Box::new(job.hour().unwrap_or_else(|e| {
		eprintln!("Error: {e}");
		std::process::exit(1);
	})))
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn days(ptr: *mut Job) -> *mut Job {
	let job = {
		assert!(!ptr.is_null());
		Box::from_raw(ptr)
	};
	Box::into_raw(Box::new(job.days().unwrap_or_else(|e| {
		eprintln!("Error: {e}");
		std::process::exit(1);
	})))
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn day(ptr: *mut Job) -> *mut Job {
	let job = {
		assert!(!ptr.is_null());
		Box::from_raw(ptr)
	};
	Box::into_raw(Box::new(job.day().unwrap_or_else(|e| {
		eprintln!("Error: {e}");
		std::process::exit(1);
	})))
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn weeks(ptr: *mut Job) -> *mut Job {
	let job = {
		assert!(!ptr.is_null());
		Box::from_raw(ptr)
	};
	Box::into_raw(Box::new(job.weeks().unwrap_or_else(|e| {
		eprintln!("Error: {e}");
		std::process::exit(1);
	})))
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn week(ptr: *mut Job) -> *mut Job {
	let job = {
		assert!(!ptr.is_null());
		Box::from_raw(ptr)
	};
	Box::into_raw(Box::new(job.week().unwrap_or_else(|e| {
		eprintln!("Error: {e}");
		std::process::exit(1);
	})))
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn months(ptr: *mut Job) -> *mut Job {
	let job = {
		assert!(!ptr.is_null());
		Box::from_raw(ptr)
	};
	Box::into_raw(Box::new(job.months().unwrap_or_else(|e| {
		eprintln!("Error: {e}");
		std::process::exit(1);
	})))
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn month(ptr: *mut Job) -> *mut Job {
	let job = {
		assert!(!ptr.is_null());
		Box::from_raw(ptr)
	};
	Box::into_raw(Box::new(job.month().unwrap_or_else(|e| {
		eprintln!("Error: {e}");
		std::process::exit(1);
	})))
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn years(ptr: *mut Job) -> *mut Job {
	let job = {
		assert!(!ptr.is_null());
		Box::from_raw(ptr)
	};
	Box::into_raw(Box::new(job.years().unwrap_or_else(|e| {
		eprintln!("Error: {e}");
		std::process::exit(1);
	})))
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn year(ptr: *mut Job) -> *mut Job {
	let job = {
		assert!(!ptr.is_null());
		Box::from_raw(ptr)
	};
	Box::into_raw(Box::new(job.year().unwrap_or_else(|e| {
		eprintln!("Error: {e}");
		std::process::exit(1);
	})))
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn monday(ptr: *mut Job) -> *mut Job {
	let job = {
		assert!(!ptr.is_null());
		Box::from_raw(ptr)
	};
	Box::into_raw(Box::new(job.monday().unwrap_or_else(|e| {
		eprintln!("Error: {e}");
		std::process::exit(1);
	})))
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn tuesday(ptr: *mut Job) -> *mut Job {
	let job = {
		assert!(!ptr.is_null());
		Box::from_raw(ptr)
	};
	Box::into_raw(Box::new(job.tuesday().unwrap_or_else(|e| {
		eprintln!("Error: {e}");
		std::process::exit(1);
	})))
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn wednesday(ptr: *mut Job) -> *mut Job {
	let job = {
		assert!(!ptr.is_null());
		Box::from_raw(ptr)
	};
	Box::into_raw(Box::new(job.wednesday().unwrap_or_else(|e| {
		eprintln!("Error: {e}");
		std::process::exit(1);
	})))
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn thursday(ptr: *mut Job) -> *mut Job {
	let job = {
		assert!(!ptr.is_null());
		Box::from_raw(ptr)
	};
	Box::into_raw(Box::new(job.thursday().unwrap_or_else(|e| {
		eprintln!("Error: {e}");
		std::process::exit(1);
	})))
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn friday(ptr: *mut Job) -> *mut Job {
	let job = {
		assert!(!ptr.is_null());
		Box::from_raw(ptr)
	};
	Box::into_raw(Box::new(job.friday().unwrap_or_else(|e| {
		eprintln!("Error: {e}");
		std::process::exit(1);
	})))
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn saturday(ptr: *mut Job) -> *mut Job {
	let job = {
		assert!(!ptr.is_null());
		Box::from_raw(ptr)
	};
	Box::into_raw(Box::new(job.saturday().unwrap_or_else(|e| {
		eprintln!("Error: {e}");
		std::process::exit(1);
	})))
}

/// # Safety
///
///  This function crosses the FFI barrier and is therefore inherently unsafe.
///
/// # Panics
///
/// Panics if passed any null pointer.
#[no_mangle]
pub unsafe extern "C" fn sunday(ptr: *mut Job) -> *mut Job {
	let job = {
		assert!(!ptr.is_null());
		Box::from_raw(ptr)
	};
	Box::into_raw(Box::new(job.sunday().unwrap_or_else(|e| {
		eprintln!("Error: {e}");
		std::process::exit(1);
	})))
}