Skip to content

Instantly share code, notes, and snippets.

@pepyakin
Forked from anonymous/playground.rs
Created September 14, 2017 12:22
Show Gist options
  • Save pepyakin/4421e5d5bda03afbba4822256a1108aa to your computer and use it in GitHub Desktop.
Save pepyakin/4421e5d5bda03afbba4822256a1108aa to your computer and use it in GitHub Desktop.
Rust code shared from the playground
#![feature(core_intrinsics)]
use std::os::raw::c_char;
use std::ffi::{CStr, CString};
use std::ptr;
trait ToCStr<T> {
fn borrow_ptr(self) -> (T, *const c_char);
}
impl<'a, T: AsRef<CStr>> ToCStr<&'a CStr> for &'a T {
fn borrow_ptr(self) -> (&'a CStr, *const c_char) {
let r = self.as_ref();
let ptr = r.as_ptr();
(r, ptr)
}
}
impl<'a, T: AsRef<[u8]>> ToCStr<CString> for &'a T {
fn borrow_ptr(self) -> (CString, *const c_char) {
let vec = self.as_ref().to_vec();
let cstring = CString::new(vec).unwrap();
let ptr = cstring.as_ptr();
(cstring, ptr)
}
}
impl<'a> ToCStr<CString> for &'a str {
fn borrow_ptr(self) -> (CString, *const c_char) {
let cstring = CString::new(self).unwrap();
let ptr = cstring.as_ptr();
(cstring, ptr)
}
}
// Good. We were given String and we convert it into CString.
impl ToCStr<CString> for String {
fn borrow_ptr(self) -> (CString, *const c_char) {
let cstring = CString::new(self).unwrap();
let ptr = cstring.as_ptr();
(cstring, ptr)
}
}
// Good, there is nothing to do here.
impl ToCStr<CString> for CString {
fn borrow_ptr(self) -> (CString, *const c_char) {
let ptr = self.as_ptr();
(self, ptr)
}
}
impl ToCStr<()> for () {
fn borrow_ptr(self) -> ((), *const c_char) {
((), ptr::null())
}
}
fn borrow_ptr_or_null<P, T: ToCStr<P>>(name: Option<T>) -> (Option<P>, *const c_char) {
match name {
Some(str) => {
let (payload, ptr) = str.borrow_ptr();
(Some(payload), ptr)
}
None => (None, ptr::null()),
}
}
fn accepts_cstr<T>(x: *const c_char) {
let type_name = unsafe { std::intrinsics::type_name::<T>() };
if x.is_null() {
println!("type_name={}, ptr is null", type_name);
return;
}
unsafe {
let cstr = CStr::from_ptr(x);
let str = cstr.to_str().unwrap();
println!("type_name={}, cstr={}, len={}", type_name, str, str.len());
}
}
fn do_stuff_maybe<P, T: ToCStr<P>>(name: Option<T>) {
let (_payload, ptr) = borrow_ptr_or_null(name);
accepts_cstr::<T>(ptr);
}
fn do_stuff<P, T: ToCStr<P>>(name: T) {
// if change _payload to _ it could lead to segfault.
// Can we do better here?
let (_payload, ptr) = name.borrow_ptr();
accepts_cstr::<T>(ptr);
}
fn main() {
do_stuff_maybe(Some("Some(String)".to_string()));
do_stuff_maybe(Some("Some(&str)"));
do_stuff_maybe(None::<&str>);
do_stuff("String".to_string());
do_stuff(&"&String".to_string());
do_stuff("&str");
// this shouldn be not allowed!
// do_stuff(None::<()>);
do_stuff(CString::new("CString").unwrap());
do_stuff(&CString::new("&CString").unwrap());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment