diff --git a/src/os/unix/mod.rs b/src/os/unix/mod.rs index 820e399..0e98a9f 100644 --- a/src/os/unix/mod.rs +++ b/src/os/unix/mod.rs @@ -1,7 +1,7 @@ /// UNIX implementation of dynamic library loading. /// /// This module should eventually be expanded with more UNIX-specific functionality in the future. -use util::{CheckedCStr, CStringAsRef}; +use util::{CowCString, CStringAsRef}; use std::ffi::{CStr, CString, OsStr}; use std::marker; @@ -125,7 +125,7 @@ impl Library { /// You may append a null byte at the end of the byte string to avoid string allocation in some /// cases. E.g. for symbol `sin` you may write `b"sin\0"` instead of `b"sin"`. pub unsafe fn get(&self, symbol: &[u8]) -> ::Result> { - let symbol = try!(CheckedCStr::from_bytes(symbol)); + let symbol = try!(CowCString::from_bytes(symbol)); // `dlsym` may return nullptr in two cases: when a symbol genuinely points to a null // pointer or the symbol cannot be found. In order to detect this case a double dlerror // pattern must be used, which is, sadly, a little bit racy. diff --git a/src/os/windows/mod.rs b/src/os/windows/mod.rs index c6b37af..534fa4a 100644 --- a/src/os/windows/mod.rs +++ b/src/os/windows/mod.rs @@ -4,7 +4,7 @@ extern crate winapi; extern crate kernel32; -use util::{CheckedCStr, CStringAsRef}; +use util::{CowCString, CStringAsRef}; use std::ffi::{OsStr, OsString}; use std::marker; @@ -67,7 +67,7 @@ impl Library { /// You may append a null byte at the end of the byte string to avoid string allocation in some /// cases. E.g. for symbol `sin` you may write `b"sin\0"` instead of `b"sin"`. pub unsafe fn get(&self, symbol: &[u8]) -> ::Result> { - let symbol = try!(CheckedCStr::from_bytes(symbol)); + let symbol = try!(CowCString::from_bytes(symbol)); with_get_last_error(|| { let symbol = kernel32::GetProcAddress(self.0, symbol.cstring_ref()); if symbol.is_null() { diff --git a/src/util.rs b/src/util.rs index b05d4c7..304b2d5 100644 --- a/src/util.rs +++ b/src/util.rs @@ -26,22 +26,19 @@ impl ::std::fmt::Display for NullError { } } -pub struct CheckedCStr<'a> { - s: Option, - p: Option<&'a raw::c_char> +pub enum CowCString<'a> { + Owned(CString), + Ref(&'a raw::c_char) } -impl<'a> CheckedCStr<'a> { +impl<'a> CowCString<'a> { /// Checks for last byte and avoids alocatting if its zero. /// /// Non-last null bytes still result in an error. - pub fn from_bytes(slice: &'a [u8]) -> Result, NullError> { + pub fn from_bytes(slice: &'a [u8]) -> Result, NullError> { Ok(if slice.len() == 0 { static ZERO: raw::c_char = 0; - CheckedCStr { - s: None, - p: Some(&ZERO) - } + CowCString::Ref(&ZERO) } else if let Some(&0) = slice.last() { // check for inner nulls for (c, i) in slice.iter().zip(0..slice.len()-2) { @@ -49,15 +46,9 @@ impl<'a> CheckedCStr<'a> { return Err(NullError(i)); } } - CheckedCStr { - s: None, - p: Some(unsafe { ::std::mem::transmute(slice.get_unchecked(0)) }), - } + CowCString::Ref(unsafe {::std::mem::transmute(slice.get_unchecked(0))}) } else { - CheckedCStr { - s: Some(try!(CString::new(slice))), - p: None - } + CowCString::Owned(try!(CString::new(slice))) }) } } @@ -72,14 +63,11 @@ impl CStringAsRef for CString { } } -impl<'a> CStringAsRef for CheckedCStr<'a> { - fn cstring_ref(&self) -> &raw::c_char { - if let Some(ref p) = self.p { - *p - } else if let Some(ref s) = self.s { - s.cstring_ref() - } else { - unreachable!() +impl<'a> CStringAsRef for CowCString<'a> { + fn cstring_ref(&self) -> &raw::c_char { + match self { + &CowCString::Ref(r) => r, + &CowCString::Owned(ref o) => o.cstring_ref() } } }