-
-
Save pepyakin/4421e5d5bda03afbba4822256a1108aa to your computer and use it in GitHub Desktop.
Rust code shared from the playground
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![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