Skip to content

Commit 6d5a95c

Browse files
committed
Cleanup string
* Add CFString::new, deprecate FromStr impl * Implement Display for CFString * Add wrapping `"`s for Debug impl
1 parent edaea4d commit 6d5a95c

File tree

1 file changed

+66
-50
lines changed

1 file changed

+66
-50
lines changed

src/string.rs

Lines changed: 66 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ use base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
1616
use base::{kCFAllocatorDefault, kCFAllocatorNull};
1717

1818
use libc;
19+
use std::ffi::CStr;
1920
use std::fmt;
20-
use std::str::FromStr;
21-
use std::string::ToString;
21+
use std::str::{self, FromStr};
2222
use std::mem;
2323
use std::ptr;
2424
use std::vec::Vec;
@@ -228,7 +228,6 @@ impl Drop for CFString {
228228
}
229229
}
230230

231-
232231
impl TCFType<CFStringRef> for CFString {
233232
#[inline]
234233
fn as_concrete_TypeRef(&self) -> CFStringRef {
@@ -265,69 +264,84 @@ impl TCFType<CFStringRef> for CFString {
265264
impl FromStr for CFString {
266265
type Err = ();
267266

268-
/// Creates a new `CFString` instance from a Rust string.
267+
/// # Deprecated
268+
///
269+
/// Use CFString::new instead.
269270
#[inline]
270271
fn from_str(string: &str) -> Result<CFString, ()> {
271-
unsafe {
272-
let string_ref = CFStringCreateWithBytes(kCFAllocatorDefault,
273-
string.as_ptr(),
274-
string.len().to_CFIndex(),
275-
kCFStringEncodingUTF8,
276-
false as Boolean,
277-
kCFAllocatorNull);
278-
Some(TCFType::wrap_under_create_rule(string_ref)).ok_or(())
279-
}
272+
Ok(CFString::new(string))
280273
}
281274
}
282275

283-
impl ToString for CFString {
284-
fn to_string(&self) -> String {
276+
impl fmt::Display for CFString {
277+
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
285278
unsafe {
286-
let char_len = self.char_len();
287-
288-
// First, ask how big the buffer ought to be.
289-
let mut bytes_required: CFIndex = 0;
290-
CFStringGetBytes(self.obj,
291-
CFRange::init(0, char_len),
292-
kCFStringEncodingUTF8,
293-
0,
294-
false as Boolean,
295-
ptr::null_mut(),
296-
0,
297-
&mut bytes_required);
298-
299-
// Then, allocate the buffer and actually copy.
300-
let mut buffer = Vec::with_capacity(bytes_required as usize);
301-
for _ in (0..bytes_required) { buffer.push('\x00' as u8) }
302-
303-
let mut bytes_used: CFIndex = 0;
304-
let chars_written = CFStringGetBytes(self.obj,
305-
CFRange::init(0, char_len),
306-
kCFStringEncodingUTF8,
307-
0,
308-
false as Boolean,
309-
buffer.as_mut_ptr(),
310-
buffer.len().to_CFIndex(),
311-
&mut bytes_used) as usize;
312-
assert!(chars_written.to_CFIndex() == char_len);
313-
314-
// This is dangerous; we over-allocate and null-terminate the string (during
315-
// initialization).
316-
assert!(bytes_used == buffer.len().to_CFIndex());
317-
String::from_utf8(buffer).unwrap()
279+
// Do this without allocating if we can get away with it
280+
let c_string = CFStringGetCStringPtr(self.obj, kCFStringEncodingUTF8);
281+
if c_string != ptr::null() {
282+
let c_str = CStr::from_ptr(c_string);
283+
fmt.write_str(str::from_utf8_unchecked(c_str.to_bytes()))
284+
} else {
285+
let char_len = self.char_len();
286+
287+
// First, ask how big the buffer ought to be.
288+
let mut bytes_required: CFIndex = 0;
289+
CFStringGetBytes(self.obj,
290+
CFRange::init(0, char_len),
291+
kCFStringEncodingUTF8,
292+
0,
293+
false as Boolean,
294+
ptr::null_mut(),
295+
0,
296+
&mut bytes_required);
297+
298+
// Then, allocate the buffer and actually copy.
299+
let mut buffer = Vec::with_capacity(bytes_required as usize);
300+
for _ in (0..bytes_required) { buffer.push('\x00' as u8) }
301+
302+
let mut bytes_used: CFIndex = 0;
303+
let chars_written = CFStringGetBytes(self.obj,
304+
CFRange::init(0, char_len),
305+
kCFStringEncodingUTF8,
306+
0,
307+
false as Boolean,
308+
buffer.as_mut_ptr(),
309+
buffer.len().to_CFIndex(),
310+
&mut bytes_used) as usize;
311+
assert!(chars_written.to_CFIndex() == char_len);
312+
313+
// This is dangerous; we over-allocate and null-terminate the string (during
314+
// initialization).
315+
assert!(bytes_used == buffer.len().to_CFIndex());
316+
fmt.write_str(str::from_utf8_unchecked(&buffer))
317+
}
318318
}
319319
}
320320
}
321321

322322
impl fmt::Debug for CFString {
323323
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
324-
write!(f, "{}", self.to_string())
324+
write!(f, "\"{}\"", self)
325325
}
326326
}
327327

328328

329329
impl CFString {
330-
/// Like `CFString::from_string`, but references a string that can be used as a backing store
330+
/// Creates a new `CFString` instance from a Rust string.
331+
#[inline]
332+
pub fn new(string: &str) -> CFString {
333+
unsafe {
334+
let string_ref = CFStringCreateWithBytes(kCFAllocatorDefault,
335+
string.as_ptr(),
336+
string.len().to_CFIndex(),
337+
kCFStringEncodingUTF8,
338+
false as Boolean,
339+
kCFAllocatorNull);
340+
CFString::wrap_under_create_rule(string_ref)
341+
}
342+
}
343+
344+
/// Like `CFString::new`, but references a string that can be used as a backing store
331345
/// by virtue of being statically allocated.
332346
#[inline]
333347
pub fn from_static_string(string: &'static str) -> CFString {
@@ -420,7 +434,9 @@ extern {
420434
//fn CFStringGetCharactersPtr
421435
//fn CFStringGetCharacterFromInlineBuffer
422436
//fn CFStringGetCString
423-
//fn CFStringGetCStringPtr
437+
fn CFStringGetCStringPtr(theString: CFStringRef,
438+
encoding: CFStringEncoding)
439+
-> *const libc::c_char;
424440
fn CFStringGetLength(theString: CFStringRef) -> CFIndex;
425441
//fn CFStringGetPascalString
426442
//fn CFStringGetPascalStringPtr

0 commit comments

Comments
 (0)