| 1 | use super::*; |
| 2 | |
| 3 | mod class; |
| 4 | mod cpp_const; |
| 5 | mod cpp_delegate; |
| 6 | mod cpp_enum; |
| 7 | mod cpp_fn; |
| 8 | mod cpp_interface; |
| 9 | mod cpp_method; |
| 10 | mod cpp_struct; |
| 11 | mod delegate; |
| 12 | mod r#enum; |
| 13 | mod interface; |
| 14 | mod method; |
| 15 | mod r#struct; |
| 16 | |
| 17 | pub use class::*; |
| 18 | pub use cpp_const::*; |
| 19 | pub use cpp_delegate::*; |
| 20 | pub use cpp_enum::*; |
| 21 | pub use cpp_fn::*; |
| 22 | pub use cpp_interface::*; |
| 23 | pub use cpp_method::*; |
| 24 | pub use cpp_struct::*; |
| 25 | pub use delegate::*; |
| 26 | pub use interface::*; |
| 27 | pub use method::*; |
| 28 | pub use r#enum::*; |
| 29 | pub use r#struct::*; |
| 30 | |
| 31 | #[derive (Clone, Debug, PartialEq, Eq, Hash)] |
| 32 | pub enum Type { |
| 33 | CppFn(CppFn), |
| 34 | Class(Class), |
| 35 | Interface(Interface), |
| 36 | CppInterface(CppInterface), |
| 37 | Delegate(Delegate), |
| 38 | CppDelegate(CppDelegate), |
| 39 | Enum(Enum), |
| 40 | CppEnum(CppEnum), |
| 41 | Struct(Struct), |
| 42 | CppStruct(CppStruct), |
| 43 | CppConst(CppConst), |
| 44 | |
| 45 | Param(&'static str), |
| 46 | PtrMut(Box<Self>, usize), |
| 47 | PtrConst(Box<Self>, usize), |
| 48 | ArrayFixed(Box<Self>, usize), |
| 49 | Array(Box<Self>), |
| 50 | ArrayRef(Box<Self>), |
| 51 | ConstRef(Box<Self>), |
| 52 | PrimitiveOrEnum(Box<Self>, Box<Self>), |
| 53 | |
| 54 | Void, |
| 55 | Bool, |
| 56 | Char, |
| 57 | I8, |
| 58 | U8, |
| 59 | I16, |
| 60 | U16, |
| 61 | I32, |
| 62 | U32, |
| 63 | I64, |
| 64 | U64, |
| 65 | F32, |
| 66 | F64, |
| 67 | ISize, |
| 68 | USize, |
| 69 | String, |
| 70 | Object, |
| 71 | Type, |
| 72 | |
| 73 | PSTR, |
| 74 | PCSTR, |
| 75 | PWSTR, |
| 76 | PCWSTR, |
| 77 | GUID, |
| 78 | HRESULT, |
| 79 | IUnknown, |
| 80 | BSTR, |
| 81 | } |
| 82 | |
| 83 | impl Ord for Type { |
| 84 | fn cmp(&self, other: &Self) -> Ordering { |
| 85 | self.sort_key().cmp(&(other.sort_key())) |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | impl PartialOrd for Type { |
| 90 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
| 91 | Some(self.cmp(other)) |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | #[derive (PartialEq)] |
| 96 | pub enum Remap { |
| 97 | Type(Type), |
| 98 | Name(TypeName), |
| 99 | None, |
| 100 | } |
| 101 | |
| 102 | impl Type { |
| 103 | fn sort_key(&self) -> (bool, TypeName, i32, i32) { |
| 104 | // This sorts types as follows: |
| 105 | // 1. functions are placed first |
| 106 | // 2. type name |
| 107 | // 3. type namespace |
| 108 | // 4. architecture |
| 109 | // 5. overloaded types |
| 110 | |
| 111 | let kind = match self { |
| 112 | Self::CppFn(..) => 0, |
| 113 | Self::Class(..) => 1, |
| 114 | Self::Interface(..) => 2, |
| 115 | Self::CppInterface(..) => 3, |
| 116 | Self::Delegate(..) => 4, |
| 117 | Self::CppDelegate(..) => 5, |
| 118 | Self::Enum(..) => 6, |
| 119 | Self::CppEnum(..) => 7, |
| 120 | Self::Struct(..) => 8, |
| 121 | Self::CppStruct(..) => 9, |
| 122 | Self::CppConst(..) => 10, |
| 123 | _ => -1, |
| 124 | }; |
| 125 | |
| 126 | let arches = match self { |
| 127 | Self::CppFn(ty) => ty.method.arches(), |
| 128 | Self::CppStruct(ty) => ty.def.arches(), |
| 129 | Self::CppDelegate(ty) => ty.def.arches(), |
| 130 | _ => 0, |
| 131 | }; |
| 132 | |
| 133 | (kind != 0, self.type_name(), arches, kind) |
| 134 | } |
| 135 | |
| 136 | fn is_intrinsic(&self) -> bool { |
| 137 | matches!( |
| 138 | self, |
| 139 | Self::Param(..) |
| 140 | | Self::Void |
| 141 | | Self::Bool |
| 142 | | Self::Char |
| 143 | | Self::I8 |
| 144 | | Self::U8 |
| 145 | | Self::I16 |
| 146 | | Self::U16 |
| 147 | | Self::I32 |
| 148 | | Self::U32 |
| 149 | | Self::I64 |
| 150 | | Self::U64 |
| 151 | | Self::F32 |
| 152 | | Self::F64 |
| 153 | | Self::ISize |
| 154 | | Self::USize |
| 155 | ) |
| 156 | } |
| 157 | |
| 158 | pub fn remap(type_name: TypeName) -> Remap { |
| 159 | match type_name { |
| 160 | TypeName::GUID => Remap::Type(Self::GUID), |
| 161 | TypeName::HResult => Remap::Type(Self::HRESULT), |
| 162 | TypeName::HRESULT => Remap::Type(Self::HRESULT), |
| 163 | TypeName::PSTR => Remap::Type(Self::PSTR), |
| 164 | TypeName::PWSTR => Remap::Type(Self::PWSTR), |
| 165 | TypeName::HSTRING => Remap::Type(Self::String), |
| 166 | TypeName::BSTR => Remap::Type(Self::BSTR), |
| 167 | TypeName::IInspectable => Remap::Type(Self::Object), |
| 168 | TypeName::CHAR => Remap::Type(Self::I8), |
| 169 | TypeName::BOOLEAN => Remap::Type(Self::Bool), |
| 170 | TypeName::IUnknown => Remap::Type(Self::IUnknown), |
| 171 | TypeName::Type => Remap::Type(Self::Type), |
| 172 | TypeName::EventRegistrationToken => Remap::Type(Type::I64), |
| 173 | |
| 174 | TypeName::D2D_MATRIX_3X2_F => Remap::Name(TypeName::Matrix3x2), |
| 175 | TypeName::D3DMATRIX => Remap::Name(TypeName::Matrix4x4), |
| 176 | |
| 177 | _ => Remap::None, |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | pub fn from_element_type(code: usize) -> Option<Self> { |
| 182 | match code as u8 { |
| 183 | ELEMENT_TYPE_VOID => Some(Self::Void), |
| 184 | ELEMENT_TYPE_BOOLEAN => Some(Self::Bool), |
| 185 | ELEMENT_TYPE_CHAR => Some(Self::Char), |
| 186 | ELEMENT_TYPE_I1 => Some(Self::I8), |
| 187 | ELEMENT_TYPE_U1 => Some(Self::U8), |
| 188 | ELEMENT_TYPE_I2 => Some(Self::I16), |
| 189 | ELEMENT_TYPE_U2 => Some(Self::U16), |
| 190 | ELEMENT_TYPE_I4 => Some(Self::I32), |
| 191 | ELEMENT_TYPE_U4 => Some(Self::U32), |
| 192 | ELEMENT_TYPE_I8 => Some(Self::I64), |
| 193 | ELEMENT_TYPE_U8 => Some(Self::U64), |
| 194 | ELEMENT_TYPE_R4 => Some(Self::F32), |
| 195 | ELEMENT_TYPE_R8 => Some(Self::F64), |
| 196 | ELEMENT_TYPE_I => Some(Self::ISize), |
| 197 | ELEMENT_TYPE_U => Some(Self::USize), |
| 198 | ELEMENT_TYPE_STRING => Some(Self::String), |
| 199 | ELEMENT_TYPE_OBJECT => Some(Self::Object), |
| 200 | _ => None, |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | pub fn from_ref(code: TypeDefOrRef, enclosing: Option<&CppStruct>, generics: &[Self]) -> Self { |
| 205 | if let TypeDefOrRef::TypeSpec(def) = code { |
| 206 | let mut blob = def.blob(0); |
| 207 | return Self::from_blob_impl(&mut blob, None, generics); |
| 208 | } |
| 209 | |
| 210 | let mut code_name = code.type_name(); |
| 211 | |
| 212 | match Self::remap(code_name) { |
| 213 | Remap::Type(ty) => return ty, |
| 214 | Remap::Name(type_name) => { |
| 215 | code_name = type_name; |
| 216 | } |
| 217 | Remap::None => {} |
| 218 | } |
| 219 | |
| 220 | if let Some(outer) = enclosing { |
| 221 | if code_name.namespace().is_empty() { |
| 222 | return Type::CppStruct(outer.nested[code_name.name()].clone()); |
| 223 | } |
| 224 | } |
| 225 | |
| 226 | code.reader() |
| 227 | .unwrap_full_name(code_name.namespace(), code_name.name()) |
| 228 | } |
| 229 | |
| 230 | pub fn from_blob(blob: &mut Blob, enclosing: Option<&CppStruct>, generics: &[Self]) -> Self { |
| 231 | // Used by WinRT to indicate that a struct input parameter is passed by reference rather than by value on the ABI. |
| 232 | let is_const = blob.read_modifiers().iter().any(|def| { |
| 233 | let type_name = def.type_name(); |
| 234 | type_name == TypeName::IsConst |
| 235 | }); |
| 236 | |
| 237 | // Used by WinRT to indicate an output parameter, but there are other ways to determine this direction so here |
| 238 | // it is only used to distinguish between slices and heap-allocated arrays. |
| 239 | let is_ref = blob.try_read(ELEMENT_TYPE_BYREF as usize); |
| 240 | |
| 241 | if blob.try_read(ELEMENT_TYPE_VOID as usize) { |
| 242 | return Self::Void; |
| 243 | } |
| 244 | |
| 245 | let is_array = blob.try_read(ELEMENT_TYPE_SZARRAY as usize); // Used by WinRT to indicate an array |
| 246 | |
| 247 | let mut pointers = 0; |
| 248 | |
| 249 | while blob.try_read(ELEMENT_TYPE_PTR as usize) { |
| 250 | pointers += 1; |
| 251 | } |
| 252 | |
| 253 | let kind = Self::from_blob_impl(blob, enclosing, generics); |
| 254 | |
| 255 | if pointers > 0 { |
| 256 | Self::PtrMut(Box::new(kind), pointers) |
| 257 | } else if is_const { |
| 258 | Self::ConstRef(Box::new(kind)) |
| 259 | } else if is_array { |
| 260 | if is_ref { |
| 261 | Self::ArrayRef(Box::new(kind)) |
| 262 | } else { |
| 263 | Self::Array(Box::new(kind)) |
| 264 | } |
| 265 | } else { |
| 266 | kind |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | fn from_blob_impl(blob: &mut Blob, enclosing: Option<&CppStruct>, generics: &[Self]) -> Self { |
| 271 | let code = blob.read_usize(); |
| 272 | |
| 273 | if let Some(code) = Self::from_element_type(code) { |
| 274 | return code; |
| 275 | } |
| 276 | |
| 277 | match code as u8 { |
| 278 | ELEMENT_TYPE_VALUETYPE | ELEMENT_TYPE_CLASS => { |
| 279 | Self::from_ref(blob.decode(), enclosing, generics) |
| 280 | } |
| 281 | ELEMENT_TYPE_VAR => generics |
| 282 | .get(blob.read_usize()) |
| 283 | .unwrap_or(&Self::Void) |
| 284 | .clone(), |
| 285 | ELEMENT_TYPE_ARRAY => { |
| 286 | let kind = Self::from_blob(blob, enclosing, generics); |
| 287 | let _rank = blob.read_usize(); |
| 288 | let _count = blob.read_usize(); |
| 289 | let bounds = blob.read_usize(); |
| 290 | Self::ArrayFixed(Box::new(kind), bounds) |
| 291 | } |
| 292 | ELEMENT_TYPE_GENERICINST => { |
| 293 | blob.read_usize(); // ELEMENT_TYPE_VALUETYPE or ELEMENT_TYPE_CLASS |
| 294 | |
| 295 | let code = blob.decode::<TypeDefOrRef>(); |
| 296 | let code_name = code.type_name(); |
| 297 | |
| 298 | let mut ty = blob |
| 299 | .reader() |
| 300 | .unwrap_full_name(code_name.namespace(), code_name.name()); |
| 301 | |
| 302 | let mut item_generics = vec![]; |
| 303 | |
| 304 | for _ in 0..blob.read_usize() { |
| 305 | item_generics.push(Self::from_blob_impl(blob, enclosing, generics)); |
| 306 | } |
| 307 | |
| 308 | ty.set_generics(item_generics); |
| 309 | ty |
| 310 | } |
| 311 | rest => panic!(" {rest:?}" ), |
| 312 | } |
| 313 | } |
| 314 | |
| 315 | pub fn to_const_type(&self) -> Self { |
| 316 | match self { |
| 317 | Self::PtrMut(ty, pointers) => Self::PtrMut(Box::new(ty.to_const_type()), *pointers), |
| 318 | Self::PtrConst(ty, pointers) => Self::PtrConst(Box::new(ty.to_const_type()), *pointers), |
| 319 | Self::PSTR => Self::PCSTR, |
| 320 | Self::PWSTR => Self::PCWSTR, |
| 321 | _ => self.clone(), |
| 322 | } |
| 323 | } |
| 324 | |
| 325 | pub fn to_const_ptr(&self) -> Self { |
| 326 | match self { |
| 327 | Self::PtrMut(ty, pointers) => Self::PtrConst(ty.clone(), *pointers), |
| 328 | _ => self.clone(), |
| 329 | } |
| 330 | } |
| 331 | |
| 332 | pub fn deref(&self) -> Self { |
| 333 | match self { |
| 334 | Self::PtrConst(ty, 1) | Self::PtrMut(ty, 1) => { |
| 335 | if **ty == Self::Void { |
| 336 | Self::U8 |
| 337 | } else { |
| 338 | *ty.clone() |
| 339 | } |
| 340 | } |
| 341 | Self::PtrConst(ty, pointers) => Self::PtrConst(ty.clone(), pointers - 1), |
| 342 | Self::PtrMut(ty, pointers) => Self::PtrMut(ty.clone(), pointers - 1), |
| 343 | Self::PSTR | Self::PCSTR => Self::U8, |
| 344 | Self::PWSTR | Self::PCWSTR => Self::U16, |
| 345 | _ => self.clone(), |
| 346 | } |
| 347 | } |
| 348 | |
| 349 | pub fn is_interface(&self) -> bool { |
| 350 | matches!( |
| 351 | self, |
| 352 | Self::Class(_) |
| 353 | | Self::Interface(_) |
| 354 | | Self::Delegate(_) |
| 355 | | Self::CppInterface(_) |
| 356 | | Self::IUnknown |
| 357 | | Self::Object |
| 358 | ) |
| 359 | } |
| 360 | |
| 361 | pub fn write_name(&self, writer: &Writer) -> TokenStream { |
| 362 | match self { |
| 363 | Self::Void => quote! { core::ffi::c_void }, |
| 364 | Self::Bool => quote! { bool }, |
| 365 | Self::Char => quote! { u16 }, |
| 366 | Self::I8 => quote! { i8 }, |
| 367 | Self::U8 => quote! { u8 }, |
| 368 | Self::I16 => quote! { i16 }, |
| 369 | Self::U16 => quote! { u16 }, |
| 370 | Self::I32 => quote! { i32 }, |
| 371 | Self::U32 => quote! { u32 }, |
| 372 | Self::I64 => quote! { i64 }, |
| 373 | Self::U64 => quote! { u64 }, |
| 374 | Self::F32 => quote! { f32 }, |
| 375 | Self::F64 => quote! { f64 }, |
| 376 | Self::ISize => quote! { isize }, |
| 377 | Self::USize => quote! { usize }, |
| 378 | Self::BSTR => { |
| 379 | let name = writer.write_core(); |
| 380 | quote! { #name BSTR } |
| 381 | } |
| 382 | Self::IUnknown => { |
| 383 | if writer.config.sys { |
| 384 | quote! { *mut core::ffi::c_void } |
| 385 | } else { |
| 386 | let name = writer.write_core(); |
| 387 | quote! { #name IUnknown } |
| 388 | } |
| 389 | } |
| 390 | Self::GUID => { |
| 391 | let name = writer.write_core(); |
| 392 | quote! { #name GUID } |
| 393 | } |
| 394 | Self::HRESULT => { |
| 395 | let name = writer.write_core(); |
| 396 | quote! { #name HRESULT } |
| 397 | } |
| 398 | Self::String => { |
| 399 | let name = writer.write_core(); |
| 400 | quote! { #name HSTRING } |
| 401 | } |
| 402 | Self::Object => { |
| 403 | if writer.config.sys { |
| 404 | quote! { *mut core::ffi::c_void } |
| 405 | } else { |
| 406 | let name = writer.write_core(); |
| 407 | quote! { #name IInspectable } |
| 408 | } |
| 409 | } |
| 410 | Self::PSTR => { |
| 411 | let name = writer.write_core(); |
| 412 | quote! { #name PSTR } |
| 413 | } |
| 414 | Self::PCSTR => { |
| 415 | let name = writer.write_core(); |
| 416 | quote! { #name PCSTR } |
| 417 | } |
| 418 | Self::PWSTR => { |
| 419 | let name = writer.write_core(); |
| 420 | quote! { #name PWSTR } |
| 421 | } |
| 422 | Self::PCWSTR => { |
| 423 | let name = writer.write_core(); |
| 424 | quote! { #name PCWSTR } |
| 425 | } |
| 426 | Self::CppInterface(ty) => ty.write_name(writer), |
| 427 | Self::Struct(ty) => ty.write_name(writer), |
| 428 | Self::Enum(ty) => ty.write_name(writer), |
| 429 | Self::Interface(ty) => ty.write_name(writer), |
| 430 | Self::CppStruct(ty) => ty.write_name(writer), |
| 431 | Self::CppEnum(ty) => ty.write_name(writer), |
| 432 | Self::CppFn(ty) => ty.write_name(writer), |
| 433 | Self::CppConst(ty) => ty.write_name(writer), |
| 434 | Self::CppDelegate(ty) => ty.write_name(writer), |
| 435 | Self::Delegate(ty) => ty.write_name(writer), |
| 436 | Self::Class(ty) => ty.write_name(writer), |
| 437 | Self::Param(param) => to_ident(param), |
| 438 | Self::PtrMut(ty, pointers) => { |
| 439 | let pointers = write_ptr_mut(*pointers); |
| 440 | let ty = ty.write_default(writer); |
| 441 | quote! { #pointers #ty } |
| 442 | } |
| 443 | Self::PtrConst(ty, pointers) => { |
| 444 | let pointers = write_ptr_const(*pointers); |
| 445 | let ty = ty.write_default(writer); |
| 446 | quote! { #pointers #ty } |
| 447 | } |
| 448 | Self::ArrayFixed(ty, len) => { |
| 449 | let name = ty.write_default(writer); |
| 450 | let len = Literal::usize_unsuffixed(*len); |
| 451 | quote! { [#name; #len] } |
| 452 | } |
| 453 | Self::Array(ty) => ty.write_name(writer), |
| 454 | Self::ArrayRef(ty) => ty.write_name(writer), |
| 455 | Self::ConstRef(ty) => ty.write_name(writer), |
| 456 | Self::PrimitiveOrEnum(primitive, ty) => { |
| 457 | if writer.config.sys { |
| 458 | primitive.write_name(writer) |
| 459 | } else { |
| 460 | ty.write_name(writer) |
| 461 | } |
| 462 | } |
| 463 | rest => panic!(" {rest:?}" ), |
| 464 | } |
| 465 | } |
| 466 | |
| 467 | pub fn write_default(&self, writer: &Writer) -> TokenStream { |
| 468 | if let Self::Array(ty) = self { |
| 469 | ty.write_default(writer) |
| 470 | } else { |
| 471 | let tokens = self.write_name(writer); |
| 472 | |
| 473 | if matches!(self, Self::Param(_)) { |
| 474 | quote! { <#tokens as windows_core::Type<#tokens>>::Default } |
| 475 | } else if self.is_interface() && !writer.config.sys { |
| 476 | quote! { Option<#tokens> } |
| 477 | } else { |
| 478 | tokens |
| 479 | } |
| 480 | } |
| 481 | } |
| 482 | |
| 483 | pub fn write_impl_name(&self, writer: &Writer) -> TokenStream { |
| 484 | match self { |
| 485 | Self::IUnknown | Self::Object => { |
| 486 | let name = writer.write_core(); |
| 487 | quote! { #name IUnknownImpl } |
| 488 | } |
| 489 | Self::CppInterface(ty) => ty.write_impl_name(writer), |
| 490 | Self::Interface(ty) => ty.write_impl_name(writer), |
| 491 | rest => panic!(" {rest:?}" ), |
| 492 | } |
| 493 | } |
| 494 | |
| 495 | pub fn write_abi(&self, writer: &Writer) -> TokenStream { |
| 496 | if writer.config.sys { |
| 497 | return self.write_default(writer); |
| 498 | } |
| 499 | |
| 500 | match self { |
| 501 | Self::IUnknown |
| 502 | | Self::Object |
| 503 | | Self::Delegate(_) |
| 504 | | Self::Class(_) |
| 505 | | Self::CppInterface(_) |
| 506 | | Self::Interface(_) |
| 507 | | Self::String |
| 508 | | Self::BSTR => quote! { *mut core::ffi::c_void }, |
| 509 | Self::ArrayFixed(ty, len) => { |
| 510 | let name = ty.write_abi(writer); |
| 511 | let len = Literal::usize_unsuffixed(*len); |
| 512 | quote! { [#name; #len] } |
| 513 | } |
| 514 | Self::Param(name) => { |
| 515 | let name = to_ident(name); |
| 516 | quote! { windows_core::AbiType<#name> } |
| 517 | } |
| 518 | Self::Struct(ty) => { |
| 519 | let name = self.write_name(writer); |
| 520 | if ty.is_copyable() { |
| 521 | name |
| 522 | } else { |
| 523 | quote! { core::mem::MaybeUninit<#name> } |
| 524 | } |
| 525 | } |
| 526 | Self::PtrMut(ty, pointers) => { |
| 527 | let ty = ty.write_abi(writer); |
| 528 | let pointers = write_ptr_mut(*pointers); |
| 529 | quote! { #pointers #ty } |
| 530 | } |
| 531 | Self::PtrConst(ty, pointers) => { |
| 532 | let ty = ty.write_abi(writer); |
| 533 | let pointers = write_ptr_const(*pointers); |
| 534 | quote! { #pointers #ty } |
| 535 | } |
| 536 | Self::PrimitiveOrEnum(ty, _) => ty.write_name(writer), |
| 537 | ty => ty.write_name(writer), |
| 538 | } |
| 539 | } |
| 540 | |
| 541 | pub fn runtime_signature(&self) -> String { |
| 542 | match self { |
| 543 | Self::Bool => "b1" .to_string(), |
| 544 | Self::Char => "c2" .to_string(), |
| 545 | Self::I8 => "i1" .to_string(), |
| 546 | Self::U8 => "u1" .to_string(), |
| 547 | Self::I16 => "i2" .to_string(), |
| 548 | Self::U16 => "u2" .to_string(), |
| 549 | Self::I32 => "i4" .to_string(), |
| 550 | Self::U32 => "u4" .to_string(), |
| 551 | Self::I64 => "i8" .to_string(), |
| 552 | Self::U64 => "u8" .to_string(), |
| 553 | Self::F32 => "f4" .to_string(), |
| 554 | Self::F64 => "f8" .to_string(), |
| 555 | Self::ISize => "is" .to_string(), |
| 556 | Self::USize => "us" .to_string(), |
| 557 | Self::String => "string" .to_string(), |
| 558 | Self::Object => "cinterface(IInspectable)" .to_string(), |
| 559 | Self::GUID => "g16" .to_string(), |
| 560 | Self::HRESULT => "struct(Windows.Foundation.HResult;i4)" .to_string(), |
| 561 | Self::Class(ty) => ty.runtime_signature(), |
| 562 | Self::Delegate(ty) => ty.runtime_signature(), |
| 563 | Self::Enum(ty) => ty.runtime_signature(), |
| 564 | Self::Interface(ty) => ty.runtime_signature(), |
| 565 | Self::Struct(ty) => ty.runtime_signature(), |
| 566 | rest => panic!(" {rest:?}" ), |
| 567 | } |
| 568 | } |
| 569 | |
| 570 | pub fn split_generic(&self) -> (Type, Vec<Type>) { |
| 571 | match self { |
| 572 | Self::Interface(ty) if !ty.generics.is_empty() => { |
| 573 | let base = ty |
| 574 | .def |
| 575 | .reader() |
| 576 | .unwrap_full_name(ty.def.namespace(), ty.def.name()); |
| 577 | (base, ty.generics.clone()) |
| 578 | } |
| 579 | Self::Delegate(ty) if !ty.generics.is_empty() => { |
| 580 | let base = ty |
| 581 | .def |
| 582 | .reader() |
| 583 | .unwrap_full_name(ty.def.namespace(), ty.def.name()); |
| 584 | (base, ty.generics.clone()) |
| 585 | } |
| 586 | _ => (self.clone(), vec![]), |
| 587 | } |
| 588 | } |
| 589 | |
| 590 | pub fn decay(&self) -> &Self { |
| 591 | match self { |
| 592 | Type::PtrMut(ty, _) => ty, |
| 593 | Type::PtrConst(ty, _) => ty, |
| 594 | Type::ArrayFixed(ty, _) => ty.decay(), |
| 595 | Type::Array(ty) => ty, |
| 596 | Type::ArrayRef(ty) => ty, |
| 597 | Type::ConstRef(ty) => ty, |
| 598 | Type::PrimitiveOrEnum(_, ty) => ty, |
| 599 | _ => self, |
| 600 | } |
| 601 | } |
| 602 | |
| 603 | pub fn dependencies(&self, dependencies: &mut TypeMap) { |
| 604 | let ty = self.decay(); |
| 605 | |
| 606 | if ty.is_intrinsic() { |
| 607 | return; |
| 608 | } |
| 609 | |
| 610 | let mut nested = false; |
| 611 | |
| 612 | if let Self::CppStruct(ty) = ty { |
| 613 | if ty.def.namespace().is_empty() { |
| 614 | nested = true; |
| 615 | } |
| 616 | } |
| 617 | |
| 618 | let (ty, generics) = ty.split_generic(); |
| 619 | |
| 620 | for ty in generics { |
| 621 | ty.dependencies(dependencies); |
| 622 | } |
| 623 | |
| 624 | if !nested && !dependencies.insert(ty.clone()) { |
| 625 | return; |
| 626 | } |
| 627 | |
| 628 | if let Some(multi) = match &ty { |
| 629 | Self::CppStruct(ty) => Some( |
| 630 | ty.def |
| 631 | .reader() |
| 632 | .with_full_name(ty.def.namespace(), ty.def.name()), |
| 633 | ), |
| 634 | Self::CppFn(ty) => Some( |
| 635 | ty.method |
| 636 | .reader() |
| 637 | .with_full_name(ty.namespace, ty.method.name()), |
| 638 | ), |
| 639 | _ => None, |
| 640 | } { |
| 641 | multi.for_each(|multi| { |
| 642 | if ty != multi { |
| 643 | multi.dependencies(dependencies) |
| 644 | } |
| 645 | }); |
| 646 | } |
| 647 | |
| 648 | match &ty { |
| 649 | Self::Class(ty) => ty.dependencies(dependencies), |
| 650 | Self::Delegate(ty) => ty.dependencies(dependencies), |
| 651 | Self::Enum(..) => {} |
| 652 | Self::Interface(ty) => ty.dependencies(dependencies), |
| 653 | Self::Struct(ty) => ty.dependencies(dependencies), |
| 654 | Self::CppConst(ty) => ty.dependencies(dependencies), |
| 655 | Self::CppDelegate(ty) => ty.dependencies(dependencies), |
| 656 | Self::CppFn(ty) => ty.dependencies(dependencies), |
| 657 | Self::CppInterface(ty) => ty.dependencies(dependencies), |
| 658 | Self::CppStruct(ty) => ty.dependencies(dependencies), |
| 659 | Self::CppEnum(ty) => ty.dependencies(dependencies), |
| 660 | |
| 661 | Self::IUnknown => { |
| 662 | Self::GUID.dependencies(dependencies); |
| 663 | Self::HRESULT.dependencies(dependencies); |
| 664 | } |
| 665 | |
| 666 | Self::Object => { |
| 667 | Self::IUnknown.dependencies(dependencies); |
| 668 | } |
| 669 | |
| 670 | _ => {} |
| 671 | } |
| 672 | } |
| 673 | |
| 674 | pub fn is_exclusive(&self) -> bool { |
| 675 | match self { |
| 676 | Self::Interface(ty) => ty.def.has_attribute("ExclusiveToAttribute" ), |
| 677 | _ => false, |
| 678 | } |
| 679 | } |
| 680 | |
| 681 | pub fn is_winrt_array(&self) -> bool { |
| 682 | matches!(self, Self::Array(_)) |
| 683 | } |
| 684 | |
| 685 | pub fn is_winrt_array_ref(&self) -> bool { |
| 686 | matches!(self, Self::ArrayRef(_)) |
| 687 | } |
| 688 | |
| 689 | pub fn is_async(&self) -> bool { |
| 690 | match self { |
| 691 | Self::Interface(ty) => ty.def.is_async(), |
| 692 | _ => false, |
| 693 | } |
| 694 | } |
| 695 | |
| 696 | pub fn is_copyable(&self) -> bool { |
| 697 | match self { |
| 698 | Self::Struct(ty) => ty.is_copyable(), |
| 699 | Self::CppStruct(ty) => ty.is_copyable(), |
| 700 | Self::Enum(_) => true, |
| 701 | Self::CppEnum(_) => true, |
| 702 | Self::CppDelegate(_) => true, |
| 703 | |
| 704 | Self::Interface(..) | Self::CppInterface(..) | Self::Class(..) | Self::Delegate(..) => { |
| 705 | false |
| 706 | } |
| 707 | |
| 708 | Self::String | Self::BSTR | Self::Object | Self::IUnknown | Self::Param(_) => false, |
| 709 | Self::ArrayFixed(ty, _) => ty.is_copyable(), |
| 710 | Self::Array(ty) => ty.is_copyable(), |
| 711 | _ => true, |
| 712 | } |
| 713 | } |
| 714 | |
| 715 | pub fn is_dropped(&self) -> bool { |
| 716 | match self { |
| 717 | Self::Struct(ty) => !ty.is_copyable(), |
| 718 | Self::CppInterface(..) => true, |
| 719 | Self::String | Self::BSTR | Self::Object | Self::IUnknown => true, |
| 720 | Self::ArrayFixed(ty, _) => ty.is_dropped(), |
| 721 | _ => false, |
| 722 | } |
| 723 | } |
| 724 | |
| 725 | pub fn is_convertible(&self) -> bool { |
| 726 | matches!( |
| 727 | self, |
| 728 | Self::Delegate(..) |
| 729 | | Self::Interface(..) |
| 730 | | Self::Class(..) |
| 731 | | Self::CppInterface(..) |
| 732 | | Self::PCSTR |
| 733 | | Self::PCWSTR |
| 734 | | Self::Object |
| 735 | | Self::IUnknown |
| 736 | | Self::Param(_) |
| 737 | ) |
| 738 | } |
| 739 | |
| 740 | pub fn is_const_ref(&self) -> bool { |
| 741 | matches!(self, Self::ConstRef(_)) |
| 742 | } |
| 743 | |
| 744 | pub fn is_primitive(&self) -> bool { |
| 745 | match self { |
| 746 | Self::Enum(_) | Self::CppEnum(_) | Self::CppDelegate(_) => true, |
| 747 | Self::CppStruct(ty) => ty.is_handle(), |
| 748 | Self::Bool |
| 749 | | Self::Char |
| 750 | | Self::I8 |
| 751 | | Self::U8 |
| 752 | | Self::I16 |
| 753 | | Self::U16 |
| 754 | | Self::I32 |
| 755 | | Self::U32 |
| 756 | | Self::I64 |
| 757 | | Self::U64 |
| 758 | | Self::F32 |
| 759 | | Self::F64 |
| 760 | | Self::ISize |
| 761 | | Self::USize |
| 762 | | Self::HRESULT |
| 763 | | Self::PtrConst(_, _) |
| 764 | | Self::PtrMut(_, _) => true, |
| 765 | _ => false, |
| 766 | } |
| 767 | } |
| 768 | |
| 769 | pub fn is_unsigned(&self) -> bool { |
| 770 | matches!( |
| 771 | self, |
| 772 | Self::U8 | Self::U16 | Self::U32 | Self::U64 | Self::USize |
| 773 | ) |
| 774 | } |
| 775 | |
| 776 | pub fn is_pointer(&self) -> bool { |
| 777 | matches!(self, Self::PtrConst(_, _) | Self::PtrMut(_, _)) |
| 778 | } |
| 779 | |
| 780 | pub fn has_explicit_layout(&self) -> bool { |
| 781 | match self { |
| 782 | Self::CppStruct(ty) => ty.has_explicit_layout(), |
| 783 | Self::ArrayFixed(ty, _) => ty.has_explicit_layout(), |
| 784 | _ => false, |
| 785 | } |
| 786 | } |
| 787 | |
| 788 | pub fn has_packing(&self) -> bool { |
| 789 | match self { |
| 790 | Self::CppStruct(ty) => ty.has_packing(), |
| 791 | Self::ArrayFixed(ty, _) => ty.has_packing(), |
| 792 | _ => false, |
| 793 | } |
| 794 | } |
| 795 | |
| 796 | pub fn is_byte_size(&self) -> bool { |
| 797 | match self { |
| 798 | Self::PtrConst(ty, _) | Self::PtrMut(ty, _) => ty.is_byte_size(), |
| 799 | Self::I8 | Self::U8 | Self::PSTR | Self::PCSTR => true, |
| 800 | _ => false, |
| 801 | } |
| 802 | } |
| 803 | |
| 804 | pub fn is_void(&self) -> bool { |
| 805 | match self { |
| 806 | Type::PtrConst(ty, _) | Type::PtrMut(ty, _) => ty.is_void(), |
| 807 | Type::Void => true, |
| 808 | _ => false, |
| 809 | } |
| 810 | } |
| 811 | |
| 812 | pub fn size(&self) -> usize { |
| 813 | match self { |
| 814 | Type::I8 | Type::U8 => 1, |
| 815 | Type::I16 | Type::U16 => 2, |
| 816 | Type::I64 | Type::U64 | Type::F64 => 8, |
| 817 | Type::GUID => 16, |
| 818 | Type::ArrayFixed(ty, len) => ty.size() * len, |
| 819 | Type::PrimitiveOrEnum(ty, _) => ty.size(), |
| 820 | Self::CppStruct(ty) => ty.size(), |
| 821 | Self::Struct(ty) => ty.size(), |
| 822 | Self::CppEnum(ty) => ty.size(), |
| 823 | _ => 4, |
| 824 | } |
| 825 | } |
| 826 | |
| 827 | pub fn align(&self) -> usize { |
| 828 | match self { |
| 829 | Type::I8 | Type::U8 => 1, |
| 830 | Type::I16 | Type::U16 => 2, |
| 831 | Type::I64 | Type::U64 | Type::F64 => 8, |
| 832 | Type::ArrayFixed(ty, len) => ty.align() * len, |
| 833 | Self::CppStruct(ty) => ty.align(), |
| 834 | Self::Struct(ty) => ty.align(), |
| 835 | Self::CppEnum(ty) => ty.align(), |
| 836 | _ => 4, |
| 837 | } |
| 838 | } |
| 839 | |
| 840 | pub fn underlying_type(&self) -> Self { |
| 841 | match self { |
| 842 | Self::Struct(ty) => ty.def.underlying_type(), |
| 843 | Self::CppEnum(ty) => ty.def.underlying_type(), |
| 844 | Self::Enum(ty) => ty.def.underlying_type(), |
| 845 | Self::CppStruct(ty) => ty.def.underlying_type(), |
| 846 | Self::HRESULT => Type::I32, |
| 847 | _ => self.clone(), |
| 848 | } |
| 849 | } |
| 850 | } |
| 851 | |
| 852 | impl Type { |
| 853 | fn write_no_deps(&self, writer: &Writer) -> TokenStream { |
| 854 | if !writer.config.no_core { |
| 855 | return quote! {}; |
| 856 | } |
| 857 | |
| 858 | match self { |
| 859 | Self::HRESULT => quote! { pub type HRESULT = i32; }, |
| 860 | |
| 861 | Self::PWSTR => quote! { pub type PWSTR = *mut u16; }, |
| 862 | Self::PCSTR => quote! { pub type PCSTR = *const u8; }, |
| 863 | Self::PSTR => quote! { pub type PSTR = *mut u8; }, |
| 864 | Self::PCWSTR => quote! { pub type PCWSTR = *const u16; }, |
| 865 | Self::BSTR => quote! { pub type BSTR = *const u16; }, |
| 866 | Self::String => { |
| 867 | quote! { pub type HSTRING = *mut core::ffi::c_void; } |
| 868 | } |
| 869 | Self::GUID => quote! { |
| 870 | #[repr(C)] |
| 871 | #[derive(Clone, Copy)] |
| 872 | pub struct GUID { |
| 873 | pub data1: u32, |
| 874 | pub data2: u16, |
| 875 | pub data3: u16, |
| 876 | pub data4: [u8; 8], |
| 877 | } |
| 878 | impl GUID { |
| 879 | pub const fn from_u128(uuid: u128) -> Self { |
| 880 | Self { data1: (uuid >> 96) as u32, data2: (uuid >> 80 & 0xffff) as u16, data3: (uuid >> 64 & 0xffff) as u16, data4: (uuid as u64).to_be_bytes() } |
| 881 | } |
| 882 | } |
| 883 | }, |
| 884 | Self::IUnknown => quote! { |
| 885 | pub const IID_IUnknown: GUID = GUID::from_u128(0x00000000_0000_0000_c000_000000000046); |
| 886 | #[repr(C)] |
| 887 | pub struct IUnknown_Vtbl { |
| 888 | pub QueryInterface: unsafe extern "system" fn(this: *mut core::ffi::c_void, iid: *const GUID, interface: *mut *mut core::ffi::c_void) -> HRESULT, |
| 889 | pub AddRef: unsafe extern "system" fn(this: *mut core::ffi::c_void) -> u32, |
| 890 | pub Release: unsafe extern "system" fn(this: *mut core::ffi::c_void) -> u32, |
| 891 | } |
| 892 | }, |
| 893 | Self::Object => quote! { |
| 894 | pub const IID_IInspectable: GUID = GUID::from_u128(0xaf86e2e0_b12d_4c6a_9c5a_d7aa65101e90); |
| 895 | #[repr(C)] |
| 896 | pub struct IInspectable_Vtbl { |
| 897 | pub base: IUnknown_Vtbl, |
| 898 | pub GetIids: unsafe extern "system" fn(this: *mut core::ffi::c_void, count: *mut u32, values: *mut *mut GUID) -> HRESULT, |
| 899 | pub GetRuntimeClassName: unsafe extern "system" fn(this: *mut core::ffi::c_void, value: *mut *mut core::ffi::c_void) -> HRESULT, |
| 900 | pub GetTrustLevel: unsafe extern "system" fn(this: *mut core::ffi::c_void, value: *mut i32) -> HRESULT, |
| 901 | } |
| 902 | }, |
| 903 | |
| 904 | _ => quote! {}, |
| 905 | } |
| 906 | } |
| 907 | |
| 908 | pub fn write(&self, writer: &Writer) -> TokenStream { |
| 909 | match self { |
| 910 | Self::Struct(ty) => ty.write(writer), |
| 911 | Self::Enum(ty) => ty.write(writer), |
| 912 | Self::Interface(ty) => ty.write(writer), |
| 913 | Self::CppStruct(ty) => ty.write(writer), |
| 914 | Self::CppEnum(ty) => ty.write(writer), |
| 915 | Self::CppFn(ty) => ty.write(writer), |
| 916 | Self::CppConst(ty) => ty.write(writer), |
| 917 | Self::CppDelegate(ty) => ty.write(writer), |
| 918 | Self::Delegate(ty) => ty.write(writer), |
| 919 | Self::Class(ty) => ty.write(writer), |
| 920 | Self::CppInterface(ty) => ty.write(writer), |
| 921 | |
| 922 | _ => self.write_no_deps(writer), |
| 923 | } |
| 924 | } |
| 925 | |
| 926 | pub fn set_generics(&mut self, generics: Vec<Type>) { |
| 927 | match self { |
| 928 | Self::Interface(ty) => ty.generics = generics, |
| 929 | Self::Delegate(ty) => ty.generics = generics, |
| 930 | rest => panic!(" {rest:?}" ), |
| 931 | } |
| 932 | } |
| 933 | |
| 934 | pub fn type_name(&self) -> TypeName { |
| 935 | match self { |
| 936 | Self::Class(ty) => ty.type_name(), |
| 937 | Self::Delegate(ty) => ty.type_name(), |
| 938 | Self::Enum(ty) => ty.type_name(), |
| 939 | Self::Interface(ty) => ty.type_name(), |
| 940 | Self::Struct(ty) => ty.type_name(), |
| 941 | Self::CppDelegate(ty) => ty.type_name(), |
| 942 | Self::CppEnum(ty) => ty.type_name(), |
| 943 | Self::CppInterface(ty) => ty.type_name(), |
| 944 | Self::CppStruct(ty) => ty.type_name(), |
| 945 | Self::CppConst(ty) => ty.type_name(), |
| 946 | Self::CppFn(ty) => ty.type_name(), |
| 947 | |
| 948 | Self::PSTR => TypeName("" , "PSTR" ), |
| 949 | Self::PCSTR => TypeName("" , "PCSTR" ), |
| 950 | Self::PWSTR => TypeName("" , "PWSTR" ), |
| 951 | Self::PCWSTR => TypeName("" , "PCWSTR" ), |
| 952 | Self::GUID => TypeName("" , "GUID" ), |
| 953 | Self::HRESULT => TypeName("" , "HRESULT" ), |
| 954 | Self::IUnknown => TypeName("" , "IUnknown" ), |
| 955 | Self::BSTR => TypeName("" , "BSTR" ), |
| 956 | Self::String => TypeName("" , "String" ), |
| 957 | Self::Object => TypeName("" , "Object" ), |
| 958 | |
| 959 | _ => TypeName("" , "" ), |
| 960 | } |
| 961 | } |
| 962 | |
| 963 | pub fn is_core(&self) -> bool { |
| 964 | matches!( |
| 965 | self, |
| 966 | Self::PSTR |
| 967 | | Self::PCSTR |
| 968 | | Self::PWSTR |
| 969 | | Self::PCWSTR |
| 970 | | Self::GUID |
| 971 | | Self::HRESULT |
| 972 | | Self::IUnknown |
| 973 | | Self::Object |
| 974 | | Self::BSTR |
| 975 | | Self::String |
| 976 | ) |
| 977 | } |
| 978 | } |
| 979 | |
| 980 | pub fn interface_signature(def: TypeDef, generics: &[Type]) -> String { |
| 981 | if generics.is_empty() { |
| 982 | let guid: GUID = def.guid_attribute().unwrap(); |
| 983 | format!(" {{{guid}}}" ) |
| 984 | } else { |
| 985 | let guid: GUID = def.guid_attribute().unwrap(); |
| 986 | let mut signature: String = format!("pinterface( {{{guid}}}" ); |
| 987 | |
| 988 | for generic: &Type in generics { |
| 989 | signature.push(ch:';' ); |
| 990 | signature.push_str(&generic.runtime_signature()) |
| 991 | } |
| 992 | |
| 993 | signature.push(ch:')' ); |
| 994 | signature |
| 995 | } |
| 996 | } |
| 997 | |
| 998 | fn write_ptr_mut(pointers: usize) -> TokenStream { |
| 999 | "*mut " .repeat(pointers).into() |
| 1000 | } |
| 1001 | |
| 1002 | fn write_ptr_const(pointers: usize) -> TokenStream { |
| 1003 | "*const " .repeat(pointers).into() |
| 1004 | } |
| 1005 | |