kotlin_poet_rs/spec/
annotation.rs1use crate::io::RenderKotlin;
2use crate::spec::{AnnotationTarget, Argument, ClassLikeTypeName, CodeBlock};
3use crate::tokens;
4
5#[derive(Debug, Clone)]
33pub struct Annotation {
34 type_name: ClassLikeTypeName,
35 arguments: Vec<Argument>,
36 target: Option<AnnotationTarget>,
37}
38
39#[derive(Debug, Clone)]
40pub(crate) enum AnnotationSlotRenderMode { Vertical, Horizontal }
41
42#[derive(Debug, Clone)]
43pub(crate) struct AnnotationSlot {
44 inner: Vec<Annotation>,
45 render_mode: AnnotationSlotRenderMode
46}
47
48impl AnnotationSlot {
49
50 pub(crate) fn vertical() -> AnnotationSlot {
51 AnnotationSlot {
52 inner: Vec::new(),
53 render_mode: AnnotationSlotRenderMode::Vertical
54 }
55 }
56
57 pub(crate) fn horizontal() -> AnnotationSlot {
58 AnnotationSlot {
59 inner: Vec::new(),
60 render_mode: AnnotationSlotRenderMode::Horizontal
61 }
62 }
63
64 pub(crate) fn push(&mut self, new: Annotation) {
65 self.inner.push(new)
66 }
67}
68
69impl RenderKotlin for AnnotationSlot {
70 fn render_into(&self, block: &mut CodeBlock) {
71 for annotation in &self.inner {
72 block.push_renderable(annotation);
73 match self.render_mode {
74 AnnotationSlotRenderMode::Vertical => {
75 block.push_new_line()
76 }
77 AnnotationSlotRenderMode::Horizontal => {
78 block.push_space()
79 }
80 }
81 }
82 }
83}
84
85impl Annotation {
86 pub fn new<ClassLikeTypeNameLike: Into<ClassLikeTypeName>>(type_name: ClassLikeTypeNameLike) -> Self {
87 Annotation {
88 type_name: type_name.into(),
89 arguments: Vec::new(),
90 target: None,
91 }
92 }
93
94 pub fn argument(mut self, argument: Argument) -> Self {
95 self.arguments.push(argument);
96 self
97 }
98
99 pub fn target(mut self, target: AnnotationTarget) -> Self {
100 self.target = Some(target);
101 self
102 }
103}
104
105impl RenderKotlin for Annotation {
106 fn render_into(&self, block: &mut CodeBlock) {
107 block.push_static_atom(tokens::AT);
108 if let Some(target) = &self.target {
109 block.push_renderable(target);
110 block.push_static_atom(tokens::COLON);
111 }
112 block.push_renderable(&self.type_name);
113 block.push_round_brackets(|inner_code| {
114 inner_code.push_comma_separated(&self.arguments)
115 });
116 }
117}
118
119macro_rules! mixin_annotation_mutators {
120 () => {
121 pub fn annotation(mut self, annotation: Annotation) -> Self {
124 self.annotation_slot.push(annotation);
125 self
126 }
127 };
128}
129
130pub(crate) use mixin_annotation_mutators;
131
132#[cfg(test)]
133mod tests {
134 use std::str::FromStr;
135 use crate::io::RenderKotlin;
136 use crate::spec::{Annotation, AnnotationTarget, Argument, ClassLikeTypeName, CodeBlock, Package};
137
138 #[test]
139 fn test_annotation() {
140 let annotation = Annotation::new(
141 ClassLikeTypeName::top_level(Package::from_str("a.b.c").unwrap(), "MyAnnotation")
142 ).argument(
143 Argument::new_named("value", CodeBlock::atom("1"))
144 ).argument(
145 Argument::new_named("name", CodeBlock::atom("\"name_value\""))
146 );
147
148 let code = annotation.render_string();
149
150 assert_eq!(
151 code,
152 "@a.b.c.MyAnnotation(value = 1, name = \"name_value\")"
153 );
154 }
155
156 #[test]
157 fn test_annotation_with_target() {
158 let annotation = Annotation::new(
159 ClassLikeTypeName::top_level(Package::from_str("a.b.c").unwrap(), "MyAnnotation")
160 ).argument(
161 Argument::new_named("value", CodeBlock::atom("1"))
162 ).argument(
163 Argument::new_named("name", CodeBlock::atom("\"name_value\""))
164 ).target(
165 AnnotationTarget::Field
166 );
167
168 let code = annotation.render_string();
169
170 assert_eq!(
171 code,
172 "@field:a.b.c.MyAnnotation(value = 1, name = \"name_value\")"
173 );
174 }
175}