use crate::{error::CoreWlanError, ffi};
use core::{ffi::c_char, ptr};
use std::ffi::CStr;
#[derive(Debug)]
pub struct RetainedObject {
raw: ffi::Object,
}
impl RetainedObject {
pub unsafe fn from_owned_raw(raw: ffi::Object) -> Option<Self> {
if raw.is_null() {
None
} else {
Some(Self { raw })
}
}
pub const fn as_raw(&self) -> ffi::Object {
self.raw
}
}
impl Clone for RetainedObject {
fn clone(&self) -> Self {
let raw = unsafe { ffi::cwrs_retain(self.raw) };
Self { raw }
}
}
impl Drop for RetainedObject {
fn drop(&mut self) {
unsafe {
ffi::cwrs_release(self.raw);
}
}
}
pub unsafe fn take_c_string(raw: *mut c_char) -> Option<String> {
if raw.is_null() {
return None;
}
let value = CStr::from_ptr(raw).to_string_lossy().into_owned();
ffi::cwrs_free_buffer(raw.cast());
Some(value)
}
pub unsafe fn take_data_buffer(raw: *mut u8, len: usize) -> Option<Vec<u8>> {
if raw.is_null() {
return (len == 0).then(Vec::new);
}
let slice = std::slice::from_raw_parts(raw, len);
let value = slice.to_vec();
ffi::cwrs_free_buffer(raw.cast());
Some(value)
}
pub unsafe fn take_string_object(raw: ffi::Object) -> Option<String> {
if raw.is_null() {
return None;
}
let value = take_c_string(ffi::cwrs_string_copy_utf8(raw));
ffi::cwrs_release(raw);
value
}
pub unsafe fn take_data_object(raw: ffi::Object) -> Option<Vec<u8>> {
if raw.is_null() {
return None;
}
let mut len = 0usize;
let bytes = ffi::cwrs_data_copy_bytes(raw, &mut len);
ffi::cwrs_release(raw);
take_data_buffer(bytes, len)
}
pub unsafe fn collect_array(raw: ffi::Object) -> Vec<ffi::Object> {
if raw.is_null() {
return Vec::new();
}
let count = ffi::cwrs_array_count(raw);
let mut out = Vec::with_capacity(count);
for index in 0..count {
let object = ffi::cwrs_array_object_at_index(raw, index);
if !object.is_null() {
out.push(object);
}
}
ffi::cwrs_release(raw);
out
}
pub unsafe fn collect_ordered_set(raw: ffi::Object) -> Vec<ffi::Object> {
if raw.is_null() {
return Vec::new();
}
let count = ffi::cwrs_ordered_set_count(raw);
let mut out = Vec::with_capacity(count);
for index in 0..count {
let object = ffi::cwrs_ordered_set_object_at_index(raw, index);
if !object.is_null() {
out.push(object);
}
}
ffi::cwrs_release(raw);
out
}
pub unsafe fn collect_set(raw: ffi::Object) -> Vec<ffi::Object> {
if raw.is_null() {
return Vec::new();
}
let array = ffi::cwrs_set_copy_all_objects(raw);
ffi::cwrs_release(raw);
collect_array(array)
}
pub unsafe fn bool_result(
ok: bool,
error: ffi::Object,
operation: &'static str,
) -> crate::Result<()> {
if ok {
if !error.is_null() {
ffi::cwrs_release(error);
}
return Ok(());
}
if error.is_null() {
return Err(CoreWlanError::OperationFailed(operation));
}
Err(error_from_raw(operation, error))
}
pub unsafe fn error_from_raw(operation: &'static str, error: ffi::Object) -> CoreWlanError {
let code = ffi::cwrs_error_code(error);
let domain = take_c_string(ffi::cwrs_error_domain(error))
.unwrap_or_else(|| "NSCocoaErrorDomain".to_owned());
let description = take_c_string(ffi::cwrs_error_description(error))
.unwrap_or_else(|| operation.to_owned());
ffi::cwrs_release(error);
CoreWlanError::ObjectiveCError {
operation,
code,
domain,
description,
}
}
pub const fn os_status_result(status: i32, operation: &'static str) -> crate::Result<()> {
if status == 0 {
Ok(())
} else {
Err(CoreWlanError::OsStatusError { operation, status })
}
}
pub const fn null_err<T>(what: &'static str) -> crate::Result<T> {
Err(CoreWlanError::UnexpectedNull(what))
}
pub fn to_c_string_bytes(value: &str) -> Vec<u8> {
let mut bytes = value
.as_bytes()
.iter()
.copied()
.filter(|byte| *byte != 0)
.collect::<Vec<_>>();
bytes.push(0);
bytes
}
pub fn optional_ptr<T>(value: Option<&[T]>) -> (*const T, usize) {
value.map_or((ptr::null(), 0), |slice| (slice.as_ptr(), slice.len()))
}