use std::marker::PhantomData;
use std::rc::Rc;
use wxdragon_sys as ffi;
#[derive(Debug)]
pub struct DateTime {
ptr: *mut ffi::wxd_DateTime_t,
owned: bool,
_nosend_nosync: PhantomData<Rc<()>>,
}
use std::io::{Error, ErrorKind::InvalidInput};
impl TryFrom<DateTime> for *const ffi::wxd_DateTime_t {
type Error = std::io::Error;
fn try_from(dt: DateTime) -> Result<Self, Self::Error> {
if dt.ptr.is_null() {
Err(Error::new(InvalidInput, "DateTime pointer is null"))
} else if dt.owned {
Err(Error::new(InvalidInput, "Cannot convert owned DateTime to const pointer"))
} else {
let ptr = dt.ptr as *const ffi::wxd_DateTime_t;
std::mem::forget(dt); Ok(ptr)
}
}
}
impl TryFrom<DateTime> for *mut ffi::wxd_DateTime_t {
type Error = std::io::Error;
fn try_from(dt: DateTime) -> Result<Self, Self::Error> {
if dt.ptr.is_null() {
Err(Error::new(InvalidInput, "DateTime pointer is null"))
} else if dt.owned {
let ptr = dt.ptr;
std::mem::forget(dt); Ok(ptr)
} else {
Err(Error::new(
InvalidInput,
"Cannot convert non-owned DateTime to mutable pointer",
))
}
}
}
impl From<*mut ffi::wxd_DateTime_t> for DateTime {
fn from(ptr: *mut ffi::wxd_DateTime_t) -> Self {
assert!(!ptr.is_null(), "invalid null pointer passed to DateTime::from");
Self {
ptr,
owned: true,
_nosend_nosync: PhantomData,
}
}
}
impl From<*const ffi::wxd_DateTime_t> for DateTime {
fn from(ptr: *const ffi::wxd_DateTime_t) -> Self {
assert!(!ptr.is_null(), "invalid null pointer passed to DateTime::from");
Self {
ptr: ptr as *mut _,
owned: false,
_nosend_nosync: PhantomData,
}
}
}
impl DateTime {
pub fn is_owned(&self) -> bool {
self.owned
}
pub fn new(year: i32, month: u16, day: i16, hour: i16, minute: i16, second: i16) -> Self {
if year <= 0
|| !(1..=12).contains(&month)
|| !(1..=31).contains(&day)
|| !(0..24).contains(&hour)
|| !(0..60).contains(&minute)
|| !(0..60).contains(&second)
{
return Self::default();
}
let c_month = month - 1; let ptr = unsafe { ffi::wxd_DateTime_FromComponents(year, c_month, day, hour, minute, second) };
if ptr.is_null() {
return Self::default();
}
Self {
ptr,
owned: true,
_nosend_nosync: PhantomData,
}
}
pub fn now() -> Self {
let ptr = unsafe { ffi::wxd_DateTime_Now() };
if ptr.is_null() {
Self::default()
} else {
Self {
ptr,
owned: true,
_nosend_nosync: PhantomData,
}
}
}
pub fn as_const_ptr(&self) -> *const ffi::wxd_DateTime_t {
self.ptr as *const _
}
pub fn as_mut_ptr(&mut self) -> *mut ffi::wxd_DateTime_t {
self.ptr
}
pub fn into_raw_mut(self) -> *mut ffi::wxd_DateTime_t {
self.try_into()
.expect("into_raw_mut can only be called on owning DateTime instances")
}
pub fn into_raw_const(self) -> *const ffi::wxd_DateTime_t {
self.try_into()
.expect("into_raw_const must only be used on non-owning (borrowed) wrappers")
}
pub fn year(&self) -> i32 {
unsafe { ffi::wxd_DateTime_GetYear(self.as_const_ptr()) }
}
pub fn month(&self) -> u16 {
unsafe { ffi::wxd_DateTime_GetMonth(self.as_const_ptr()) + 1 }
}
pub fn day(&self) -> i16 {
unsafe { ffi::wxd_DateTime_GetDay(self.as_const_ptr()) }
}
pub fn hour(&self) -> i16 {
unsafe { ffi::wxd_DateTime_GetHour(self.as_const_ptr()) }
}
pub fn minute(&self) -> i16 {
unsafe { ffi::wxd_DateTime_GetMinute(self.as_const_ptr()) }
}
pub fn second(&self) -> i16 {
unsafe { ffi::wxd_DateTime_GetSecond(self.as_const_ptr()) }
}
pub fn is_valid(&self) -> bool {
unsafe { ffi::wxd_DateTime_IsValid(self.as_const_ptr()) }
}
}
impl Default for DateTime {
fn default() -> Self {
let ptr = unsafe { ffi::wxd_DateTime_Default() };
assert!(!ptr.is_null(), "Failed to create default wxDateTime");
Self {
ptr,
owned: true,
_nosend_nosync: PhantomData,
}
}
}
impl Drop for DateTime {
fn drop(&mut self) {
if !self.ptr.is_null() && self.owned {
unsafe { ffi::wxd_DateTime_Destroy(self.as_mut_ptr()) };
self.ptr = std::ptr::null_mut();
}
}
}
impl Clone for DateTime {
fn clone(&self) -> Self {
let ptr = unsafe { ffi::wxd_DateTime_Clone(self.as_const_ptr()) };
assert!(!ptr.is_null(), "Failed to clone wxDateTime");
Self {
ptr,
owned: true,
_nosend_nosync: PhantomData,
}
}
}
#[cfg(test)]
mod tests {
use super::DateTime;
use wxdragon_sys as ffi;
#[test]
fn datetime_now_clone_into_raw_then_destroy() {
let dt = DateTime::now();
assert!(dt.is_owned(), "DateTime::now should produce an owned instance");
assert!(dt.is_valid(), "DateTime::now should be valid");
let clone = dt.clone();
assert!(clone.is_owned(), "cloned DateTime should be owned");
assert!(clone.is_valid(), "cloned DateTime should be valid");
let raw = clone.into_raw_mut();
assert!(!raw.is_null(), "raw pointer from into_raw_mut should be non-null");
unsafe { ffi::wxd_DateTime_Destroy(raw) };
}
}