intercom_common/model/
comlibrary.rs1use super::*;
2use crate::prelude::*;
3
4use crate::guid::GUID;
5use syn::{LitStr, Path};
6
7#[derive(Debug, Clone)]
8pub enum LibraryItemType
9{
10 Module(Path),
11 Class(Path),
12 Interface(Path),
13}
14
15impl syn::parse::Parse for LibraryItemType
16{
17 fn parse(input: syn::parse::ParseStream) -> syn::parse::Result<Self>
18 {
19 let ident: syn::Ident = input.parse()?;
20 match ident.to_string().as_str() {
21 "module" => Ok(LibraryItemType::Module(input.parse()?)),
22 "class" => Ok(LibraryItemType::Class(input.parse()?)),
23 "interface" => Ok(LibraryItemType::Interface(input.parse()?)),
24 _ => Err(input.error(&format!(
25 "Expected 'class', 'interface' or 'module', found {}",
26 ident
27 ))),
28 }
29 }
30}
31
32intercom_attribute!(
33 ComLibraryAttr< ComLibraryAttrParam, LibraryItemType > {
34 libid : LitStr,
35 on_load : Path,
36 on_register : Path,
37 on_unregister : Path,
38 }
39);
40
41#[derive(Debug, PartialEq, Eq)]
43pub struct ComLibrary
44{
45 pub name: String,
46 pub libid: GUID,
47 pub on_load: Option<Path>,
48 pub on_register: Option<Path>,
49 pub on_unregister: Option<Path>,
50 pub coclasses: Vec<Path>,
51 pub interfaces: Vec<Path>,
52 pub submodules: Vec<Path>,
53}
54
55impl ComLibrary
56{
57 pub fn parse(crate_name: &str, attr_params: TokenStream) -> ParseResult<ComLibrary>
59 {
60 let attr: ComLibraryAttr = ::syn::parse2(attr_params)
61 .map_err(|_| ParseError::ComLibrary("Attribute syntax error".into()))?;
62
63 let libid = match attr.libid().map_err(ParseError::ComLibrary)? {
65 Some(libid) => GUID::parse(&libid.value()).map_err(ParseError::ComLibrary)?,
66 None => crate::utils::generate_libid(crate_name),
67 };
68
69 let on_load = attr.on_load().map_err(ParseError::ComLibrary)?.cloned();
70 let on_register = attr.on_register().map_err(ParseError::ComLibrary)?.cloned();
71 let on_unregister = attr
72 .on_unregister()
73 .map_err(ParseError::ComLibrary)?
74 .cloned();
75
76 let mut coclasses = vec![];
77 let mut interfaces = vec![];
78 let mut submodules = vec![];
79 for arg in attr.args().into_iter().cloned() {
80 match arg {
81 LibraryItemType::Class(cls) => coclasses.push(cls),
82 LibraryItemType::Interface(cls) => interfaces.push(cls),
83 LibraryItemType::Module(cls) => submodules.push(cls),
84 }
85 }
86
87 Ok(ComLibrary {
88 name: crate_name.to_owned(),
89 on_load,
90 on_register,
91 on_unregister,
92 coclasses,
93 interfaces,
94 submodules,
95 libid,
96 })
97 }
98}
99
100#[cfg(test)]
101mod test
102{
103 use super::*;
104
105 #[test]
106 fn parse_com_library()
107 {
108 let lib = ComLibrary::parse(
109 "library_name".into(),
110 quote!(
111 libid = "12345678-1234-1234-1234-567890ABCDEF",
112 class Foo,
113 class Bar),
114 )
115 .expect("com_library attribute parsing failed");
116
117 assert_eq!(lib.name, "library_name");
118 assert_eq!(
119 lib.libid,
120 GUID {
121 data1: 0x12345678,
122 data2: 0x1234,
123 data3: 0x1234,
124 data4: [0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF]
125 }
126 );
127 assert_eq!(lib.coclasses.len(), 2);
128 assert_eq!(lib.coclasses[0], parse_quote!(Foo));
129 assert_eq!(lib.coclasses[1], parse_quote!(Bar));
130 }
131
132 #[test]
133 fn parse_com_library_with_auto_guid()
134 {
135 let lib = ComLibrary::parse("another_library".into(), quote!(class One, class Two))
141 .expect("com_library attribute parsing failed");
142
143 assert_eq!(lib.name, "another_library");
144 assert_eq!(
145 lib.libid,
146 GUID::parse("696B2FAE-AC56-3E08-7C2C-ABAA8DB8F6E3").unwrap()
147 );
148 assert_eq!(lib.coclasses.len(), 2);
149 assert_eq!(lib.coclasses[0], parse_quote!(One));
150 assert_eq!(lib.coclasses[1], parse_quote!(Two));
151 }
152
153 #[test]
154 fn parse_com_library_with_empty_parameters()
155 {
156 let lib = ComLibrary::parse("lib".into(), quote!()).unwrap();
157 assert_eq!(lib.coclasses.len(), 0);
158 assert_eq!(
159 lib.libid,
160 GUID::parse("22EC0095-CD17-3AFD-6C4F-531464178911").unwrap()
161 );
162 }
163}