diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 53d6d59bc..d6cbd09b1 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -3227,7 +3227,7 @@ pub unsafe extern "C" fn dc_lot_get_text1(lot: *mut dc_lot_t) -> *mut libc::c_ch } let lot = &*lot; - strdup_opt(lot.get_text1()) + lot.get_text1().strdup() } #[no_mangle] @@ -3238,7 +3238,7 @@ pub unsafe extern "C" fn dc_lot_get_text2(lot: *mut dc_lot_t) -> *mut libc::c_ch } let lot = &*lot; - strdup_opt(lot.get_text2()) + lot.get_text2().strdup() } #[no_mangle] @@ -3323,13 +3323,6 @@ impl ResultExt for Result { } } -unsafe fn strdup_opt(s: Option>) -> *mut libc::c_char { - match s { - Some(s) => s.as_ref().strdup(), - None => ptr::null_mut(), - } -} - trait ResultNullableExt { fn into_raw(self) -> *mut T; } diff --git a/deltachat-ffi/src/string.rs b/deltachat-ffi/src/string.rs index 8baf4d56a..7cfd1c357 100644 --- a/deltachat-ffi/src/string.rs +++ b/deltachat-ffi/src/string.rs @@ -1,5 +1,6 @@ use failure::Fail; use std::ffi::{CStr, CString}; +use std::ptr; /// Duplicates a string /// @@ -144,7 +145,7 @@ pub trait CStringExt { impl CStringExt for CString {} -/// Convenience methods to make transitioning from raw C strings easier. +/// Convenience methods to turn strings into C strings. /// /// To interact with (legacy) C APIs we often need to convert from /// Rust strings to raw C strings. This can be clumsy to do correctly @@ -174,6 +175,35 @@ impl> StrExt for T { } } +/// Convenience methods to turn optional strings into C strings. +/// +/// This is the same as the [StrExt] trait but a different trait name +/// to work around the type system not allowing to implement [StrExt] +/// for `Option` When we already have an [StrExt] impl +/// for `AsRef<&str>`. +/// +/// When the [Option] is [Option::Some] this behaves just like +/// [StrExt::strdup], when it is [Option::None] a null pointer is +/// returned. +pub trait OptStrExt { + /// Allocate a new raw C `*char` version of this string, or NULL. + /// + /// See [StrExt::strdup] for details. + unsafe fn strdup(&self) -> *mut libc::c_char; +} + +impl> OptStrExt for Option { + unsafe fn strdup(&self) -> *mut libc::c_char { + match self { + Some(s) => { + let tmp = CString::yolo(s.as_ref()); + dc_strdup(tmp.as_ptr()) + } + None => ptr::null_mut(), + } + } +} + pub fn to_string_lossy(s: *const libc::c_char) -> String { if s.is_null() { return "".into(); @@ -347,4 +377,19 @@ mod tests { assert_eq!(cmp, 0); } } + + #[test] + fn test_strdup_opt_string() { + unsafe { + let s = Some("hello"); + let c = s.strdup(); + let cmp = strcmp(c, b"hello\x00" as *const u8 as *const libc::c_char); + free(c as *mut libc::c_void); + assert_eq!(cmp, 0); + + let s: Option<&str> = None; + let c = s.strdup(); + assert_eq!(c, ptr::null_mut()); + } + } }