1use std::io::{Result, Write};
2
3use super::{
4 general::{doc_alias, doc_hidden},
5 property_body,
6};
7use crate::{
8 analysis::{child_properties::ChildProperty, rust_type::RustType},
9 chunk::Chunk,
10 env::Env,
11 library,
12 nameutil::use_gtk_type,
13 traits::IntoString,
14 writer::{primitives::tabs, ToCode},
15};
16
17pub fn generate(
18 w: &mut dyn Write,
19 env: &Env,
20 prop: &ChildProperty,
21 in_trait: bool,
22 only_declaration: bool,
23 indent: usize,
24) -> Result<()> {
25 generate_func(w, env, prop, in_trait, only_declaration, indent, true)?;
26 generate_func(w, env, prop, in_trait, only_declaration, indent, false)?;
27
28 Ok(())
29}
30
31fn generate_func(
32 w: &mut dyn Write,
33 env: &Env,
34 prop: &ChildProperty,
35 in_trait: bool,
36 only_declaration: bool,
37 indent: usize,
38 is_get: bool,
39) -> Result<()> {
40 let pub_prefix = if in_trait { "" } else { "pub " };
41 let decl_suffix = if only_declaration { ";" } else { " {" };
42 let type_string = RustType::try_new(env, prop.typ);
43 let comment_prefix = if type_string.is_err() { "//" } else { "" };
44
45 writeln!(w)?;
46
47 doc_hidden(w, prop.doc_hidden, comment_prefix, indent)?;
48 let decl = declaration(env, prop, is_get);
49 let add_doc_alias = if is_get {
50 prop.name != prop.getter_name && prop.name != prop.prop_name
51 } else {
52 prop.name != prop.prop_name
53 };
54 if add_doc_alias {
55 doc_alias(
56 w,
57 &format!("{}.{}", &prop.child_name, &prop.name),
58 comment_prefix,
59 indent,
60 )?;
61 }
62 writeln!(
63 w,
64 "{}{}{}{}{}",
65 tabs(indent),
66 comment_prefix,
67 pub_prefix,
68 decl,
69 decl_suffix
70 )?;
71
72 if !only_declaration {
73 let body = body(env, prop, in_trait, is_get).to_code(env);
74 for s in body {
75 writeln!(w, "{}{}{}", tabs(indent), comment_prefix, s)?;
76 }
77 }
78
79 Ok(())
80}
81
82fn declaration(env: &Env, prop: &ChildProperty, is_get: bool) -> String {
83 let func_name = if is_get {
84 format!("{}_{}", prop.child_name, prop.getter_name)
85 } else {
86 format!("set_{}_{}", prop.child_name, prop.prop_name)
87 };
88 let mut bounds = if let Some(typ) = prop.child_type {
89 let child_type = RustType::try_new(env, typ).into_string();
90 format!("T: IsA<{child_type}>")
91 } else {
92 format!("T: IsA<{}>", use_gtk_type(env, "Widget"))
93 };
94 if !is_get && !prop.bounds.is_empty() {
95 bounds = format!("{}, {}", prop.bounds, bounds);
96 }
97 let return_str = if is_get {
98 let dir = library::ParameterDirection::Return;
99 let ret_type = RustType::builder(env, prop.typ)
100 .direction(dir)
101 .nullable(prop.nullable)
102 .ref_mode(prop.get_out_ref_mode)
103 .try_build_param()
104 .into_string();
105 format!(" -> {ret_type}")
106 } else {
107 String::new()
108 };
109 format!(
110 "fn {}<{}>(&self, item: &T{}){}",
111 func_name,
112 bounds,
113 if is_get {
114 String::new()
115 } else {
116 format!(", {}", prop.set_params)
117 },
118 return_str
119 )
120}
121
122fn body(env: &Env, prop: &ChildProperty, in_trait: bool, is_get: bool) -> Chunk {
123 let mut builder = property_body::Builder::new_for_child_property(env);
124 builder
125 .name(&prop.name)
126 .in_trait(in_trait)
127 .var_name(&prop.prop_name)
128 .is_get(is_get);
129
130 if let Ok(type_) = RustType::try_new(env, prop.typ) {
131 builder.type_(type_.as_str());
132 } else {
133 builder.type_("/*Unknown type*/");
134 }
135
136 builder.generate()
137}