libgir/codegen/
bound.rs

1use crate::{
2    analysis::{
3        bounds::{Bound, BoundType},
4        ref_mode::RefMode,
5    },
6    library::Nullable,
7};
8
9impl Bound {
10    /// Returns the type parameter reference.
11    /// Currently always returns the alias.
12    pub(super) fn type_parameter_reference(&self) -> Option<char> {
13        self.alias
14    }
15
16    /// Returns the type parameter reference, with [`BoundType::IsA`] wrapped
17    /// in `ref_mode` and `nullable` as appropriate.
18    pub(super) fn full_type_parameter_reference(
19        &self,
20        ref_mode: RefMode,
21        nullable: Nullable,
22        r#async: bool,
23    ) -> String {
24        let ref_str = ref_mode.for_rust_type();
25
26        // Generate `impl Trait` if this bound does not have an alias
27        let trait_bound = match self.type_parameter_reference() {
28            Some(t) => t.to_string(),
29            None => {
30                let trait_bound = self.trait_bound(r#async);
31                let trait_bound = format!("impl {trait_bound}");
32
33                // Combining a ref mode and lifetime requires parentheses for disambiguation
34                match self.bound_type {
35                    BoundType::IsA(lifetime) => {
36                        // TODO: This is fragile
37                        let has_lifetime = r#async || lifetime.is_some();
38
39                        if !ref_str.is_empty() && has_lifetime {
40                            format!("({trait_bound})")
41                        } else {
42                            trait_bound
43                        }
44                    }
45                    _ => trait_bound,
46                }
47            }
48        };
49
50        match self.bound_type {
51            BoundType::IsA(_) if *nullable => {
52                format!("Option<{ref_str}{trait_bound}>")
53            }
54            BoundType::IsA(_) => format!("{ref_str}{trait_bound}"),
55            BoundType::AsRef(_) if *nullable => {
56                format!("Option<{trait_bound}>")
57            }
58            BoundType::NoWrapper | BoundType::AsRef(_) => trait_bound,
59        }
60    }
61
62    /// Returns the type parameter definition for this bound, usually
63    /// of the form `T: SomeTrait` or `T: IsA<Foo>`.
64    pub(super) fn type_parameter_definition(&self, r#async: bool) -> Option<String> {
65        self.alias
66            .map(|alias| format!("{}: {}", alias, self.trait_bound(r#async)))
67    }
68
69    /// Returns the trait bound, usually of the form `SomeTrait`
70    /// or `IsA<Foo>`.
71    pub(super) fn trait_bound(&self, r#async: bool) -> String {
72        match self.bound_type {
73            BoundType::NoWrapper => self.type_str.clone(),
74            BoundType::IsA(lifetime) => {
75                if r#async {
76                    assert!(lifetime.is_none(), "Async overwrites lifetime");
77                }
78                let is_a = format!("IsA<{}>", self.type_str);
79
80                let lifetime = r#async
81                    .then(|| " + Clone + 'static".to_string())
82                    .or_else(|| lifetime.map(|l| format!(" + '{l}")))
83                    .unwrap_or_default();
84
85                format!("{is_a}{lifetime}")
86            }
87            BoundType::AsRef(Some(_ /* lifetime */)) => panic!("AsRef cannot have a lifetime"),
88            BoundType::AsRef(None) => format!("AsRef<{}>", self.type_str),
89        }
90    }
91}