kotlin_poet_rs/spec/
generic_parameter.rs

1use crate::spec::{CodeBlock, GenericInvariance, Name, Type};
2use crate::tokens;
3
4/// Describes a generic parameter of a class or function.
5///
6/// Note, because [crate::io::RenderKotlin] implementation for this struct would be ambiguous, it is not implemented.
7#[derive(Debug, Clone)]
8pub struct GenericParameter {
9    name: Name,
10    /// Invariance of the generic parameter, only available for function's generic parameters
11    invariance: Option<GenericInvariance>,
12    type_boundaries: Vec<Type>,
13}
14
15impl GenericParameter {
16    /// Creates new [GenericParameter] with a given name, no invariance modifier or type boundaries.
17    pub fn new<NameLike: Into<Name>>(name: NameLike) -> Self {
18        GenericParameter {
19            name: name.into(),
20            invariance: None,
21            type_boundaries: Vec::new(),
22        }
23    }
24
25    /// Sets [GenericInvariance]. Should not be used with function generic parameters.
26    pub fn invariance(mut self, invariance: GenericInvariance) -> Self {
27        self.invariance = Some(invariance);
28        self
29    }
30
31    /// Adds new type boundary to the generic parameter.
32    /// This method could be called multiple times to add multiple type boundaries.
33    pub fn type_boundary<TypeLike: Into<Type>>(mut self, boundary: TypeLike) -> Self {
34        self.type_boundaries.push(boundary.into());
35        self
36    }
37
38    pub(crate) fn render_definition(&self) -> CodeBlock {
39        let mut code = CodeBlock::empty();
40        if let Some(invariance) = &self.invariance {
41            code.push_renderable(invariance);
42            code.push_space();
43        }
44        code.push_renderable(&self.name);
45        code
46    }
47
48    pub(crate) fn render_type_boundaries(&self) -> CodeBlock {
49        let mut code = CodeBlock::empty();
50        code.push_comma_separated(
51            &self.type_boundaries.iter().map(|boundary| {
52                let mut inner = CodeBlock::empty();
53                inner.push_renderable(&self.name);
54                inner.push_static_atom(tokens::COLON);
55                inner.push_space();
56                inner.push_renderable(boundary);
57                inner
58            }).collect::<Vec<CodeBlock>>()
59        );
60        code
61    }
62
63    pub(crate) fn render_type_boundaries_vec_if_required(vec: &[GenericParameter]) -> CodeBlock {
64        let boundary_code_blocks = vec.iter().filter(|parameter| !parameter.type_boundaries.is_empty())
65            .map(|parameter| {
66                parameter.render_type_boundaries()
67            })
68            .collect::<Vec<CodeBlock>>();
69
70        if boundary_code_blocks.is_empty() {
71            return CodeBlock::empty();
72        }
73
74        let mut code = CodeBlock::empty();
75        code.push_static_atom(tokens::keyword::WHERE);
76        code.push_space();
77        code.push_comma_separated(&boundary_code_blocks);
78        code.push_space();
79
80        code
81    }
82}