1mod parse;
2#[cfg(test)]
3mod tests;
4
5use log::debug;
6use petgraph::Direction;
7use proc_macro2::{Span, TokenStream};
8use rustc_hash::FxHashSet;
9use smol_str::SmolStr;
10use std::{cell::RefCell, convert::TryInto, fmt::Write, rc::Rc};
11use syn::{
12 spanned::Spanned,
13 visit_mut::{visit_type_mut, VisitMut},
14 LitStr, Type,
15};
16
17use crate::{
18 error::{invalid_src_id_span, DiagnosticError, Result, SourceIdSpan},
19 source_registry::SourceId,
20 typemap::{
21 ast::{
22 get_trait_bounds, is_second_subst_of_first, normalize_type, parse_ty_with_given_span,
23 DisplayToTokens, GenericTypeConv, SpannedSmolStr, TyParamsSubstMap,
24 },
25 ty::TraitNamesSet,
26 TypeConvCode, UniqueName,
27 },
28 WRITE_TO_MEM_FAILED_MSG,
29};
30use parse::CItemsList;
31
32pub(crate) use parse::MacroArgs;
33
34static GENERIC_ALIAS: &str = "generic_alias";
35static SWIG_CONCAT_IDENTS: &str = "swig_concat_idents";
36static SWIG_I_TYPE: &str = "swig_i_type";
37static DEFINE_C_TYPE: &str = "define_c_type";
38static SWIG_FROM_RUST_TO_I_TYPE: &str = "swig_from_rust_to_i_type";
39static SWIG_FROM_I_TYPE_TO_RUST: &str = "swig_from_i_type_to_rust";
40static SWIG_FOREIGN_TO_I_TYPE: &str = "swig_foreign_to_i_type";
41static SWIG_FOREIGN_FROM_I_TYPE: &str = "swig_foreign_from_i_type";
42static SWIG_F_TYPE: &str = "swig_f_type";
43pub(in crate::typemap) static SWIG_SUBST_TYPE: &str = "swig_subst_type";
44
45#[derive(Debug)]
46pub(crate) struct TypeMapConvRuleInfo {
47 pub src_id: SourceId,
48 pub span: Span,
49 pub rtype_generics: Option<syn::Generics>,
50 pub rtype_left_to_right: Option<RTypeConvRule>,
51 pub rtype_right_to_left: Option<RTypeConvRule>,
52 pub ftype_left_to_right: Vec<FTypeConvRule>,
53 pub ftype_right_to_left: Vec<FTypeConvRule>,
54 pub c_types: Option<CItems>,
56 pub generic_c_types: Option<GenericCItems>,
57 pub f_code: Vec<ForeignCode>,
58 pub generic_aliases: Vec<GenericAlias>,
59}
60
61#[derive(Debug, Clone, PartialEq)]
62pub(crate) enum CItem {
63 Struct(syn::ItemStruct),
64 Union(syn::ItemUnion),
65 Fn(syn::ItemFn),
66 Static(syn::ItemStatic),
67}
68
69#[derive(Debug, Clone, PartialEq)]
70pub(crate) struct CItems {
71 pub header_name: SmolStr,
72 pub items: Vec<CItem>,
73}
74
75#[derive(Debug, Clone)]
76pub(crate) struct ForeignCode {
77 pub sp: Span,
78 pub module_name: SmolStr,
79 pub cfg_option: Option<SpannedSmolStr>,
80 pub code: String,
81}
82
83#[derive(Debug)]
84pub(crate) struct GenericAlias {
85 pub alias: syn::Ident,
86 pub value: TokenStream,
87}
88
89#[derive(Debug, Clone)]
90pub(crate) struct ModuleName {
91 pub name: SmolStr,
92 pub sp: Span,
93}
94
95impl PartialEq for ModuleName {
96 fn eq(&self, other: &Self) -> bool {
97 self.name == other.name
98 }
99}
100
101impl Eq for ModuleName {}
102
103impl Ord for ModuleName {
104 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
105 self.name.cmp(&other.name)
106 }
107}
108
109impl PartialOrd for ModuleName {
110 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
111 Some(self.name.cmp(&other.name))
112 }
113}
114
115#[derive(Debug)]
116pub(crate) struct GenericCItems {
117 pub header_name: ModuleName,
118 pub types: TokenStream,
119}
120
121impl TypeMapConvRuleInfo {
122 pub(crate) fn is_empty(&self) -> bool {
123 self.rtype_generics.is_none()
124 && self.rtype_left_to_right.is_none()
125 && self.rtype_right_to_left.is_none()
126 && self.ftype_left_to_right.is_empty()
127 && self.ftype_right_to_left.is_empty()
128 && self.c_types.is_none()
129 && self.generic_c_types.is_none()
130 && self.f_code.is_empty()
131 && self.generic_aliases.is_empty()
132 }
133 pub(crate) fn if_simple_rtype_ftype_map(
134 &self,
135 ) -> Option<(&Type, &FTypeName, &[ModuleName], Option<&SpannedSmolStr>)> {
136 if self.rtype_right_to_left.is_some()
137 || !self.ftype_right_to_left.is_empty()
138 || self.ftype_left_to_right.len() > 1
139 {
140 return None;
141 }
142 match (
143 self.rtype_left_to_right.as_ref(),
144 self.ftype_left_to_right.first(),
145 ) {
146 (
147 Some(RTypeConvRule {
148 left_ty: ref r_ty,
149 right_ty: None,
150 code: None,
151 }),
152 Some(FTypeConvRule {
153 left_right_ty: FTypeLeftRightPair::OnlyLeft(ref f_ty),
154 code: None,
155 ref req_modules,
156 ref unique_prefix,
157 ..
158 }),
159 ) => Some((r_ty, f_ty, req_modules.as_slice(), unique_prefix.as_ref())),
160 _ => None,
161 }
162 }
163
164 pub(crate) fn if_simple_rtype_ftype_map_no_lang_backend(
166 &self,
167 ) -> Option<(&Type, &FTypeName, &[ModuleName], Option<&SpannedSmolStr>)> {
168 if !self.f_code.is_empty() || self.c_types.is_some() {
169 return None;
170 }
171
172 self.if_simple_rtype_ftype_map()
173 }
174
175 pub(in crate::typemap) fn contains_data_for_language_backend(&self) -> bool {
176 self.is_generic()
177 || !self.f_code.is_empty()
178 || self.c_types.is_some()
179 || self
180 .ftype_left_to_right
181 .iter()
182 .any(|x| x.cfg_option.is_some())
183 || self
184 .ftype_right_to_left
185 .iter()
186 .any(|x| x.cfg_option.is_some())
187 || self.ftype_left_to_right.len() > 1
188 || self.ftype_right_to_left.len() > 1
189 }
190
191 pub(crate) fn is_generic(&self) -> bool {
192 self.rtype_generics.is_some()
193 }
194
195 pub(crate) fn is_ty_subst_of_my_generic_rtype<TraitChecker>(
196 &self,
197 ty: &Type,
198 direction: Direction,
199 impl_trait: TraitChecker,
200 ) -> Option<TyParamsSubstMap<'_>>
201 where
202 TraitChecker: Fn(&Type, &TraitNamesSet) -> bool,
203 {
204 assert!(self.is_generic());
205 let generic_ty = if let Some((r_type, _, _, _)) = self.if_simple_rtype_ftype_map() {
206 r_type
207 } else {
208 let rule = match direction {
209 Direction::Incoming => self.rtype_right_to_left.as_ref(),
210 Direction::Outgoing => self.rtype_left_to_right.as_ref(),
211 };
212 let rule = rule?;
213 &rule.left_ty
214 };
215
216 let generics = self
217 .rtype_generics
218 .as_ref()
219 .expect("Internal error: should used only for generics");
220 let mut subst_map = TyParamsSubstMap::default();
221 for ty_p in generics.type_params() {
222 subst_map.insert(&ty_p.ident, None);
223 }
224 if !is_second_subst_of_first(generic_ty, ty, &mut subst_map) {
225 return None;
226 }
227 let bounds = get_trait_bounds(generics);
228 for b in &bounds {
229 if let Some(Some(ty)) = subst_map.get(b.ty_param.as_ref()) {
230 if !impl_trait(ty, &b.trait_names) {
231 return None;
232 }
233 } else {
234 println!(
235 "cargo:warning=invalid generic bounds({}) refer unknown parameter, subst. map {:?}",
236 b.ty_param.as_ref(),
237 subst_map
238 );
239 return None;
240 }
241 }
242
243 Some(subst_map)
244 }
245
246 pub(crate) fn subst_generic_params_to_c_items(
247 &self,
248 param_map: &TyParamsSubstMap,
249 expander: &mut dyn TypeMapConvRuleInfoExpanderHelper,
250 ) -> Result<Option<CItems>> {
251 debug!("subst_generic_params_to_c_items");
252 assert!(self.is_generic());
253 let type_aliases =
254 build_generic_aliases(self.src_id, &self.generic_aliases, param_map, expander)?;
255 let mut c_types = self.c_types.clone();
256 if let Some(generic_c_types) = self.generic_c_types.as_ref() {
257 let code_span = generic_c_types.types.span();
258 let code = expand_rust_code(
259 &generic_c_types.types.to_string(),
260 param_map,
261 expander,
262 &type_aliases,
263 (self.src_id, code_span),
264 )?;
265
266 let citems_list: CItemsList =
267 syn::LitStr::new(&code, code_span).parse().map_err(|err| {
268 DiagnosticError::new(
269 self.src_id,
270 code_span,
271 format!("can not parse this code after expand: {err}"),
272 )
273 .add_span_note(
274 invalid_src_id_span(),
275 format!("Code after expand: ```\n{code}\n```"),
276 )
277 })?;
278 assert!(self.c_types.is_none());
279
280 let header_name = expand_module_name(
281 &generic_c_types.header_name.name,
282 (self.src_id, generic_c_types.header_name.sp),
283 &type_aliases,
284 )?;
285
286 c_types = Some(CItems {
287 header_name,
288 items: citems_list.0,
289 });
290 }
291 Ok(c_types)
292 }
293
294 pub(crate) fn subst_generic_params(
295 &self,
296 param_map: TyParamsSubstMap,
297 direction: Direction,
298 expander: &mut dyn TypeMapConvRuleInfoExpanderHelper,
299 ) -> Result<Self> {
300 debug!(
301 "subst_generic_params: direction {:?}, rule {:?}",
302 direction, *self
303 );
304 assert!(self.is_generic());
305 let type_aliases =
306 build_generic_aliases(self.src_id, &self.generic_aliases, ¶m_map, expander)?;
307 let (rtype_left_to_right, ftype_left_to_right) =
308 if direction == Direction::Outgoing || self.if_simple_rtype_ftype_map().is_some() {
309 (
310 expand_rtype_rule(
311 self.src_id,
312 self.rtype_left_to_right.as_ref(),
313 ¶m_map,
314 expander,
315 &type_aliases,
316 )?,
317 expand_ftype_rule(
318 self.src_id,
319 self.ftype_left_to_right.as_ref(),
320 ¶m_map,
321 expander,
322 &type_aliases,
323 )?,
324 )
325 } else {
326 (None, vec![])
327 };
328 let (rtype_right_to_left, ftype_right_to_left) = if direction == Direction::Incoming {
329 (
330 expand_rtype_rule(
331 self.src_id,
332 self.rtype_right_to_left.as_ref(),
333 ¶m_map,
334 expander,
335 &type_aliases,
336 )?,
337 expand_ftype_rule(
338 self.src_id,
339 self.ftype_right_to_left.as_ref(),
340 ¶m_map,
341 expander,
342 &type_aliases,
343 )?,
344 )
345 } else {
346 (None, vec![])
347 };
348 let f_code = expand_fcode(
349 &self.f_code,
350 ¶m_map,
351 expander,
352 &type_aliases,
353 self.src_id,
354 )?;
355 Ok(TypeMapConvRuleInfo {
356 src_id: self.src_id,
357 span: self.span,
358 rtype_generics: None,
359 rtype_left_to_right,
360 rtype_right_to_left,
361 ftype_left_to_right,
362 ftype_right_to_left,
363 f_code,
364 c_types: None,
365 generic_c_types: None,
366 generic_aliases: vec![],
367 })
368 }
369 pub(in crate::typemap) fn set_src_id(&mut self, src_id: SourceId) {
370 self.src_id = src_id;
371 fn rtype_change_src_id(r: Option<&mut RTypeConvRule>, src_id: SourceId) {
372 if let Some(RTypeConvRule {
373 code: Some(ref mut conv_code),
374 ..
375 }) = r
376 {
377 conv_code.span.0 = src_id;
378 }
379 }
380 fn ftype_change_src_id(rules: &mut [FTypeConvRule], src_id: SourceId) {
381 for r in rules {
382 if let Some(conv_code) = r.code.as_mut() {
383 conv_code.span.0 = src_id;
384 }
385 }
386 }
387
388 rtype_change_src_id(self.rtype_left_to_right.as_mut(), src_id);
389 rtype_change_src_id(self.rtype_right_to_left.as_mut(), src_id);
390 ftype_change_src_id(&mut self.ftype_left_to_right, src_id);
391 ftype_change_src_id(&mut self.ftype_right_to_left, src_id);
392 }
393}
394
395impl TryInto<GenericTypeConv> for TypeMapConvRuleInfo {
396 type Error = TypeMapConvRuleInfo;
397
398 fn try_into(mut self) -> std::result::Result<GenericTypeConv, Self::Error> {
399 if !self.ftype_left_to_right.is_empty()
400 || !self.ftype_right_to_left.is_empty()
401 || self.c_types.is_some()
402 || self.generic_c_types.is_some()
403 || !self.f_code.is_empty()
404 || !self.generic_aliases.is_empty()
405 {
406 return Err(self);
407 }
408
409 let generic_params = match self.rtype_generics.take() {
410 Some(x) => x,
411 None => return Err(self),
412 };
413 let r_left_to_right = self.rtype_left_to_right.take();
414 let r_right_to_left = self.rtype_right_to_left.take();
415
416 let (from_ty, to_ty, code) = match (r_left_to_right, r_right_to_left) {
417 (Some(x), Some(y)) => {
418 self.rtype_generics = Some(generic_params);
419 self.rtype_left_to_right = Some(x);
420 self.rtype_right_to_left = Some(y);
421 return Err(self);
422 }
423 (None, None) => {
424 self.rtype_generics = Some(generic_params);
425 return Err(self);
426 }
427 (
428 Some(RTypeConvRule {
429 left_ty: from_ty,
430 right_ty: Some(to_ty),
431 code: Some(conv_code),
432 }),
433 None,
434 ) => (from_ty, to_ty, conv_code),
435 (
436 None,
437 Some(RTypeConvRule {
438 left_ty: to_ty,
439 right_ty: Some(from_ty),
440 code: Some(conv_code),
441 }),
442 ) => (from_ty, to_ty, conv_code),
443 (Some(x), None) => {
444 self.rtype_generics = Some(generic_params);
445 self.rtype_left_to_right = Some(x);
446 return Err(self);
447 }
448 (None, Some(y)) => {
449 self.rtype_generics = Some(generic_params);
450 self.rtype_right_to_left = Some(y);
451 return Err(self);
452 }
453 };
454
455 Ok(GenericTypeConv {
456 src_id: self.src_id,
457 from_ty,
458 to_ty,
459 code,
460 dependency: Rc::new(RefCell::new(None)),
461 generic_params,
462 to_foreigner_hint: None,
463 from_foreigner_hint: None,
464 })
465 }
466}
467
468#[derive(Debug, PartialEq)]
469pub(crate) struct RTypeConvRule {
470 pub left_ty: Type,
471 pub right_ty: Option<Type>,
472 pub code: Option<TypeConvCode>,
473}
474
475#[derive(Debug, PartialEq)]
476pub(crate) struct FTypeConvRule {
477 pub req_modules: Vec<ModuleName>,
478 pub cfg_option: Option<SpannedSmolStr>,
479 pub left_right_ty: FTypeLeftRightPair,
480 pub input_to_output: bool,
481 pub unique_prefix: Option<SpannedSmolStr>,
482 pub code: Option<TypeConvCode>,
483}
484
485#[derive(Debug, PartialEq)]
486pub(crate) enum FTypeLeftRightPair {
487 OnlyLeft(FTypeName),
488 OnlyRight(FTypeName),
489 Both(FTypeName, FTypeName),
490}
491
492impl FTypeLeftRightPair {
493 pub(crate) fn span(&self) -> Span {
494 use FTypeLeftRightPair::*;
495 match self {
496 OnlyRight(ref x) => x.sp,
497 OnlyLeft(ref x) => x.sp,
498 Both(ref x, _) => x.sp,
499 }
500 }
501}
502
503#[derive(Debug, Clone)]
504pub(crate) struct FTypeName {
505 pub name: UniqueName,
506 pub sp: Span,
507}
508
509impl PartialEq for FTypeName {
510 fn eq(&self, o: &Self) -> bool {
511 self.name == o.name
512 }
513}
514
515impl From<LitStr> for FTypeName {
516 fn from(x: LitStr) -> FTypeName {
517 FTypeName {
518 name: x.value().into(),
519 sp: x.span(),
520 }
521 }
522}
523
524pub(crate) struct ExpandedFType {
525 pub name: UniqueName,
526 pub provided_by_module: Vec<SmolStr>,
527}
528
529pub(crate) trait TypeMapConvRuleInfoExpanderHelper {
530 fn swig_i_type(&mut self, ty: &syn::Type, opt_arg: Option<&str>) -> Result<syn::Type>;
531 fn swig_from_rust_to_i_type(
532 &mut self,
533 ty: &syn::Type,
534 in_var_name: &str,
535 out_var_name: &str,
536 ) -> Result<String>;
537 fn swig_from_i_type_to_rust(
538 &mut self,
539 ty: &syn::Type,
540 in_var_name: &str,
541 out_var_name: &str,
542 ) -> Result<String>;
543 fn swig_f_type(&mut self, ty: &syn::Type, param1: Option<&str>) -> Result<ExpandedFType>;
545 fn swig_foreign_to_i_type(&mut self, ty: &syn::Type, var_name: &str) -> Result<String>;
546 fn swig_foreign_from_i_type(&mut self, ty: &syn::Type, var_name: &str) -> Result<String>;
547}
548
549struct CalcGenericAlias<'a> {
550 name: &'a syn::Ident,
551 value: syn::Type,
552 req_modules: Vec<SmolStr>,
553}
554
555fn build_generic_aliases<'a>(
556 src_id: SourceId,
557 generic_aliases: &'a [GenericAlias],
558 param_map: &TyParamsSubstMap,
559 expander: &mut dyn TypeMapConvRuleInfoExpanderHelper,
560) -> Result<Vec<CalcGenericAlias<'a>>> {
561 let mut ret = vec![];
562 for ga in generic_aliases {
563 let item: GenericAliasItem = syn::parse2(ga.value.clone())
564 .map_err(|err| DiagnosticError::from_syn_err(src_id, err))?;
565 let mut req_modules = Vec::<SmolStr>::new();
566 let mut ident = String::new();
567 concat_idents(
568 src_id,
569 item,
570 param_map,
571 expander,
572 &mut req_modules,
573 &mut ident,
574 )?;
575 let ident = properly_escape_str_as_type(&ident);
576 let new_type: syn::Type =
577 parse_ty_with_given_span(&ident, ga.value.span()).map_err(|err| {
578 DiagnosticError::from_syn_err(src_id, err).add_span_note(
579 invalid_src_id_span(),
580 format!("trying to parse '{ident}' as type"),
581 )
582 })?;
583 ret.push(CalcGenericAlias {
584 name: &ga.alias,
585 value: new_type,
586 req_modules,
587 });
588 }
589 Ok(ret)
590}
591
592fn properly_escape_str_as_type(s: &str) -> String {
593 let data = s
594 .replace(":: std :: os :: raw ::", "")
595 .replace("std :: os :: raw ::", "");
596 let mut ret = String::with_capacity(data.len());
597 for ch in data.chars() {
598 if ch.is_ascii_alphanumeric() || ch == '_' {
599 ret.push(ch);
600 } else {
601 write!(&mut ret, "{}", u32::from(ch)).expect("write to String failed, no free mem?");
602 }
603 }
604 ret
605}
606
607#[derive(Debug)]
608enum GenericAliasItem {
609 Concat(Vec<GenericAliasItem>),
610 Ident(syn::Ident),
611 SwigIType((syn::Ident, Option<syn::Ident>)),
612 SwigFType(syn::Ident),
613}
614
615fn concat_idents(
616 src_id: SourceId,
617 item: GenericAliasItem,
618 param_map: &TyParamsSubstMap,
619 expander: &mut dyn TypeMapConvRuleInfoExpanderHelper,
620 req_modules: &mut Vec<SmolStr>,
621 ident: &mut String,
622) -> Result<()> {
623 match item {
624 GenericAliasItem::Concat(items) => {
625 for it in items {
626 concat_idents(src_id, it, param_map, expander, req_modules, ident)?;
627 }
628 }
629 GenericAliasItem::SwigIType((id, opt_arg)) => {
630 let ty = find_type_param(param_map, &id.to_string(), (src_id, id.span()))?;
631 let i_type: syn::Type = expander.swig_i_type(
632 ty.as_ref(),
633 opt_arg.as_ref().map(syn::Ident::to_string).as_deref(),
634 )?;
635 ident.push_str(&DisplayToTokens(&i_type).to_string());
636 }
637 GenericAliasItem::SwigFType(id) => {
638 let ty = find_type_param(param_map, &id.to_string(), (src_id, id.span()))?;
639 let mut f_type = expander.swig_f_type(ty.as_ref(), None)?;
640 req_modules.append(&mut f_type.provided_by_module);
641 ident.push_str(f_type.name.display());
642 }
643 GenericAliasItem::Ident(id) => ident.push_str(&id.to_string()),
644 }
645 Ok(())
646}
647
648pub(in crate::typemap) fn expand_macroses<E>(code: &str, mut expander: E) -> Result<String>
649where
650 E: FnMut(&str, Vec<&str>, &mut String) -> Result<()>,
651{
652 let mut prev_pos = 0;
653 let mut ret = String::with_capacity(code.len());
654 loop {
655 match (code[prev_pos..]).find(char::is_alphabetic) {
656 Some(pos) => {
657 let skip_chunk = &code[prev_pos..(prev_pos + pos)];
658 ret.push_str(skip_chunk);
659 prev_pos += pos;
660 if let Some((macro_id, params, macro_call_end)) = find_macro(&code[prev_pos..]) {
661 expander(macro_id, params, &mut ret)?;
662 prev_pos += macro_call_end;
663 } else {
664 match (code[prev_pos..]).find(|ch: char| !ch.is_alphabetic()) {
665 Some(pos) => {
666 let skip_chunk = &code[prev_pos..(prev_pos + pos)];
667 ret.push_str(skip_chunk);
668 prev_pos += pos;
669 }
670 None => {
671 ret.push_str(&code[prev_pos..]);
672 break;
673 }
674 }
675 }
676 }
677 None => {
678 ret.push_str(&code[prev_pos..]);
679 break;
680 }
681 }
682 }
683
684 Ok(ret)
685}
686
687fn find_macro(code: &str) -> Option<(&str, Vec<&str>, usize)> {
688 let id_end = code.find(|ch: char| !(ch.is_alphanumeric() || ch == '_'))?;
689 let mut next_pos = id_end + (code[id_end..]).find(|ch: char| !ch.is_whitespace())?;
690 if &code[next_pos..=next_pos] != "!" {
691 return None;
692 }
693 next_pos += 1;
694 next_pos = next_pos + (code[next_pos..]).find(|ch: char| !ch.is_whitespace())?;
695 if &code[next_pos..=next_pos] != "(" {
696 return None;
697 }
698 next_pos += 1;
699 let cnt_start = next_pos;
700 let mut bracket_counter: usize = 1;
701 let mut close_bracket_pos = None;
702 for (idx, ch) in code[next_pos..].chars().enumerate() {
703 if ch == ')' {
704 bracket_counter -= 1;
705 if bracket_counter == 0 {
706 close_bracket_pos = Some(idx);
707 break;
708 }
709 } else if ch == '(' {
710 bracket_counter += 1;
711 }
712 }
713 next_pos += close_bracket_pos?;
714 let cnt_end = next_pos;
715 let id = &code[0..id_end];
716 let params: Vec<&str> = code[cnt_start..cnt_end]
717 .trim()
718 .split(',')
719 .filter_map(|x| {
720 let s = x.trim();
721 if !s.is_empty() {
722 Some(s)
723 } else {
724 None
725 }
726 })
727 .collect();
728 Some((id, params, next_pos + 1))
729}
730
731fn expand_rtype_rule(
732 src_id: SourceId,
733 grule: Option<&RTypeConvRule>,
734 param_map: &TyParamsSubstMap,
735 expander: &mut dyn TypeMapConvRuleInfoExpanderHelper,
736 generic_aliases: &[CalcGenericAlias],
737) -> Result<Option<RTypeConvRule>> {
738 let grule = match grule {
739 Some(x) => x,
740 None => return Ok(None),
741 };
742 let left_ty = expand_type(&grule.left_ty, src_id, param_map, expander, generic_aliases)?;
743 let right_ty: Option<Type> = match grule.right_ty.as_ref() {
744 Some(x) => Some(expand_type(
745 x,
746 src_id,
747 param_map,
748 expander,
749 generic_aliases,
750 )?),
751 None => None,
752 };
753
754 let code = match grule.code {
755 Some(ref x) => {
756 let code = expand_rust_code(
757 x.as_str(),
758 param_map,
759 expander,
760 generic_aliases,
761 (src_id, x.span()),
762 )?;
763 Some(TypeConvCode::new(code, (SourceId::none(), x.span())))
764 }
765 None => None,
766 };
767 Ok(Some(RTypeConvRule {
768 left_ty,
769 right_ty,
770 code,
771 }))
772}
773
774fn expand_type(
775 in_ty: &Type,
776 src_id: SourceId,
777 subst_map: &TyParamsSubstMap,
778 expander: &mut dyn TypeMapConvRuleInfoExpanderHelper,
779 generic_aliases: &[CalcGenericAlias],
780) -> Result<Type> {
781 struct ReplaceTypes<'a, 'b, 'c> {
782 src_id: SourceId,
783 expander: &'a mut dyn TypeMapConvRuleInfoExpanderHelper,
784 subst_map: &'a TyParamsSubstMap<'b>,
785 generic_aliases: &'a [CalcGenericAlias<'c>],
786 err: Option<DiagnosticError>,
787 }
788 impl VisitMut for ReplaceTypes<'_, '_, '_> {
789 fn visit_type_mut(&mut self, t: &mut Type) {
790 if self.err.is_some() {
791 return;
792 }
793
794 let ty_name = normalize_type(t);
795 if let Some(Some(subst)) = self.subst_map.get(&ty_name) {
796 *t = subst.clone();
797 } else {
798 visit_type_mut(self, t);
799 }
800
801 if let Type::Macro(ref type_macro) = t {
802 let ctx_span = (self.src_id, t.span());
803 match expand_macro_in_type(
804 type_macro,
805 ctx_span,
806 self.subst_map,
807 self.expander,
808 self.generic_aliases,
809 ) {
810 Ok(Some(new_ty)) => *t = new_ty,
811 Ok(None) => {}
812 Err(err) => self.err = Some(err),
813 }
814 }
815 }
816 }
817
818 let mut rt = ReplaceTypes {
819 subst_map,
820 src_id,
821 expander,
822 generic_aliases,
823 err: None,
824 };
825 let mut new_ty = in_ty.clone();
826 rt.visit_type_mut(&mut new_ty);
827 Ok(new_ty)
828}
829
830fn expand_macro_in_type(
831 type_macro: &syn::TypeMacro,
832 ctx_span: SourceIdSpan,
833 param_map: &TyParamsSubstMap,
834 expander: &mut dyn TypeMapConvRuleInfoExpanderHelper,
835 generic_aliases: &[CalcGenericAlias],
836) -> Result<Option<Type>> {
837 if type_macro.mac.path.is_ident(SWIG_I_TYPE) {
838 let param = type_macro.mac.tokens.to_string();
839 let ty = find_type_param(param_map, ¶m, ctx_span)?;
840 let i_type = expander.swig_i_type(ty.as_ref(), None)?;
841 Ok(Some(i_type))
842 } else {
843 let alias_idx = generic_aliases
844 .iter()
845 .position(|a| type_macro.mac.path.is_ident(a.name))
846 .ok_or_else(|| {
847 DiagnosticError::new2(
848 ctx_span,
849 format!(
850 "unknown {} name {}",
851 GENERIC_ALIAS,
852 DisplayToTokens(&type_macro.mac.path)
853 ),
854 )
855 })?;
856 Ok(Some(generic_aliases[alias_idx].value.clone()))
857 }
858}
859
860fn expand_ftype_rule(
861 src_id: SourceId,
862 grules: &[FTypeConvRule],
863 param_map: &TyParamsSubstMap,
864 expander: &mut dyn TypeMapConvRuleInfoExpanderHelper,
865 generic_aliases: &[CalcGenericAlias],
866) -> Result<Vec<FTypeConvRule>> {
867 let mut ret = Vec::with_capacity(grules.len());
868
869 for grule in grules {
870 use FTypeLeftRightPair::*;
871 let mut provided_by_module = Vec::<ModuleName>::new();
872 let left_right_ty = match grule.left_right_ty {
873 OnlyLeft(ref ftype) => OnlyLeft(expand_ftype_name(
874 src_id,
875 ftype,
876 param_map,
877 expander,
878 generic_aliases,
879 &mut provided_by_module,
880 )?),
881 OnlyRight(ref ftype) => OnlyRight(expand_ftype_name(
882 src_id,
883 ftype,
884 param_map,
885 expander,
886 generic_aliases,
887 &mut provided_by_module,
888 )?),
889 Both(ref fl, ref fr) => Both(
890 expand_ftype_name(
891 src_id,
892 fl,
893 param_map,
894 expander,
895 generic_aliases,
896 &mut provided_by_module,
897 )?,
898 expand_ftype_name(
899 src_id,
900 fr,
901 param_map,
902 expander,
903 generic_aliases,
904 &mut provided_by_module,
905 )?,
906 ),
907 };
908 let code = match grule.code {
909 Some(ref x) => {
910 let code = expand_foreign_type_conv_code(
911 x,
912 param_map,
913 expander,
914 generic_aliases,
915 (src_id, x.span()),
916 )?;
917 Some(code)
918 }
919 None => None,
920 };
921 for m in &grule.req_modules {
922 let mod_name = expand_module_name(&m.name, (src_id, m.sp), generic_aliases)?;
923 provided_by_module.push(ModuleName {
924 name: mod_name,
925 sp: m.sp,
926 });
927 }
928 let mut mod_uniques = FxHashSet::default();
930 provided_by_module.retain(|e| mod_uniques.insert(e.name.clone()));
931 let unique_prefix = if let Some(unique_prefix) = grule.unique_prefix.as_ref() {
932 let ctx_span = (src_id, unique_prefix.sp);
933 let mut provided_by_module = vec![];
934 let new_unique_prefix = expand_str_in_ftype_name_context(
935 ctx_span,
936 unique_prefix.as_str(),
937 param_map,
938 expander,
939 generic_aliases,
940 &mut provided_by_module,
941 )?;
942 Some(SpannedSmolStr {
943 sp: unique_prefix.sp,
944 value: new_unique_prefix.into(),
945 })
946 } else {
947 None
948 };
949
950 ret.push(FTypeConvRule {
951 unique_prefix,
952 req_modules: provided_by_module,
953 cfg_option: grule.cfg_option.clone(),
954 left_right_ty,
955 input_to_output: grule.input_to_output,
956 code,
957 });
958 }
959 Ok(ret)
960}
961
962fn call_swig_f_type(
963 ctx_sp: SourceIdSpan,
964 params: Vec<&str>,
965 out: &mut String,
966 param_map: &TyParamsSubstMap,
967 expander: &mut dyn TypeMapConvRuleInfoExpanderHelper,
968 generic_aliases: &[CalcGenericAlias],
969) -> Result<Vec<SmolStr>> {
970 let (type_name, opt_param) = match params.len() {
971 1 => (params[0], None),
972 2 => (params[0], Some(params[1])),
973 _ => {
974 return Err(DiagnosticError::new2(
975 ctx_sp,
976 format!(
977 "{} parameters in {} instead of 1 or 2",
978 params.len(),
979 SWIG_F_TYPE
980 ),
981 ))
982 }
983 };
984 let ty = if type_name.ends_with("!()") {
985 let alias_name = type_name[0..type_name.len() - 3].trim();
986 let pos = generic_aliases
987 .iter()
988 .position(|a| a.name == alias_name)
989 .ok_or_else(|| {
990 DiagnosticError::new2(ctx_sp, format!("unknown type alias '{alias_name}'"))
991 })?;
992 TyValueOrRef::Ref(&generic_aliases[pos].value)
993 } else {
994 find_type_param(param_map, type_name, ctx_sp)?
995 };
996
997 let f_type = expander.swig_f_type(ty.as_ref(), opt_param)?;
998 out.push_str(f_type.name.value());
999 Ok(f_type.provided_by_module)
1000}
1001
1002fn expand_ftype_name(
1003 src_id: SourceId,
1004 ftype: &FTypeName,
1005 param_map: &TyParamsSubstMap,
1006 expander: &mut dyn TypeMapConvRuleInfoExpanderHelper,
1007 generic_aliases: &[CalcGenericAlias],
1008 provided_by_module: &mut Vec<ModuleName>,
1009) -> Result<FTypeName> {
1010 let ctx_span = (src_id, ftype.sp);
1011
1012 let new_fytpe = expand_str_in_ftype_name_context(
1013 ctx_span,
1014 ftype.name.display(),
1015 param_map,
1016 expander,
1017 generic_aliases,
1018 provided_by_module,
1019 )?;
1020
1021 Ok(FTypeName {
1022 name: new_fytpe.into(),
1023 sp: ftype.sp,
1024 })
1025}
1026
1027fn expand_str_in_ftype_name_context(
1028 ctx_span: SourceIdSpan,
1029 input: &str,
1030 param_map: &TyParamsSubstMap,
1031 expander: &mut dyn TypeMapConvRuleInfoExpanderHelper,
1032 generic_aliases: &[CalcGenericAlias],
1033 provided_by_module: &mut Vec<ModuleName>,
1034) -> Result<String> {
1035 expand_macroses(input, |id: &str, params: Vec<&str>, out: &mut String| {
1036 if id == SWIG_F_TYPE {
1037 let modules: Vec<SmolStr> =
1038 call_swig_f_type(ctx_span, params, out, param_map, expander, generic_aliases)?;
1039 provided_by_module.extend(modules.into_iter().map(|name| ModuleName {
1040 name,
1041 sp: Span::call_site(),
1042 }));
1043 Ok(())
1044 } else if id == SWIG_SUBST_TYPE {
1045 let type_name = if params.len() == 1 {
1046 params[0]
1047 } else {
1048 return Err(DiagnosticError::new2(
1049 ctx_span,
1050 format!("{} parameters in {} instead of 1", params.len(), id),
1051 ));
1052 };
1053 let ty = find_type_param(param_map, type_name, ctx_span)?;
1054 out.push_str(normalize_type(ty.as_ref()));
1055 Ok(())
1056 } else if let Some(pos) = generic_aliases.iter().position(|a| a.name == id) {
1057 write!(out, "{}", DisplayToTokens(&generic_aliases[pos].value))
1058 .expect(WRITE_TO_MEM_FAILED_MSG);
1059 provided_by_module.extend(generic_aliases[pos].req_modules.iter().map(|name| {
1060 ModuleName {
1061 name: name.clone(),
1062 sp: Span::call_site(),
1063 }
1064 }));
1065 Ok(())
1066 } else {
1067 Err(DiagnosticError::new2(
1068 ctx_span,
1069 format!("unknown macros '{id}' in this context"),
1070 ))
1071 }
1072 })
1073}
1074
1075enum TyValueOrRef<'a> {
1076 Value(Type),
1077 Ref(&'a Type),
1078}
1079
1080impl AsRef<Type> for TyValueOrRef<'_> {
1081 fn as_ref(&self) -> &Type {
1082 match self {
1083 TyValueOrRef::Value(ref ty) => ty,
1084 TyValueOrRef::Ref(ty) => ty,
1085 }
1086 }
1087}
1088
1089fn find_type_param<'b>(
1090 param_map: &'b TyParamsSubstMap,
1091 param: &str,
1092 param_span: SourceIdSpan,
1093) -> Result<TyValueOrRef<'b>> {
1094 if let Some(Some(ty)) = param_map.get(param) {
1095 return Ok(TyValueOrRef::Ref(ty));
1096 }
1097 let compound_ty: Type = parse_ty_with_given_span(param, param_span.1).map_err(|err| {
1098 DiagnosticError::new2(param_span, format!("unknown type parameter '{param}'"))
1099 .add_span_note(invalid_src_id_span(), err)
1100 })?;
1101 if let Type::Reference(ty_ref) = compound_ty {
1102 let param = DisplayToTokens(&ty_ref.elem).to_string();
1103 if let Some(Some(ty)) = param_map.get(¶m) {
1104 let new_ty = Type::Reference(syn::TypeReference {
1105 and_token: ty_ref.and_token,
1106 lifetime: ty_ref.lifetime,
1107 mutability: ty_ref.mutability,
1108 elem: Box::new(ty.clone()),
1109 });
1110 return Ok(TyValueOrRef::Value(new_ty));
1111 }
1112 }
1113 Err(DiagnosticError::new2(
1114 param_span,
1115 format!("unknown type parameter '{param}'"),
1116 ))
1117}
1118
1119fn expand_module_name(
1120 generic_mod_name: &str,
1121 ctx_sp: SourceIdSpan,
1122 aliases: &[CalcGenericAlias],
1123) -> Result<SmolStr> {
1124 expand_macroses(
1125 generic_mod_name,
1126 |id: &str, params: Vec<&str>, out: &mut String| -> Result<()> {
1127 if !params.is_empty() {
1128 Err(DiagnosticError::new2(
1129 ctx_sp,
1130 format!("{GENERIC_ALIAS} ({id}) does not accept parameters: {params:?}"),
1131 ))
1132 } else if let Some(pos) = aliases.iter().position(|e| e.name == id) {
1133 write!(out, "{}", DisplayToTokens(&aliases[pos].value))
1134 .expect(WRITE_TO_MEM_FAILED_MSG);
1135 Ok(())
1136 } else {
1137 Err(DiagnosticError::new2(
1138 ctx_sp,
1139 format!("unknown macros '{id}' in this context"),
1140 ))
1141 }
1142 },
1143 )
1144 .map(|x| x.into())
1145}
1146
1147fn expand_rust_code(
1148 code: &str,
1149 param_map: &TyParamsSubstMap,
1150 expander: &mut dyn TypeMapConvRuleInfoExpanderHelper,
1151 generic_aliases: &[CalcGenericAlias],
1152 ctx_span: SourceIdSpan,
1153) -> Result<String> {
1154 expand_macroses(
1155 code,
1156 |id: &str, params: Vec<&str>, out: &mut String| -> Result<()> {
1157 match id {
1158 _ if id == SWIG_FROM_RUST_TO_I_TYPE || id == SWIG_FROM_I_TYPE_TO_RUST => {
1159 let (type_name, in_var_name, out_var_name) = if params.len() == 3 {
1160 (¶ms[0], ¶ms[1], ¶ms[2])
1161 } else {
1162 return Err(DiagnosticError::new2(
1163 ctx_span,
1164 format!("{} parameters in {} instead of 2", params.len(), id),
1165 ));
1166 };
1167 let ty = find_type_param(param_map, type_name, ctx_span)?;
1168 let tt: String = if id == SWIG_FROM_RUST_TO_I_TYPE {
1169 expander.swig_from_rust_to_i_type(ty.as_ref(), in_var_name, out_var_name)?
1170 } else if id == SWIG_FROM_I_TYPE_TO_RUST {
1171 expander.swig_from_i_type_to_rust(ty.as_ref(), in_var_name, out_var_name)?
1172 } else {
1173 unreachable!()
1174 };
1175 write!(out, "{tt}").expect(WRITE_TO_MEM_FAILED_MSG);
1176 }
1177 _ if id == SWIG_I_TYPE => {
1178 let (param, opt_arg) = match params.len() {
1179 1 => (params[0], None),
1180 2 => (params[0], Some(params[1])),
1181 _ => {
1182 return Err(DiagnosticError::new2(
1183 ctx_span,
1184 format!(
1185 "{} parameters in {} instead of 1 or 2",
1186 params.len(),
1187 SWIG_I_TYPE
1188 ),
1189 ));
1190 }
1191 };
1192 let ty = find_type_param(param_map, param, ctx_span)?;
1193 let i_type = expander.swig_i_type(ty.as_ref(), opt_arg)?;
1194 write!(out, "{}", normalize_type(&i_type)).expect(WRITE_TO_MEM_FAILED_MSG);
1195 }
1196 _ if id == SWIG_SUBST_TYPE => {
1197 let type_name = if params.len() == 1 {
1198 ¶ms[0]
1199 } else {
1200 return Err(DiagnosticError::new2(
1201 ctx_span,
1202 format!("{} parameters in {} instead of 1", params.len(), id),
1203 ));
1204 };
1205 let ty = find_type_param(param_map, type_name, ctx_span)?;
1206 write!(out, "{}", normalize_type(ty.as_ref())).expect(WRITE_TO_MEM_FAILED_MSG);
1207 }
1208 _ => {
1209 if let Some(alias_idx) = generic_aliases.iter().position(|a| a.name == id) {
1210 write!(out, "{}", normalize_type(&generic_aliases[alias_idx].value))
1211 .expect(WRITE_TO_MEM_FAILED_MSG);
1212 } else {
1213 write!(out, "{id}!(").expect(WRITE_TO_MEM_FAILED_MSG);
1214 for (i, p) in params.iter().enumerate() {
1215 if i == 0 {
1216 out.push_str(p);
1217 } else {
1218 write!(out, ", {p}").expect(WRITE_TO_MEM_FAILED_MSG);
1219 }
1220 }
1221 out.push(')');
1222 }
1223 }
1224 }
1225 Ok(())
1226 },
1227 )
1228}
1229
1230fn expand_foreign_code(
1231 code: &str,
1232 param_map: &TyParamsSubstMap,
1233 expander: &mut dyn TypeMapConvRuleInfoExpanderHelper,
1234 generic_aliases: &[CalcGenericAlias],
1235 ctx_span: SourceIdSpan,
1236) -> Result<String> {
1237 expand_macroses(
1238 code,
1239 |id: &str, params: Vec<&str>, out: &mut String| -> Result<()> {
1240 match id {
1241 _ if id == SWIG_F_TYPE => {
1242 call_swig_f_type(ctx_span, params, out, param_map, expander, generic_aliases)?;
1243 }
1244 _ if id == SWIG_I_TYPE => {
1245 let (param, opt_arg) = match params.len() {
1246 1 => (params[0], None),
1247 2 => (params[0], Some(params[1])),
1248 _ => {
1249 return Err(DiagnosticError::new2(
1250 ctx_span,
1251 format!(
1252 "{} parameters in {} instead of 1 or 2",
1253 params.len(),
1254 SWIG_I_TYPE
1255 ),
1256 ));
1257 }
1258 };
1259 let ty = find_type_param(param_map, param, ctx_span)?;
1260 let i_type = expander.swig_i_type(ty.as_ref(), opt_arg)?;
1261 let f_type = expander.swig_f_type(&i_type, opt_arg)?;
1262 out.push_str(f_type.name.display());
1263 }
1264 _ if id == SWIG_FOREIGN_TO_I_TYPE || id == SWIG_FOREIGN_FROM_I_TYPE => {
1265 let (type_name, var_name) = if params.len() == 2 {
1266 (¶ms[0], ¶ms[1])
1267 } else {
1268 return Err(DiagnosticError::new2(
1269 ctx_span,
1270 format!("{} parameters in {} instead of 2", params.len(), id),
1271 ));
1272 };
1273
1274 let ty = find_type_param(param_map, type_name, ctx_span)?;
1275 let tt: String = if id == SWIG_FOREIGN_TO_I_TYPE {
1276 expander.swig_foreign_to_i_type(ty.as_ref(), var_name)?
1277 } else if id == SWIG_FOREIGN_FROM_I_TYPE {
1278 expander.swig_foreign_from_i_type(ty.as_ref(), var_name)?
1279 } else {
1280 unreachable!()
1281 };
1282 write!(out, "{tt}").expect(WRITE_TO_MEM_FAILED_MSG);
1283 }
1284 _ => {
1285 if let Some(pos) = generic_aliases.iter().position(|a| a.name == id) {
1286 write!(out, "{}", DisplayToTokens(&generic_aliases[pos].value))
1287 .expect(WRITE_TO_MEM_FAILED_MSG);
1288 } else {
1289 return Err(DiagnosticError::new2(
1290 ctx_span,
1291 format!("unknown macro {id} in f_type conversion code"),
1292 ));
1293 }
1294 }
1295 }
1296 Ok(())
1297 },
1298 )
1299}
1300
1301fn expand_foreign_type_conv_code(
1302 code: &TypeConvCode,
1303 param_map: &TyParamsSubstMap,
1304 expander: &mut dyn TypeMapConvRuleInfoExpanderHelper,
1305 generic_aliases: &[CalcGenericAlias],
1306 ctx_span: SourceIdSpan,
1307) -> Result<TypeConvCode> {
1308 let ret_code = expand_foreign_code(
1309 code.as_str(),
1310 param_map,
1311 expander,
1312 generic_aliases,
1313 ctx_span,
1314 )?;
1315 Ok(TypeConvCode::with_params(
1316 ret_code,
1317 code.span,
1318 code.params().to_vec(),
1319 ))
1320}
1321
1322fn expand_fcode(
1323 f_code: &[ForeignCode],
1324 param_map: &TyParamsSubstMap,
1325 expander: &mut dyn TypeMapConvRuleInfoExpanderHelper,
1326 generic_aliases: &[CalcGenericAlias],
1327 src_id: SourceId,
1328) -> Result<Vec<ForeignCode>> {
1329 let mut ret = Vec::<ForeignCode>::with_capacity(f_code.len());
1330 for fc in f_code {
1331 let module_name: SmolStr =
1332 expand_module_name(&fc.module_name, (src_id, fc.sp), generic_aliases)?;
1333 let code = expand_foreign_code(
1334 &fc.code,
1335 param_map,
1336 expander,
1337 generic_aliases,
1338 (src_id, fc.sp),
1339 )?;
1340 ret.push(ForeignCode {
1341 sp: fc.sp,
1342 module_name,
1343 cfg_option: fc.cfg_option.clone(),
1344 code,
1345 });
1346 }
1347 Ok(ret)
1348}