use std;
use ffi;
use libc::c_char;
use python::{Python, PythonObject, PyDrop};
use objectprotocol::ObjectProtocol;
use conversion::ToPyObject;
use objects::{PyObject, PyTuple, PyDict, exc};
use py_class::PythonObjectFromPyClassMacro;
use err::{self, PyResult, PyErr};
use std::ffi::{CStr, CString};
pub struct PyModule(PyObject);
pyobject_newtype!(PyModule, PyModule_Check, PyModule_Type);
impl PyModule {
pub fn new(py: Python, name: &str) -> PyResult<PyModule> {
let name = CString::new(name).unwrap();
unsafe {
err::result_cast_from_owned_ptr(py, ffi::PyModule_New(name.as_ptr()))
}
}
pub fn import(py: Python, name: &str) -> PyResult<PyModule> {
let name = CString::new(name).unwrap();
unsafe {
err::result_cast_from_owned_ptr(py, ffi::PyImport_ImportModule(name.as_ptr()))
}
}
pub fn dict(&self, py: Python) -> PyDict {
unsafe {
let r = PyObject::from_borrowed_ptr(py, ffi::PyModule_GetDict(self.0.as_ptr()));
r.unchecked_cast_into::<PyDict>()
}
}
unsafe fn str_from_ptr<'a>(&'a self, py: Python, ptr: *const c_char) -> PyResult<&'a str> {
if ptr.is_null() {
Err(PyErr::fetch(py))
} else {
let slice = CStr::from_ptr(ptr).to_bytes();
match std::str::from_utf8(slice) {
Ok(s) => Ok(s),
Err(e) => Err(PyErr::from_instance(py, try!(exc::UnicodeDecodeError::new_utf8(py, slice, e))))
}
}
}
pub fn name<'a>(&'a self, py: Python) -> PyResult<&'a str> {
unsafe { self.str_from_ptr(py, ffi::PyModule_GetName(self.0.as_ptr())) }
}
pub fn filename<'a>(&'a self, py: Python) -> PyResult<&'a str> {
unsafe { self.str_from_ptr(py, ffi::PyModule_GetFilename(self.0.as_ptr())) }
}
pub fn get(&self, py: Python, name: &str) -> PyResult<PyObject> {
self.as_object().getattr(py, name)
}
pub fn call<A>(&self, py: Python, name: &str, args: A, kwargs: Option<&PyDict>) -> PyResult<PyObject>
where A: ToPyObject<ObjectType=PyTuple>
{
try!(self.as_object().getattr(py, name)).call(py, args, kwargs)
}
pub fn add<V>(&self, py: Python, name: &str, value: V) -> PyResult<()> where V: ToPyObject {
self.as_object().setattr(py, name, value)
}
pub fn add_class<'p, T>(&self, py: Python<'p>) -> PyResult<()>
where T: PythonObjectFromPyClassMacro
{
T::add_to_module(py, self)
}
}