Skip to content

Instantly share code, notes, and snippets.

@atheriel
Last active January 20, 2018 07:58
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save atheriel/3ede430057f9dd25da36 to your computer and use it in GitHub Desktop.
Save atheriel/3ede430057f9dd25da36 to your computer and use it in GitHub Desktop.
Can one write a Python extension in Rust?
PyObject * RustPy_InitModule(const char *name, PyMethodDef *methods, const char *doc) {
// return Py_InitModule4(name, methods, doc, (PyObject *) NULL, PYTHON_API_VERSION);
return Py_InitModule3(name, methods, doc);
}
#![feature(macro_rules)]
#![crate_type = "dylib"]
extern crate libc;
use std::ptr;
use libc::{c_char, c_int};
pub struct PyObjectRaw;
type PyCFunction = extern "C" fn(slf: *mut PyObjectRaw, args: *mut PyObjectRaw) -> *mut PyObjectRaw;
type PyCFunctionWithKeywords = extern "C" fn(slf: *mut PyObjectRaw, args: *mut PyObjectRaw, kwargs: *mut PyObjectRaw) -> *mut PyObjectRaw;
#[repr(C)]
pub struct PyMethodDef {
ml_name: &'static [u8],
ml_meth: Option<PyCFunction>,
ml_flags: c_int,
ml_doc: &'static [u8],
}
#[link(name = "python2.7")]
#[link(name = "macroexpand", kind = "static")]
extern "C" {
fn RustPy_InitModule(name: *const c_char, methods: *const PyMethodDef,
doc: *const c_char) -> *mut PyObjectRaw;
fn PyModule_AddObject(module: *mut PyObjectRaw, name: *const c_char,
value: *mut PyObjectRaw) -> c_int;
fn PyString_FromString(string: *const c_char) -> *mut PyObjectRaw;
}
fn py_str(string: &str) -> Option<*mut PyObjectRaw> {
let cstring = string.to_c_str();
unsafe {
let obj = PyString_FromString(cstring.as_ptr());
if obj.is_not_null() { Some(obj) } else { None }
}
}
pub trait RustPyModule {
fn init(name: &'static str, methods: &'static [PyMethodDef]) -> Option<Self>;
fn add_object(&mut self, name: &str,
object: *mut PyObjectRaw) -> Result<(), ()>;
}
impl RustPyModule for PyObjectRaw {
fn init(name: &'static str, methods: &'static [PyMethodDef]) -> Option<PyObjectRaw> {
let c_name = name.to_c_str();
unsafe {
let m = RustPy_InitModule(c_name.as_ptr(), methods.as_ptr(), ptr::null());
if m.is_not_null() { Some(*m) } else { None }
}
}
fn add_object(&mut self, name: &str,
object: *mut PyObjectRaw) -> Result<(), ()> {
let c_name = name.to_c_str();
unsafe {
if PyModule_AddObject(self, c_name.as_ptr(), object) == 0 {
Ok(())
} else { Err(()) }
}
}
}
#[allow(unused_variable)]
extern "C" fn helloworld(slf: *mut PyObjectRaw,
args: *mut PyObjectRaw) -> *mut PyObjectRaw {
println!("Hello, world!");
ptr::mut_null()
}
static RUSTTEST_METHODS: &'static [PyMethodDef] = &[
PyMethodDef {
ml_name: b"helloworld\x00",
ml_meth: Some(helloworld), ml_flags: 1,
ml_doc: b"No documentation provided.\x00"
}
];
#[no_mangle]
pub extern "C" fn initrusttest() {
let mut m: PyObjectRaw = match RustPyModule::init("rusttest", RUSTTEST_METHODS) {
Some(val) => val,
None => return
};
let _ = m.add_object("__author__", py_str("The Pumpkin King").unwrap());
let _ = m.add_object("__version__", py_str("0.0.1").unwrap());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment