use std::io::Read;
use std::ffi::CStr;
use sys::*;
use error::{Result, Error};
use version::Version;
use string::IntoCString;
#[macro_export]
macro_rules! jl_catch {
() => {
jl_catch!(|ex| { ex });
};
(|$ex:ident| $body:expr) => {
jl_catch!(|$ex -> $crate::error::Error::UnhandledException| $crate::error::Error::UnhandledException($body));
};
(|$ex:ident -> $t:ty| $body:expr) => {
#[allow(unused_variables)] {
if let Some($ex) = $crate::api::Exception::catch() {
return Err($body);
}
}
}
}
#[macro_use]
pub mod value;
#[macro_use]
pub mod array;
pub mod function;
pub mod sym;
pub mod module;
pub mod datatype;
pub mod task;
pub mod exception;
pub mod primitive;
pub use self::value::{Value, JlValue};
pub use self::array::{Array, Svec};
pub use self::function::Function;
pub use self::sym::{Symbol, IntoSymbol};
pub use self::module::Module;
pub use self::datatype::Datatype;
pub use self::task::Task;
pub use self::exception::Exception;
pub use self::primitive::*;
pub struct Gc;
impl Gc {
pub fn enable(&mut self, p: bool) -> Result<()> {
unsafe {
jl_gc_enable(p as i32);
}
jl_catch!();
Ok(())
}
pub fn is_enabled(&self) -> bool {
unsafe { jl_gc_is_enabled() != 0 }
}
pub fn collect(&mut self, full: bool) -> Result<()> {
unsafe {
jl_gc_collect(full as i32);
}
jl_catch!();
Ok(())
}
pub fn total_bytes(&self) -> isize {
unsafe { jl_gc_total_bytes() as isize }
}
pub fn total_hrtime(&self) -> usize {
unsafe { jl_gc_total_hrtime() as usize }
}
pub fn diff_total_bytes(&self) -> isize {
unsafe { jl_gc_diff_total_bytes() as isize }
}
}
pub struct Julia {
main: Module,
core: Module,
base: Module,
top: Module,
at_exit: Option<i32>,
gc: Gc,
}
impl Julia {
pub unsafe fn new_unchecked() -> Julia {
if !Julia::is_initialized() {
panic!("Julia is not initialized");
}
let main = Module::new_unchecked(jl_main_module);
let core = Module::new_unchecked(jl_core_module);
let base = Module::new_unchecked(jl_base_module);
let top = Module::new_unchecked(jl_top_module);
Julia {
main: main,
core: core,
base: base,
top: top,
at_exit: None,
gc: Gc,
}
}
pub fn new() -> Result<Julia> {
if Julia::is_initialized() {
return Err(Error::JuliaInitialized);
}
unsafe {
jl_init();
}
jl_catch!();
let mut jl = unsafe { Julia::new_unchecked() };
jl.at_exit = Some(0);
Ok(jl)
}
pub fn version(&self) -> Version {
unsafe {
let major = jl_ver_major() as u32;
let minor = jl_ver_minor() as u32;
let patch = jl_ver_patch() as u32;
let release = jl_ver_is_release() != 0;
let branch = jl_git_branch();
let commit = jl_git_commit();
let mut branch = CStr::from_ptr(branch).to_str().ok();
let commit = CStr::from_ptr(commit).to_str().ok();
if branch == Some("(no branch)") {
branch = None;
}
Version {
name: "julia",
major: major,
minor: minor,
patch: patch,
release: release,
branch: branch,
commit: commit,
}
}
}
pub fn gc(&self) -> &Gc {
&self.gc
}
pub fn gc_mut(&mut self) -> &mut Gc {
&mut self.gc
}
pub fn is_initialized() -> bool {
unsafe { jl_is_initialized() != 0 }
}
pub fn exit(mut self, at_exit: i32) {
self.at_exit(Some(at_exit))
}
pub fn at_exit(&mut self, at_exit: Option<i32>) {
self.at_exit = at_exit;
}
pub fn main(&self) -> &Module {
&self.main
}
pub fn core(&self) -> &Module {
&self.core
}
pub fn base(&self) -> &Module {
&self.base
}
pub fn top(&self) -> &Module {
&self.top
}
pub fn load<R: Read, S: IntoCString>(&mut self, r: &mut R, name: Option<S>) -> Result<Value> {
let mut content = String::new();
let len = r.read_to_string(&mut content)?;
let content = content.into_cstring();
let content = content.as_ptr();
let name = name.map(|s| s.into_cstring()).unwrap_or_else(
|| "string".into_cstring(),
);
let name = name.as_ptr();
let raw = unsafe { jl_load_file_string(content, len, name as *mut _) };
jl_catch!();
Value::new(raw)
}
pub fn eval_string<S: IntoCString>(&mut self, string: S) -> Result<Value> {
let string = string.into_cstring();
let string = string.as_ptr();
let ret = unsafe { jl_eval_string(string) };
jl_catch!();
Value::new(ret).map_err(|_| Error::EvalError)
}
}
impl Drop for Julia {
fn drop(&mut self) {
self.at_exit.map(|s| unsafe { jl_atexit_hook(s) });
}
}