/* Copyright 2018-2019 Mozilla Foundation * *LicensedundertheApacheLicense(Version2.0),ortheMITlicense, *(the"Licenses")atyouroption.Youmaynotusethisfileexceptin *compliancewithoneoftheLicenses.Youmayobtaincopiesofthe *Licensesat: * *http://www.apache.org/licenses/LICENSE-2.0 *http://opensource.org/licenses/MIT * *Unlessrequiredbyapplicablelaworagreedtoinwriting,software *distributedundertheLicensesisdistributedonan"ASIS"BASIS, *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. *SeetheLicensesforthespecificlanguagegoverningpermissionsand
* limitations under the Licenses. */
use std::ffi::CStr; use std::marker::PhantomData; use std::os::raw::c_char;
/// `FfiStr<'a>` is a safe (`#[repr(transparent)]`) wrapper around a /// nul-terminated `*const c_char` (e.g. a C string). Conceptually, it is /// similar to [`std::ffi::CStr`], except that it may be used in the signatures /// of extern "C" functions. /// /// Functions accepting strings should use this instead of accepting a C string /// directly. This allows us to write those functions using safe code without /// allowing safe Rust to cause memory unsafety. /// /// A single function for constructing these from Rust ([`FfiStr::from_raw`]) /// has been provided. Most of the time, this should not be necessary, and users /// should accept `FfiStr` in the parameter list directly. /// /// ## Caveats /// /// An effort has been made to make this struct hard to misuse, however it is /// still possible, if the `'static` lifetime is manually specified in the /// struct. E.g. /// /// ```rust,no_run /// # use ffi_support::FfiStr; /// // NEVER DO THIS /// #[no_mangle] /// extern "C" fn never_do_this(s: FfiStr<'static>) { /// // save `s` somewhere, and access it after this /// // function returns. /// } /// ``` /// /// Instead, one of the following patterns should be used: /// /// ``` /// # use ffi_support::FfiStr; /// #[no_mangle] /// extern "C" fn valid_use_1(s: FfiStr<'_>) { /// // Use of `s` after this function returns is impossible /// } /// // Alternative: /// #[no_mangle] /// extern "C" fn valid_use_2(s: FfiStr) { /// // Use of `s` after this function returns is impossible /// } /// ``` #[repr(transparent)] pubstruct FfiStr<'a> {
cstr: *const c_char,
_boo: PhantomData<&'a ()>,
}
impl<'a> FfiStr<'a> { /// Construct an `FfiStr` from a raw pointer. /// /// This should not be needed most of the time, and users should instead /// accept `FfiStr` in function parameter lists. /// /// # Safety /// /// Dereferences a pointer and is thus unsafe. #[inline] pubunsafefn from_raw(ptr: *const c_char) -> Self { Self {
cstr: ptr,
_boo: PhantomData,
}
}
/// Construct a FfiStr from a `std::ffi::CStr`. This is provided for /// completeness, as a safe method of producing an `FfiStr` in Rust. #[inline] pubfn from_cstr(cstr: &'a CStr) -> Self { Self {
cstr: cstr.as_ptr(),
_boo: PhantomData,
}
}
/// Get an `&str` out of the `FfiStr`. This will panic in any case that /// [`FfiStr::as_opt_str`] would return `None` (e.g. null pointer or invalid /// UTF-8). /// /// If the string should be optional, you should use [`FfiStr::as_opt_str`] /// instead. If an owned string is desired, use [`FfiStr::into_string`] or /// [`FfiStr::into_opt_string`]. #[inline] pubfn as_str(&self) -> &'a str { self.as_opt_str()
.expect("Unexpected null string pointer passed to rust")
}
/// Get an `Option<&str>` out of the `FfiStr`. If this stores a null /// pointer, then None will be returned. If a string containing invalid /// UTF-8 was passed, then an error will be logged and `None` will be /// returned. /// /// If the string is a required argument, use [`FfiStr::as_str`], or /// [`FfiStr::into_string`] instead. If `Option<String>` is desired, use /// [`FfiStr::into_opt_string`] (which will handle invalid UTF-8 by /// replacing with the replacement character). pubfn as_opt_str(&self) -> Option<&'a str> { ifself.cstr.is_null() { return None;
} unsafe { match std::ffi::CStr::from_ptr(self.cstr).to_str() {
Ok(s) => Some(s),
Err(e) => {
log::error!("Invalid UTF-8 was passed to rust! {:?}", e);
None
}
}
}
}
/// Get an `Option<String>` out of the `FfiStr`. Returns `None` if this /// `FfiStr` holds a null pointer. Note that unlike [`FfiStr::as_opt_str`], /// invalid UTF-8 is replaced with the replacement character instead of /// causing us to return None. /// /// If the string should be mandatory, you should use /// [`FfiStr::into_string`] instead. If an owned string is not needed, you /// may want to use [`FfiStr::as_str`] or [`FfiStr::as_opt_str`] instead, /// (however, note the differences in how invalid UTF-8 is handled, should /// this be relevant to your use). pubfn into_opt_string(self) -> Option<String> { if !self.cstr.is_null() { unsafe { Some(CStr::from_ptr(self.cstr).to_string_lossy().to_string()) }
} else {
None
}
}
/// Get a `String` out of a `FfiStr`. This function is essential a /// convenience wrapper for `ffi_str.into_opt_string().unwrap()`, with a /// message that indicates that a null argument was passed to rust when it /// should be mandatory. As with [`FfiStr::into_opt_string`], invalid UTF-8 /// is replaced with the replacement character if encountered. /// /// If the string should *not* be mandatory, you should use /// [`FfiStr::into_opt_string`] instead. If an owned string is not needed, /// you may want to use [`FfiStr::as_str`] or [`FfiStr::as_opt_str`] /// instead, (however, note the differences in how invalid UTF-8 is handled, /// should this be relevant to your use). #[inline] pubfn into_string(self) -> String { self.into_opt_string()
.expect("Unexpected null string pointer passed to rust")
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.