This repository has been archived by the owner on Jun 8, 2021. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 62
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This new module keeps track of CStrings to help avoid allocating new Strings in gir's generated code.
- Loading branch information
Showing
3 changed files
with
185 additions
and
7 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
// Copyright 2018, The Gtk-rs Project Developers. | ||
// See the COPYRIGHT file at the top-level directory of this distribution. | ||
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT> | ||
|
||
use std::ffi::CStr; | ||
use std::ops::Deref; | ||
use std::os::raw::c_char; | ||
use std::ptr; | ||
use translate::*; | ||
use types::{StaticType, Type}; | ||
|
||
use gobject_ffi; | ||
use ffi as glib_ffi; | ||
use value::{FromValueOptional, Value}; | ||
|
||
#[derive(Debug, Hash, PartialOrd, Ord)] | ||
pub struct CStringHolder { | ||
slice: Box<CStr>, | ||
ptr: *const c_char, | ||
owned: bool, | ||
} | ||
|
||
impl CStringHolder { | ||
pub fn new(ptr: *const c_char) -> Self { | ||
assert!(!ptr.is_null()); | ||
unsafe { | ||
let slice = CStr::from_ptr(ptr); | ||
Self { ptr, slice: Box::from(slice), owned: true } | ||
} | ||
} | ||
|
||
pub fn from(s: &[u8]) -> Self { | ||
let slice = match CStr::from_bytes_with_nul(s) { | ||
Ok(s) => s, | ||
Err(e) => panic!(e), | ||
}; | ||
let ptr = slice.as_ptr(); | ||
assert!(!ptr.is_null()); | ||
Self { ptr, slice: Box::from(slice), owned: false } | ||
} | ||
|
||
pub fn as_str(&self) -> &str { | ||
let bytes = self.slice.to_bytes(); | ||
match std::str::from_utf8(bytes) { | ||
Ok(s) => s, | ||
Err(e) => { | ||
panic!("UTF-8 conversion failed: {}", e); | ||
}, | ||
} | ||
} | ||
} | ||
|
||
impl Drop for CStringHolder { | ||
fn drop(&mut self) { | ||
if self.owned { | ||
unsafe { | ||
glib_ffi::g_free(self.ptr as *mut _); | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl PartialEq for CStringHolder { | ||
fn eq(&self, other: &CStringHolder) -> bool { | ||
self.slice == other.slice | ||
} | ||
} | ||
|
||
impl Eq for CStringHolder {} | ||
|
||
impl AsRef<str> for CStringHolder { | ||
fn as_ref(&self) -> &str { | ||
self.as_str() | ||
} | ||
} | ||
|
||
impl Deref for CStringHolder { | ||
type Target = str; | ||
|
||
fn deref(&self) -> &str { | ||
self.as_str() | ||
} | ||
} | ||
|
||
impl From<CStringHolder> for String { | ||
fn from(holder: CStringHolder) -> Self { | ||
String::from(holder.as_str()) | ||
} | ||
} | ||
|
||
impl From<String> for CStringHolder { | ||
fn from(s: String) -> Self { | ||
CStringHolder::new(s.into_bytes().as_ptr() as *const c_char) | ||
} | ||
} | ||
|
||
impl From<CStringHolder> for Box<str> { | ||
fn from(holder: CStringHolder) -> Self { | ||
Box::from(holder.as_str()) | ||
} | ||
} | ||
|
||
impl FromGlibPtrFull<*const c_char> for CStringHolder { | ||
unsafe fn from_glib_full(ptr: *const c_char) -> Self { | ||
CStringHolder::new(ptr) | ||
} | ||
} | ||
|
||
impl FromGlibPtrFull<*mut i8> for CStringHolder { | ||
unsafe fn from_glib_full(ptr: *mut i8) -> Self { | ||
CStringHolder::new(ptr as *const c_char) | ||
} | ||
} | ||
|
||
impl FromGlib<*mut i8> for CStringHolder { | ||
fn from_glib(ptr: *mut i8) -> Self { | ||
CStringHolder::new(ptr as *const c_char) | ||
} | ||
} | ||
|
||
impl FromGlibPtrNone<*const c_char> for CStringHolder { | ||
unsafe fn from_glib_none(ptr: *const c_char) -> Self { | ||
assert!(!ptr.is_null()); | ||
CStringHolder::new(ptr) | ||
} | ||
} | ||
|
||
impl FromGlibPtrNone<*mut i8> for CStringHolder { | ||
unsafe fn from_glib_none(ptr: *mut i8) -> Self { | ||
assert!(!ptr.is_null()); | ||
CStringHolder::new(ptr) | ||
} | ||
} | ||
|
||
impl StaticType for CStringHolder { | ||
fn static_type() -> Type { | ||
unimplemented!(); | ||
} | ||
} | ||
|
||
impl<'a> FromValueOptional<'a> for CStringHolder { | ||
unsafe fn from_value_optional(value: &'a Value) -> Option<Self> { | ||
from_glib_none(gobject_ffi::g_value_get_string(value.to_glib_none().0)) | ||
} | ||
} | ||
|
||
impl_from_glib_container_as_vec_string!(CStringHolder, *const c_char); | ||
impl_from_glib_container_as_vec_string!(CStringHolder, *mut c_char); | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use cstringholder::CStringHolder; | ||
use std::ffi::CString; | ||
|
||
#[test] | ||
fn test_holder() { | ||
let data = CString::new("foo").unwrap(); | ||
let ptr = data.into_raw(); | ||
|
||
let holder = CStringHolder::new(ptr); | ||
assert_eq!(holder.as_str(), "foo"); | ||
let foo: Box<str> = holder.into(); | ||
assert_eq!(foo.as_ref(), "foo"); | ||
} | ||
|
||
#[test] | ||
fn test_holder_from_str() { | ||
let holder = CStringHolder::from(b"foo\0"); | ||
assert_eq!(holder.as_str(), "foo"); | ||
let foo: Box<str> = holder.into(); | ||
assert_eq!(foo.as_ref(), "foo"); | ||
} | ||
} |
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
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