dcommon 0.3.0-alpha1

Common types and utilities for my collection for DirectX-related crates (dxgi, wic, direct2d, directwrite, direct3d11)
Documentation
use super::EnumString;
use crate::helpers::CoTaskWString;
use crate::{Error, Status};

use std::iter::Fuse;

use com_impl::Refcount;
use com_impl::VTable;
use com_wrapper::ComWrapper;
use winapi::shared::winerror::E_FAIL;
use winapi::shared::wtypesbase::LPOLESTR;
use winapi::um::objidlbase::{IEnumString, IEnumStringVtbl};

#[repr(C)]
#[derive(ComImpl)]
pub struct CustomEnumString<I>
where
    I: Iterator<Item = CoTaskWString> + 'static,
{
    vtbl: VTable<IEnumStringVtbl>,
    refcount: Refcount,
    iter: Fuse<I>,
    original: Option<Fuse<I>>,
    clone_fn: Option<fn(&Fuse<I>) -> Fuse<I>>,
}

impl<I> CustomEnumString<I>
where
    I: Iterator<Item = CoTaskWString> + Clone + 'static,
{
    pub fn create(iter: I) -> EnumString {
        let iter = iter.fuse();
        let orig = Some(iter.clone());
        let clone_fn: Option<fn(&Fuse<I>) -> Fuse<I>> = Some(<Fuse<I> as Clone>::clone);
        unsafe {
            let raw = Self::create_raw(iter, orig, clone_fn);
            let raw: *mut CustomEnumString<I> = raw;
            let raw: *mut IEnumString = raw as *mut _;
            EnumString::from_raw(raw)
        }
    }
}

impl<I> CustomEnumString<I>
where
    I: Iterator<Item = CoTaskWString> + 'static,
{
    pub fn create_without_clone(iter: I) -> EnumString {
        let iter = iter.fuse();
        unsafe {
            let raw = Self::create_raw(iter, None, None);
            let raw: *mut CustomEnumString<I> = raw;
            let raw: *mut IEnumString = raw as *mut _;
            EnumString::from_raw(raw)
        }
    }
}

#[com_impl]
unsafe impl<I> IEnumString for CustomEnumString<I>
where
    I: Iterator<Item = CoTaskWString> + 'static,
{
    #[panic(result = "E_FAIL")]
    unsafe fn next(&mut self, ce: u32, out: *mut LPOLESTR, pce: *mut u32) -> i32 {
        let mut tot = 0;
        for i in 0..ce {
            let s = match self.iter.next() {
                Some(s) => s,
                None => break,
            };
            *out.offset(i as isize) = s.into_raw();
            tot += 1;
        }
        *pce = tot;
        if tot < ce {
            Status::FALSE.0
        } else {
            Status::OK.0
        }
    }

    #[panic(result = "E_FAIL")]
    unsafe fn clone(&self, other: *mut *mut IEnumString) -> i32 {
        let clone_fn = match self.clone_fn {
            Some(f) => f,
            None => return Error::NOTIMPL.0,
        };

        let iter = clone_fn(&self.iter);
        let original = self.original.as_ref().map(clone_fn);

        let raw = Self::create_raw(iter, original, Some(clone_fn));
        let raw: *mut CustomEnumString<I> = raw;
        let raw: *mut IEnumString = raw as *mut _;
        *other = raw;

        Status::OK.0
    }

    #[panic(result = "E_FAIL")]
    unsafe fn reset(&mut self) -> i32 {
        let orig = match &self.original {
            Some(orig) => orig,
            None => return Error::NOTIMPL.0,
        };
        let clone_fn = match self.clone_fn {
            Some(f) => f,
            None => return Error::NOTIMPL.0,
        };

        self.iter = clone_fn(orig);
        Status::OK.0
    }

    #[panic(result = "E_FAIL")]
    unsafe fn skip(&mut self, count: u32) -> i32 {
        for _ in 0..count {
            self.iter.next();
        }
        Status::OK.0
    }
}