libgir/codegen/
properties.rs
1use std::io::{Result, Write};
2
3use super::{
4 general::{cfg_deprecated, doc_alias, version_condition},
5 property_body,
6};
7use crate::{
8 analysis::{properties::Property, rust_type::RustType},
9 chunk::Chunk,
10 env::Env,
11 library,
12 traits::IntoString,
13 writer::{primitives::tabs, ToCode},
14};
15
16pub fn generate(
17 w: &mut dyn Write,
18 env: &Env,
19 prop: &Property,
20 in_trait: bool,
21 only_declaration: bool,
22 indent: usize,
23) -> Result<()> {
24 generate_prop_func(w, env, prop, in_trait, only_declaration, indent)?;
25
26 Ok(())
27}
28
29fn generate_prop_func(
30 w: &mut dyn Write,
31 env: &Env,
32 prop: &Property,
33 in_trait: bool,
34 only_declaration: bool,
35 indent: usize,
36) -> Result<()> {
37 let pub_prefix = if in_trait { "" } else { "pub " };
38 let decl_suffix = if only_declaration { ";" } else { " {" };
39 let commented = RustType::try_new(env, prop.typ).is_err();
40 let comment_prefix = if commented { "//" } else { "" };
41
42 writeln!(w)?;
43
44 let decl = declaration(env, prop);
45 cfg_deprecated(
46 w,
47 env,
48 Some(prop.typ),
49 prop.deprecated_version,
50 commented,
51 indent,
52 )?;
53 version_condition(w, env, None, prop.version, commented, indent)?;
54 let add_doc_alias = if let Some(func_name_alias) = prop.func_name_alias.as_ref() {
55 &prop.name != func_name_alias && prop.name != prop.var_name
56 } else {
57 prop.name != prop.var_name
58 };
59 if add_doc_alias {
60 doc_alias(w, &prop.name, comment_prefix, indent)?;
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).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: &Property) -> String {
83 let bound: String;
84 let set_param = if prop.is_get {
85 bound = String::new();
86 String::new()
87 } else if let Some(ref set_bound) = prop.set_bound {
88 bound = format!("<{}: IsA<{}>>", set_bound.alias, set_bound.type_str);
89 format!(", {}: Option<&{}>", prop.var_name, set_bound.alias)
90 } else {
91 bound = String::new();
92 let dir = library::ParameterDirection::In;
93 let param_type = RustType::builder(env, prop.typ)
94 .direction(dir)
95 .nullable(prop.nullable)
96 .ref_mode(prop.set_in_ref_mode)
97 .try_build_param()
98 .into_string();
99 format!(", {}: {}", prop.var_name, param_type)
100 };
101 let return_str = if prop.is_get {
102 let dir = library::ParameterDirection::Return;
103 let ret_type = RustType::builder(env, prop.typ)
104 .direction(dir)
105 .nullable(prop.nullable)
106 .ref_mode(prop.get_out_ref_mode)
107 .try_build_param()
108 .into_string();
109 format!(" -> {ret_type}")
110 } else {
111 String::new()
112 };
113 format!(
114 "fn {}{}(&self{}){}",
115 prop.func_name, bound, set_param, return_str
116 )
117}
118
119fn body(env: &Env, prop: &Property, in_trait: bool) -> Chunk {
120 let mut builder = property_body::Builder::new(env);
121 builder
122 .name(&prop.name)
123 .in_trait(in_trait)
124 .var_name(&prop.var_name)
125 .is_get(prop.is_get);
126
127 if let Ok(type_) = RustType::try_new(env, prop.typ) {
128 builder.type_(type_.as_str());
129 } else {
130 builder.type_("/*Unknown type*/");
131 }
132
133 builder.generate()
134}