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}