use super::{RemoteArray, RemotePointer};
pub(crate) trait IntoBridge<Bridge> {
fn into_bridge(self) -> Bridge;
}
pub(crate) trait ToNative<Native> {
fn to_native(&self) -> Native;
}
pub(crate) trait FromNative<Native> {
fn from_native(native: &Native) -> Self
where
Self: Sized;
}
pub(crate) trait TryToNative<Native> {
fn try_to_native(&self) -> windows::core::Result<Native>;
}
pub(crate) trait TryFromNative<Native> {
fn try_from_native(native: &Native) -> windows::core::Result<Self>
where
Self: Sized;
}
pub(crate) trait TryToLocal<Local> {
fn try_to_local(&self) -> windows::core::Result<Local>;
}
impl<Native, T: TryFromNative<Native>> TryToLocal<T> for Native {
fn try_to_local(&self) -> windows::core::Result<T> {
T::try_from_native(self)
}
}
impl<Native, T: FromNative<Native>> TryFromNative<Native> for T {
fn try_from_native(native: &Native) -> windows::core::Result<Self> {
Ok(Self::from_native(native))
}
}
impl<Native, T: ToNative<Native>> TryToNative<Native> for T {
fn try_to_native(&self) -> windows::core::Result<Native> {
Ok(self.to_native())
}
}
impl<Bridge, B: IntoBridge<Bridge>> IntoBridge<Vec<Bridge>> for Vec<B> {
fn into_bridge(self) -> Vec<Bridge> {
self.into_iter().map(IntoBridge::into_bridge).collect()
}
}
impl<Bridge, B: IntoBridge<Bridge> + Clone> IntoBridge<Vec<Bridge>> for &[B] {
fn into_bridge(self) -> Vec<Bridge> {
self.iter().cloned().map(IntoBridge::into_bridge).collect()
}
}
impl<Native, T: TryToNative<Native>> TryToNative<Vec<Native>> for Vec<T> {
fn try_to_native(&self) -> windows::core::Result<Vec<Native>> {
self.iter().map(TryToNative::try_to_native).collect()
}
}
impl TryFromNative<RemoteArray<windows::core::HRESULT>> for Vec<windows::core::Result<()>> {
fn try_from_native(
native: &RemoteArray<windows::core::HRESULT>,
) -> windows::core::Result<Self> {
Ok(native.as_slice().iter().map(|v| (*v).ok()).collect())
}
}
impl<Native, T: TryFromNative<Native>> TryFromNative<RemoteArray<Native>> for Vec<T> {
fn try_from_native(native: &RemoteArray<Native>) -> windows::core::Result<Self> {
native.as_slice().iter().map(T::try_from_native).collect()
}
}
impl<Native, T: TryFromNative<Native>>
TryFromNative<(RemoteArray<Native>, RemoteArray<windows::core::HRESULT>)>
for Vec<windows::core::Result<T>>
{
fn try_from_native(
native: &(RemoteArray<Native>, RemoteArray<windows::core::HRESULT>),
) -> windows::core::Result<Self> {
let (results, errors) = native;
if results.len() != errors.len() {
return Err(windows::core::Error::new(
windows::Win32::Foundation::E_INVALIDARG,
"Results and errors arrays have different lengths",
));
}
Ok(results
.as_slice()
.iter()
.zip(errors.as_slice())
.map(|(result, error)| {
if error.is_ok() {
T::try_from_native(result)
} else {
Err((*error).into())
}
})
.collect())
}
}
impl TryFromNative<windows::Win32::Foundation::FILETIME> for std::time::SystemTime {
fn try_from_native(
native: &windows::Win32::Foundation::FILETIME,
) -> windows::core::Result<Self> {
let ft = ((native.dwHighDateTime as u64) << 32) | (native.dwLowDateTime as u64);
let duration_since_1601 = std::time::Duration::from_nanos(ft * 100);
let windows_to_unix_epoch_diff = std::time::Duration::from_secs(11_644_473_600);
let duration_since_unix_epoch = duration_since_1601
.checked_sub(windows_to_unix_epoch_diff)
.ok_or_else(|| {
windows::core::Error::new(
windows::Win32::Foundation::E_INVALIDARG,
"FILETIME is before UNIX_EPOCH",
)
})?;
Ok(std::time::UNIX_EPOCH + duration_since_unix_epoch)
}
}
#[macro_export]
macro_rules! try_from_native {
($native:expr) => {
TryFromNative::try_from_native($native)?
};
}
impl TryToNative<windows::Win32::Foundation::FILETIME> for std::time::SystemTime {
fn try_to_native(&self) -> windows::core::Result<windows::Win32::Foundation::FILETIME> {
let duration_since_unix_epoch =
self.duration_since(std::time::UNIX_EPOCH).map_err(|_| {
windows::core::Error::new(
windows::Win32::Foundation::E_INVALIDARG,
"SystemTime is before UNIX_EPOCH",
)
})?;
let duration_since_windows_epoch =
duration_since_unix_epoch + std::time::Duration::from_secs(11_644_473_600);
let ft = duration_since_windows_epoch.as_nanos() / 100;
Ok(windows::Win32::Foundation::FILETIME {
dwLowDateTime: ft as u32,
dwHighDateTime: (ft >> 32) as u32,
})
}
}
impl TryFromNative<windows::core::PWSTR> for String {
fn try_from_native(native: &windows::core::PWSTR) -> windows::core::Result<Self> {
RemotePointer::from(*native).try_into()
}
}