intercom/typelib/
mod.rs

1use crate::{
2    com_class, com_interface, type_system::TypeSystemName, ComBox, ComError, ComItf, ComRc,
3    ComResult, ExternOutput, ExternType, ForeignType, GUID,
4};
5
6use std::borrow::Cow;
7
8#[derive(Fail, Debug)]
9pub enum TypeLibError
10{
11    #[fail(display = "COM error occurred: {}", _0)]
12    ComError(ComError),
13}
14
15impl From<ComError> for TypeLibError
16{
17    fn from(s: ComError) -> Self
18    {
19        TypeLibError::ComError(s)
20    }
21}
22
23mod from_impls;
24
25// pub mod raw;
26// use raw::*;
27
28#[derive(Debug)]
29pub struct InterfaceRef
30{
31    pub name: Cow<'static, str>,
32    pub iid_automation: GUID,
33    pub iid_raw: GUID,
34}
35
36// TypeLib
37
38#[com_class(IIntercomTypeLib)]
39#[derive(Debug)]
40pub struct TypeLib
41{
42    pub name: Cow<'static, str>,
43    pub libid: GUID,
44    pub version: Cow<'static, str>,
45    pub types: Vec<TypeInfo>,
46}
47
48#[com_interface]
49pub trait IIntercomTypeLib
50{
51    fn get_info(&self) -> ComResult<(String, GUID, String)>;
52    fn get_type_count(&self) -> ComResult<u32>;
53    fn get_type(&self, idx: u32) -> ComResult<ComRc<dyn IIntercomTypeInfo>>;
54}
55
56// TypeInfo
57
58#[derive(Debug)]
59pub enum TypeInfo
60{
61    Class(ComBox<CoClass>),
62    Interface(ComBox<Interface>),
63}
64
65#[derive(ExternType, ExternOutput, ForeignType, Debug)]
66#[repr(C)]
67pub enum TypeInfoKind
68{
69    CoClass,
70    Interface,
71}
72
73#[com_interface]
74pub trait IIntercomTypeInfo
75{
76    fn get_name(&self) -> ComResult<String>;
77    fn get_kind(&self) -> ComResult<TypeInfoKind>;
78}
79
80// TypeInfo::CoClass
81
82#[com_class(IIntercomTypeInfo, IIntercomCoClass)]
83#[derive(Debug)]
84pub struct CoClass
85{
86    pub name: Cow<'static, str>,
87    pub clsid: GUID,
88    pub interfaces: Vec<InterfaceRef>,
89}
90
91#[com_interface]
92pub trait IIntercomCoClass
93{
94    // FIXME: Support interface inheritance
95    fn get_name(&self) -> ComResult<String>;
96
97    fn get_clsid(&self) -> ComResult<GUID>;
98    fn get_interface_count(&self) -> ComResult<u32>;
99    fn get_interface_ref(&self, idx: u32, ts: TypeSystemName) -> ComResult<(String, GUID)>;
100}
101
102// TypeInfo::Interface
103
104#[com_class(IIntercomTypeInfo, IIntercomInterface)]
105#[derive(Debug)]
106pub struct Interface
107{
108    pub name: Cow<'static, str>,
109    pub variants: Vec<ComBox<InterfaceVariant>>,
110    pub options: InterfaceOptions,
111}
112
113#[derive(Debug, Clone, Default, ExternType, ExternOutput, ForeignType)]
114#[repr(C)]
115pub struct InterfaceOptions
116{
117    pub class_impl_interface: bool,
118    pub __non_exhaustive: (),
119}
120
121#[com_class(IIntercomInterfaceVariant)]
122#[derive(Debug)]
123pub struct InterfaceVariant
124{
125    pub ts: TypeSystemName,
126    pub iid: GUID,
127    pub methods: Vec<ComBox<Method>>,
128}
129
130#[com_interface]
131pub trait IIntercomInterface
132{
133    // FIXME: Support interface inheritance
134    fn get_name(&self) -> ComResult<String>;
135    fn get_options(&self) -> ComResult<InterfaceOptions>;
136
137    fn get_variant_count(&self) -> ComResult<u32>;
138    fn get_variant(&self, idx: u32) -> ComResult<ComRc<dyn IIntercomInterfaceVariant>>;
139}
140
141#[com_interface]
142pub trait IIntercomInterfaceVariant
143{
144    fn get_type_system(&self) -> ComResult<TypeSystemName>;
145    fn get_iid(&self) -> ComResult<GUID>;
146    fn get_method_count(&self) -> ComResult<u32>;
147    fn get_method(&self, idx: u32) -> ComResult<ComRc<dyn IIntercomMethod>>;
148}
149
150// Method
151
152#[com_class(IIntercomMethod)]
153#[derive(Debug)]
154pub struct Method
155{
156    pub name: Cow<'static, str>,
157    pub return_type: Arg,
158    pub parameters: Vec<Arg>,
159}
160
161#[derive(Debug)]
162pub struct Arg
163{
164    pub name: Cow<'static, str>,
165    pub ty: Cow<'static, str>,
166    pub indirection_level: u32,
167    pub direction: Direction,
168}
169
170#[derive(Debug, Clone, Copy, ExternType, ExternOutput, ForeignType, PartialEq, Eq)]
171#[repr(C)]
172pub enum Direction
173{
174    In,
175    Out,
176    Retval,
177    Return,
178}
179
180#[com_interface]
181pub trait IIntercomMethod
182{
183    fn get_name(&self) -> ComResult<String>;
184    fn get_return_type(&self) -> ComResult<(String, u32)>;
185    fn get_parameter_count(&self) -> ComResult<u32>;
186    fn get_parameter(&self, idx: u32) -> ComResult<(String, String, u32, Direction)>;
187}
188
189// Impls
190
191impl IIntercomTypeLib for TypeLib
192{
193    fn get_info(&self) -> ComResult<(String, GUID, String)>
194    {
195        Ok((
196            self.name.to_string(),
197            self.libid.clone(),
198            self.version.to_string(),
199        ))
200    }
201
202    fn get_type_count(&self) -> ComResult<u32>
203    {
204        Ok(self.types.len() as u32)
205    }
206
207    fn get_type(&self, idx: u32) -> ComResult<ComRc<dyn IIntercomTypeInfo>>
208    {
209        Ok(match &self.types[idx as usize] {
210            TypeInfo::Class(cls) => ComRc::from(cls),
211            TypeInfo::Interface(itf) => ComRc::from(itf),
212        })
213    }
214}
215
216impl IIntercomTypeInfo for CoClass
217{
218    fn get_name(&self) -> ComResult<String>
219    {
220        Ok(self.name.to_string())
221    }
222
223    fn get_kind(&self) -> ComResult<TypeInfoKind>
224    {
225        Ok(TypeInfoKind::CoClass)
226    }
227}
228
229impl IIntercomCoClass for CoClass
230{
231    fn get_name(&self) -> ComResult<String>
232    {
233        Ok(self.name.to_string())
234    }
235
236    fn get_clsid(&self) -> ComResult<GUID>
237    {
238        Ok(self.clsid.clone())
239    }
240    fn get_interface_count(&self) -> ComResult<u32>
241    {
242        Ok(self.interfaces.len() as u32)
243    }
244
245    fn get_interface_ref(&self, idx: u32, ts: TypeSystemName) -> ComResult<(String, GUID)>
246    {
247        let itf = &self.interfaces[idx as usize];
248        Ok((
249            itf.name.to_string(),
250            match ts {
251                TypeSystemName::Automation => itf.iid_automation.clone(),
252                TypeSystemName::Raw => itf.iid_raw.clone(),
253            },
254        ))
255    }
256}
257
258impl IIntercomTypeInfo for Interface
259{
260    fn get_name(&self) -> ComResult<String>
261    {
262        Ok(self.name.to_string())
263    }
264
265    fn get_kind(&self) -> ComResult<TypeInfoKind>
266    {
267        Ok(TypeInfoKind::Interface)
268    }
269}
270
271impl IIntercomInterface for Interface
272{
273    fn get_name(&self) -> ComResult<String>
274    {
275        Ok(self.name.to_string())
276    }
277
278    fn get_options(&self) -> ComResult<InterfaceOptions>
279    {
280        Ok(self.options.clone())
281    }
282
283    fn get_variant_count(&self) -> ComResult<u32>
284    {
285        Ok(self.variants.len() as u32)
286    }
287
288    fn get_variant(&self, idx: u32) -> ComResult<ComRc<dyn IIntercomInterfaceVariant>>
289    {
290        Ok(ComRc::from(&self.variants[idx as usize]))
291    }
292}
293
294impl IIntercomInterfaceVariant for InterfaceVariant
295{
296    fn get_type_system(&self) -> ComResult<TypeSystemName>
297    {
298        Ok(self.ts)
299    }
300
301    fn get_iid(&self) -> ComResult<GUID>
302    {
303        Ok(self.iid.clone())
304    }
305
306    fn get_method_count(&self) -> ComResult<u32>
307    {
308        Ok(self.methods.len() as u32)
309    }
310
311    fn get_method(&self, idx: u32) -> ComResult<ComRc<dyn IIntercomMethod>>
312    {
313        Ok(ComRc::from(&self.methods[idx as usize]))
314    }
315}
316
317impl IIntercomMethod for Method
318{
319    fn get_name(&self) -> ComResult<String>
320    {
321        Ok(self.name.to_string())
322    }
323
324    fn get_return_type(&self) -> ComResult<(String, u32)>
325    {
326        Ok((
327            self.return_type.ty.to_string(),
328            self.return_type.indirection_level,
329        ))
330    }
331
332    fn get_parameter_count(&self) -> ComResult<u32>
333    {
334        Ok(self.parameters.len() as u32)
335    }
336    fn get_parameter(&self, idx: u32) -> ComResult<(String, String, u32, Direction)>
337    {
338        let arg = &self.parameters[idx as usize];
339        Ok((
340            arg.name.to_string(),
341            arg.ty.to_string(),
342            arg.indirection_level,
343            arg.direction,
344        ))
345    }
346}
347
348impl CoClass
349{
350    pub fn __new(name: Cow<'static, str>, clsid: GUID, interfaces: Vec<InterfaceRef>) -> Self
351    {
352        Self {
353            name,
354            clsid,
355            interfaces,
356        }
357    }
358}
359
360impl TypeLib
361{
362    pub fn __new(
363        name: Cow<'static, str>,
364        libid: GUID,
365        version: Cow<'static, str>,
366        mut types: Vec<TypeInfo>,
367    ) -> TypeLib
368    {
369        types.sort_by_key(|item| match item {
370            TypeInfo::Class(cls) => ("class", cls.as_ref().name.to_string()),
371            TypeInfo::Interface(itf) => ("itf", itf.as_ref().name.to_string()),
372        });
373        types.dedup_by_key(|item| match item {
374            TypeInfo::Class(cls) => ("class", cls.as_ref().name.to_string()),
375            TypeInfo::Interface(itf) => ("itf", itf.as_ref().name.to_string()),
376        });
377        TypeLib {
378            name,
379            libid,
380            version,
381            types,
382        }
383    }
384}