diff --git a/Cargo.toml b/Cargo.toml index d30309b..59f1636 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ fallback = [] android_system_properties = "0.1.4" [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] -core-foundation = "0.9" +core-foundation-sys = "0.8.3" [target.'cfg(target_os = "windows")'.dependencies] winapi = { version = "0.3.9", features = ["activation", "combaseapi", "objbase", "roapi", "winerror", "winstring"] } diff --git a/src/tz_macos.rs b/src/tz_macos.rs index 3d3e65a..a42c00a 100644 --- a/src/tz_macos.rs +++ b/src/tz_macos.rs @@ -1,5 +1,41 @@ +use core_foundation_sys::base::{CFRelease, CFTypeRef}; +use core_foundation_sys::string::{kCFStringEncodingUTF8, CFStringGetCStringPtr}; +use core_foundation_sys::timezone::{CFTimeZoneCopySystem, CFTimeZoneGetName}; + pub(crate) fn get_timezone_inner() -> Result { - Ok(core_foundation::timezone::CFTimeZone::system() - .name() - .to_string()) + unsafe { + Dropping::new(CFTimeZoneCopySystem()) + .and_then(|tz| Dropping::new(CFTimeZoneGetName(tz.0))) + .and_then(|name| { + let name = CFStringGetCStringPtr(name.0, kCFStringEncodingUTF8); + if name.is_null() { + None + } else { + Some(name) + } + }) + .and_then(|name| std::ffi::CStr::from_ptr(name).to_str().ok()) + .map(|name| name.to_owned()) + .ok_or(crate::GetTimezoneError::OsError) + } +} + +struct Dropping(*const T); + +impl Drop for Dropping { + #[inline] + fn drop(&mut self) { + unsafe { CFRelease(self.0 as CFTypeRef) }; + } +} + +impl Dropping { + #[inline] + unsafe fn new(v: *const T) -> Option { + if v.is_null() { + None + } else { + Some(Self(v)) + } + } }