libgir/codegen/
record.rs

1use std::io::{Result, Write};
2
3use super::{function, general, trait_impls};
4use crate::{
5    analysis::{self, record_type::RecordType, special_functions::Type},
6    env::Env,
7    library,
8    traits::MaybeRef,
9};
10
11pub fn generate(w: &mut dyn Write, env: &Env, analysis: &analysis::record::Info) -> Result<()> {
12    let type_ = analysis.type_(&env.library);
13
14    general::start_comments(w, &env.config)?;
15    general::uses(w, env, &analysis.imports, type_.version)?;
16
17    if RecordType::of(env.type_(analysis.type_id).maybe_ref().unwrap()) == RecordType::AutoBoxed {
18        if let Some((ref glib_get_type, _)) = analysis.glib_get_type {
19            general::define_auto_boxed_type(
20                w,
21                env,
22                &analysis.name,
23                &type_.c_type,
24                analysis.boxed_inline,
25                &analysis.init_function_expression,
26                &analysis.copy_into_function_expression,
27                &analysis.clear_function_expression,
28                glib_get_type,
29                &analysis.derives,
30                analysis.visibility,
31                analysis.type_id,
32            )?;
33        } else {
34            panic!(
35                "Record {} has record_boxed=true but don't have glib:get_type function",
36                analysis.name
37            );
38        }
39    } else if let (Some(ref_fn), Some(unref_fn)) = (
40        analysis.specials.traits().get(&Type::Ref),
41        analysis.specials.traits().get(&Type::Unref),
42    ) {
43        general::define_shared_type(
44            w,
45            env,
46            &analysis.name,
47            &type_.c_type,
48            &ref_fn.glib_name,
49            &unref_fn.glib_name,
50            analysis.glib_get_type.as_ref().map(|(f, v)| {
51                if v > &analysis.version {
52                    (f.clone(), *v)
53                } else {
54                    (f.clone(), None)
55                }
56            }),
57            &analysis.derives,
58            analysis.visibility,
59            analysis.type_id,
60        )?;
61    } else if let (Some(copy_fn), Some(free_fn)) = (
62        analysis.specials.traits().get(&Type::Copy),
63        analysis.specials.traits().get(&Type::Free),
64    ) {
65        general::define_boxed_type(
66            w,
67            env,
68            &analysis.name,
69            &type_.c_type,
70            copy_fn,
71            &free_fn.glib_name,
72            analysis.boxed_inline,
73            &analysis.init_function_expression,
74            &analysis.copy_into_function_expression,
75            &analysis.clear_function_expression,
76            analysis.glib_get_type.as_ref().map(|(f, v)| {
77                if v > &analysis.version {
78                    (f.clone(), *v)
79                } else {
80                    (f.clone(), None)
81                }
82            }),
83            &analysis.derives,
84            analysis.visibility,
85            analysis.type_id,
86        )?;
87    } else {
88        panic!(
89            "Missing memory management functions for {}",
90            analysis.full_name
91        );
92    }
93
94    if analysis
95        .functions
96        .iter()
97        .any(|f| f.status.need_generate() && !f.hidden)
98    {
99        writeln!(w)?;
100        write!(w, "impl {} {{", analysis.name)?;
101
102        for func_analysis in &analysis.functions {
103            function::generate(
104                w,
105                env,
106                Some(analysis.type_id),
107                func_analysis,
108                Some(&analysis.specials),
109                analysis.version,
110                false,
111                false,
112                1,
113            )?;
114        }
115
116        writeln!(w, "}}")?;
117    }
118
119    general::declare_default_from_new(w, env, &analysis.name, &analysis.functions, false)?;
120
121    trait_impls::generate(
122        w,
123        env,
124        &analysis.name,
125        &analysis.functions,
126        &analysis.specials,
127        None,
128        analysis.version,
129        None, // There is no need for #[cfg()] since it's applied on the whole file.
130    )?;
131
132    if analysis.concurrency != library::Concurrency::None {
133        writeln!(w)?;
134    }
135
136    match analysis.concurrency {
137        library::Concurrency::Send | library::Concurrency::SendSync => {
138            writeln!(w, "unsafe impl Send for {} {{}}", analysis.name)?;
139        }
140        _ => (),
141    }
142
143    if analysis.concurrency == library::Concurrency::SendSync {
144        writeln!(w, "unsafe impl Sync for {} {{}}", analysis.name)?;
145    }
146
147    Ok(())
148}
149
150pub fn generate_reexports(
151    env: &Env,
152    analysis: &analysis::record::Info,
153    module_name: &str,
154    contents: &mut Vec<String>,
155) {
156    let cfg_condition = general::cfg_condition_string(analysis.cfg_condition.as_ref(), false, 0);
157    let version_cfg = general::version_condition_string(
158        env,
159        Some(analysis.type_id.ns_id),
160        analysis.version,
161        false,
162        0,
163    );
164    let mut cfg = String::new();
165    if let Some(s) = cfg_condition {
166        cfg.push_str(&s);
167        cfg.push('\n');
168    };
169    if let Some(s) = version_cfg {
170        cfg.push_str(&s);
171        cfg.push('\n');
172    };
173    contents.push(String::new());
174    contents.push(format!("{cfg}mod {module_name};"));
175    contents.push(format!(
176        "{}{} use self::{}::{};",
177        cfg,
178        analysis.visibility.export_visibility(),
179        module_name,
180        analysis.name
181    ));
182}