use crate::{
com_class, com_interface, type_system::TypeSystemName, ComBox, ComError, ComItf, ComRc,
ComResult, ExternOutput, ExternType, ForeignType, GUID,
};
use std::borrow::Cow;
#[derive(Fail, Debug)]
pub enum TypeLibError
{
#[fail(display = "COM error occurred: {}", _0)]
ComError(ComError),
}
impl From<ComError> for TypeLibError
{
fn from(s: ComError) -> Self
{
TypeLibError::ComError(s)
}
}
mod from_impls;
#[derive(Debug)]
pub struct InterfaceRef
{
pub name: Cow<'static, str>,
pub iid_automation: GUID,
pub iid_raw: GUID,
}
#[com_class(IIntercomTypeLib)]
#[derive(Debug)]
pub struct TypeLib
{
pub name: Cow<'static, str>,
pub libid: GUID,
pub version: Cow<'static, str>,
pub types: Vec<TypeInfo>,
}
#[com_interface]
pub trait IIntercomTypeLib
{
fn get_info(&self) -> ComResult<(String, GUID, String)>;
fn get_type_count(&self) -> ComResult<u32>;
fn get_type(&self, idx: u32) -> ComResult<ComRc<dyn IIntercomTypeInfo>>;
}
#[derive(Debug)]
pub enum TypeInfo
{
Class(ComBox<CoClass>),
Interface(ComBox<Interface>),
}
#[derive(ExternType, ExternOutput, ForeignType, Debug)]
#[repr(C)]
pub enum TypeInfoKind
{
CoClass,
Interface,
}
#[com_interface]
pub trait IIntercomTypeInfo
{
fn get_name(&self) -> ComResult<String>;
fn get_kind(&self) -> ComResult<TypeInfoKind>;
}
#[com_class(IIntercomTypeInfo, IIntercomCoClass)]
#[derive(Debug)]
pub struct CoClass
{
pub name: Cow<'static, str>,
pub clsid: GUID,
pub interfaces: Vec<InterfaceRef>,
}
#[com_interface]
pub trait IIntercomCoClass
{
fn get_name(&self) -> ComResult<String>;
fn get_clsid(&self) -> ComResult<GUID>;
fn get_interface_count(&self) -> ComResult<u32>;
fn get_interface_ref(&self, idx: u32, ts: TypeSystemName) -> ComResult<(String, GUID)>;
}
#[com_class(IIntercomTypeInfo, IIntercomInterface)]
#[derive(Debug)]
pub struct Interface
{
pub name: Cow<'static, str>,
pub variants: Vec<ComBox<InterfaceVariant>>,
pub options: InterfaceOptions,
}
#[derive(Debug, Clone, Default, ExternType, ExternOutput, ForeignType)]
#[repr(C)]
pub struct InterfaceOptions
{
pub class_impl_interface: bool,
pub __non_exhaustive: (),
}
#[com_class(IIntercomInterfaceVariant)]
#[derive(Debug)]
pub struct InterfaceVariant
{
pub ts: TypeSystemName,
pub iid: GUID,
pub methods: Vec<ComBox<Method>>,
}
#[com_interface]
pub trait IIntercomInterface
{
fn get_name(&self) -> ComResult<String>;
fn get_options(&self) -> ComResult<InterfaceOptions>;
fn get_variant_count(&self) -> ComResult<u32>;
fn get_variant(&self, idx: u32) -> ComResult<ComRc<dyn IIntercomInterfaceVariant>>;
}
#[com_interface]
pub trait IIntercomInterfaceVariant
{
fn get_type_system(&self) -> ComResult<TypeSystemName>;
fn get_iid(&self) -> ComResult<GUID>;
fn get_method_count(&self) -> ComResult<u32>;
fn get_method(&self, idx: u32) -> ComResult<ComRc<dyn IIntercomMethod>>;
}
#[com_class(IIntercomMethod)]
#[derive(Debug)]
pub struct Method
{
pub name: Cow<'static, str>,
pub return_type: Arg,
pub parameters: Vec<Arg>,
}
#[derive(Debug)]
pub struct Arg
{
pub name: Cow<'static, str>,
pub ty: Cow<'static, str>,
pub indirection_level: u32,
pub direction: Direction,
}
#[derive(Debug, Clone, Copy, ExternType, ExternOutput, ForeignType, PartialEq, Eq)]
#[repr(C)]
pub enum Direction
{
In,
Out,
Retval,
Return,
}
#[com_interface]
pub trait IIntercomMethod
{
fn get_name(&self) -> ComResult<String>;
fn get_return_type(&self) -> ComResult<(String, u32)>;
fn get_parameter_count(&self) -> ComResult<u32>;
fn get_parameter(&self, idx: u32) -> ComResult<(String, String, u32, Direction)>;
}
impl IIntercomTypeLib for TypeLib
{
fn get_info(&self) -> ComResult<(String, GUID, String)>
{
Ok((
self.name.to_string(),
self.libid.clone(),
self.version.to_string(),
))
}
fn get_type_count(&self) -> ComResult<u32>
{
Ok(self.types.len() as u32)
}
fn get_type(&self, idx: u32) -> ComResult<ComRc<dyn IIntercomTypeInfo>>
{
Ok(match &self.types[idx as usize] {
TypeInfo::Class(cls) => ComRc::from(cls),
TypeInfo::Interface(itf) => ComRc::from(itf),
})
}
}
impl IIntercomTypeInfo for CoClass
{
fn get_name(&self) -> ComResult<String>
{
Ok(self.name.to_string())
}
fn get_kind(&self) -> ComResult<TypeInfoKind>
{
Ok(TypeInfoKind::CoClass)
}
}
impl IIntercomCoClass for CoClass
{
fn get_name(&self) -> ComResult<String>
{
Ok(self.name.to_string())
}
fn get_clsid(&self) -> ComResult<GUID>
{
Ok(self.clsid.clone())
}
fn get_interface_count(&self) -> ComResult<u32>
{
Ok(self.interfaces.len() as u32)
}
fn get_interface_ref(&self, idx: u32, ts: TypeSystemName) -> ComResult<(String, GUID)>
{
let itf = &self.interfaces[idx as usize];
Ok((
itf.name.to_string(),
match ts {
TypeSystemName::Automation => itf.iid_automation.clone(),
TypeSystemName::Raw => itf.iid_raw.clone(),
},
))
}
}
impl IIntercomTypeInfo for Interface
{
fn get_name(&self) -> ComResult<String>
{
Ok(self.name.to_string())
}
fn get_kind(&self) -> ComResult<TypeInfoKind>
{
Ok(TypeInfoKind::Interface)
}
}
impl IIntercomInterface for Interface
{
fn get_name(&self) -> ComResult<String>
{
Ok(self.name.to_string())
}
fn get_options(&self) -> ComResult<InterfaceOptions>
{
Ok(self.options.clone())
}
fn get_variant_count(&self) -> ComResult<u32>
{
Ok(self.variants.len() as u32)
}
fn get_variant(&self, idx: u32) -> ComResult<ComRc<dyn IIntercomInterfaceVariant>>
{
Ok(ComRc::from(&self.variants[idx as usize]))
}
}
impl IIntercomInterfaceVariant for InterfaceVariant
{
fn get_type_system(&self) -> ComResult<TypeSystemName>
{
Ok(self.ts)
}
fn get_iid(&self) -> ComResult<GUID>
{
Ok(self.iid.clone())
}
fn get_method_count(&self) -> ComResult<u32>
{
Ok(self.methods.len() as u32)
}
fn get_method(&self, idx: u32) -> ComResult<ComRc<dyn IIntercomMethod>>
{
Ok(ComRc::from(&self.methods[idx as usize]))
}
}
impl IIntercomMethod for Method
{
fn get_name(&self) -> ComResult<String>
{
Ok(self.name.to_string())
}
fn get_return_type(&self) -> ComResult<(String, u32)>
{
Ok((
self.return_type.ty.to_string(),
self.return_type.indirection_level,
))
}
fn get_parameter_count(&self) -> ComResult<u32>
{
Ok(self.parameters.len() as u32)
}
fn get_parameter(&self, idx: u32) -> ComResult<(String, String, u32, Direction)>
{
let arg = &self.parameters[idx as usize];
Ok((
arg.name.to_string(),
arg.ty.to_string(),
arg.indirection_level,
arg.direction,
))
}
}
impl CoClass
{
pub fn __new(name: Cow<'static, str>, clsid: GUID, interfaces: Vec<InterfaceRef>) -> Self
{
Self {
name,
clsid,
interfaces,
}
}
}
impl TypeLib
{
pub fn __new(
name: Cow<'static, str>,
libid: GUID,
version: Cow<'static, str>,
mut types: Vec<TypeInfo>,
) -> TypeLib
{
types.sort_by_key(|item| match item {
TypeInfo::Class(cls) => ("class", cls.as_ref().name.to_string()),
TypeInfo::Interface(itf) => ("itf", itf.as_ref().name.to_string()),
});
types.dedup_by_key(|item| match item {
TypeInfo::Class(cls) => ("class", cls.as_ref().name.to_string()),
TypeInfo::Interface(itf) => ("itf", itf.as_ref().name.to_string()),
});
TypeLib {
name,
libid,
version,
types,
}
}
}