Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate impl blocks for associated enum functions #991

Merged
merged 26 commits into from
Dec 7, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
bfb0a2d
Fix clippy::search_is_some
MarijnS95 Nov 25, 2020
a639364
Fix clippy::unnecessary_wraps
MarijnS95 Nov 25, 2020
e54e73f
env: Remove unnecessary `if` from main_sys_crate_name
MarijnS95 Nov 22, 2020
18d4a54
special_functions: Perform argument and ret validation on to_string
MarijnS95 Nov 30, 2020
68e4c73
special_functions: Rename ToString after the trait it impls: Display
MarijnS95 Nov 30, 2020
0f554d7
codegen/parameter: Do not pass ByRef::None as reference
MarijnS95 Nov 15, 2020
354c580
Remove unnecessary main_sys_crate_name imports
MarijnS95 Dec 5, 2020
ef8c22b
Generate associated functions for enums
MarijnS95 Aug 29, 2020
9bc5f6e
enum: all imports should go to one Imports as it's one file
MarijnS95 Aug 30, 2020
841582f
Only generate enum functions if >=1 function
MarijnS95 Sep 11, 2020
6e89f56
imports: Add support for multiple, lazily added declared symbols
MarijnS95 Nov 14, 2020
50cee9e
enums: Move rejection and glib imports from codegen to analysis
MarijnS95 Nov 14, 2020
70eab37
codegen/enums: Add missing trait_impls::generate call
MarijnS95 Nov 15, 2020
3023445
analysis/enums: Treat first function parameter as instance
MarijnS95 Nov 15, 2020
7123280
codegen: Add version condition on special function traits
MarijnS95 Nov 15, 2020
c3e827f
enums: Generate special to_str for static functions
MarijnS95 Nov 18, 2020
37366a2
enums: Do not inherit InfoBase to get rid of unused imports
MarijnS95 Nov 21, 2020
6a43595
analysis: Move enum discovery out of generic analyze() function
MarijnS95 Nov 21, 2020
e549975
Copypaste enum analysis and function generation to bitfield
MarijnS95 Nov 21, 2020
518d277
codegen/flags: Add missing display trait generation
MarijnS95 Nov 30, 2020
68760c0
codegen: Don't emit Rust Display impl when C function is available
MarijnS95 Nov 30, 2020
a1cfe65
special_functions: Add version condition to imports as well
MarijnS95 Dec 2, 2020
bf7dd09
special_functions: Only override to_string nullability if not trusted
MarijnS95 Dec 5, 2020
18c12a5
Separate special functions from traits
MarijnS95 Dec 6, 2020
5b32e69
Give more string-returning functions on flags/enums a static lifetime
MarijnS95 Dec 6, 2020
2915bde
Cargo update
MarijnS95 Dec 6, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Copypaste enum analysis and function generation to bitfield
  • Loading branch information
MarijnS95 committed Dec 6, 2020
commit e549975b156139e67b8325e9e74e76ef11ff8f9f
117 changes: 117 additions & 0 deletions src/analysis/flags.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
use super::{function_parameters::TransformationType, imports::Imports, *};
use crate::{config::gobjects::GObject, env::Env, nameutil::*, traits::*};

use log::info;

#[derive(Debug, Default)]
pub struct Info {
pub full_name: String,
pub type_id: library::TypeId,
pub name: String,
pub functions: Vec<functions::Info>,
pub specials: special_functions::Infos,
}

impl Info {
pub fn type_<'a>(&self, library: &'a library::Library) -> &'a library::Bitfield {
let type_ = library
.type_(self.type_id)
.maybe_ref()
.unwrap_or_else(|| panic!("{} is not an flags.", self.full_name));
type_
}
}

pub fn new(env: &Env, obj: &GObject, imports: &mut Imports) -> Option<Info> {
info!("Analyzing flags {}", obj.name);

if !obj.status.need_generate() {
return None;
}

if !obj
.type_id
.map_or(false, |tid| tid.ns_id == namespaces::MAIN)
{
return None;
}

let flags_tid = env.library.find_type(0, &obj.name)?;
let type_ = env.type_(flags_tid);
let flags: &library::Bitfield = type_.maybe_ref()?;

let name = split_namespace_name(&obj.name).1;

// Mark the type as available within the bitfield namespace:
imports.add_defined(&format!("crate::{}", name));

let has_get_type = flags.glib_get_type.is_some();
if has_get_type {
imports.add("glib::Type");
imports.add("glib::StaticType");
imports.add("glib::value::SetValue");
imports.add("glib::value::FromValue");
imports.add("glib::value::FromValueOptional");
}

if obj.generate_display_trait {
imports.add("std::fmt");
}

let mut functions = functions::analyze(
env,
&flags.functions,
flags_tid,
false,
false,
obj,
imports,
None,
None,
);

// Gir does not currently mark the first parameter of associated bitfield functions -
// that are identical to its bitfield type - as instance parameter since most languages
// do not support this.
for f in &mut functions {
if f.parameters.c_parameters.is_empty() {
continue;
}

let first_param = &mut f.parameters.c_parameters[0];

if first_param.typ == flags_tid {
first_param.instance_parameter = true;

let t = f
.parameters
.transformations
.iter_mut()
.find(|t| t.ind_c == 0)
.unwrap();

if let TransformationType::ToGlibScalar { name, .. } = &mut t.transformation_type {
*name = "self".to_owned();
} else {
panic!(
"Bitfield function instance param must be passed as scalar, not {:?}",
t.transformation_type
);
}
}
}

let specials = special_functions::extract(&mut functions, type_);

special_functions::analyze_imports(&specials, imports);

let info = Info {
full_name: obj.name.clone(),
type_id: flags_tid,
name: name.to_owned(),
functions,
specials,
};

Some(info)
}
30 changes: 30 additions & 0 deletions src/analysis/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub mod constants;
pub mod conversion_type;
pub mod enums;
pub mod ffi_type;
pub mod flags;
pub mod function_parameters;
pub mod functions;
pub mod general;
Expand Down Expand Up @@ -48,6 +49,9 @@ pub struct Analysis {
pub constants: Vec<constants::Info>,
pub enumerations: Vec<enums::Info>,
pub enum_imports: Imports,

pub flags: Vec<flags::Info>,
pub flags_imports: Imports,
}

pub fn run(env: &mut Env) {
Expand Down Expand Up @@ -90,6 +94,8 @@ pub fn run(env: &mut Env) {

analyze_enums(env);

analyze_flags(env);

analyze_constants(env);

// Analyze free functions as the last step once all types are analyzed
Expand Down Expand Up @@ -119,6 +125,30 @@ fn analyze_enums(env: &mut Env) {
env.analysis.enum_imports = imports;
}

fn analyze_flags(env: &mut Env) {
let mut imports = Imports::new(&env.library);
imports.add("glib::translate::*");
imports.add("bitflags::bitflags");

for obj in env.config.objects.values() {
if obj.status.ignored() {
continue;
}
let tid = match env.library.find_type(0, &obj.name) {
Some(x) => x,
None => continue,
};

if let Type::Bitfield(_) = env.library.type_(tid) {
if let Some(info) = flags::new(env, obj, &mut imports) {
env.analysis.flags.push(info);
}
}
}

env.analysis.flags_imports = imports;
}

fn analyze_global_functions(env: &mut Env) {
let ns = env.library.namespace(library::MAIN_NAMESPACE);

Expand Down
101 changes: 57 additions & 44 deletions src/codegen/flags.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::{function, trait_impls};
use crate::{
analysis::{imports::Imports, namespaces},
analysis::flags::Info,
codegen::general::{
self, cfg_deprecated, derives, version_condition, version_condition_string,
},
Expand All @@ -16,62 +17,40 @@ use std::{
};

pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec<String>) {
let configs: Vec<&GObject> = env
.config
.objects
.values()
.filter(|c| {
c.status.need_generate() && c.type_id.map_or(false, |tid| tid.ns_id == namespaces::MAIN)
})
.collect();
let has_any = configs
.iter()
.any(|c| matches!(*env.library.type_(c.type_id.unwrap()), Type::Bitfield(_)));

if !has_any {
if env.analysis.flags.is_empty() {
return;
}

let path = root_path.join("flags.rs");
file_saver::save_to_file(path, env.config.make_backup, |w| {
let mut imports = Imports::new(&env.library);
imports.add("glib::translate::*");
imports.add("bitflags::bitflags");

for config in &configs {
if let Type::Bitfield(ref flags) = *env.library.type_(config.type_id.unwrap()) {
if flags.glib_get_type.is_some() {
imports.add("glib::Type");
imports.add("glib::StaticType");
imports.add("glib::value::SetValue");
imports.add("glib::value::FromValue");
imports.add("glib::value::FromValueOptional");
break;
}
}
}

general::start_comments(w, &env.config)?;
general::uses(w, env, &imports)?;
general::uses(w, env, &env.analysis.flags_imports)?;
writeln!(w)?;

mod_rs.push("\nmod flags;".into());
for config in &configs {
if let Type::Bitfield(ref flags) = *env.library.type_(config.type_id.unwrap()) {
if let Some(cfg) = version_condition_string(env, flags.version, false, 0) {
mod_rs.push(cfg);
}
mod_rs.push(format!("pub use self::flags::{};", flags.name));
generate_flags(env, w, flags, config)?;
for flags_analysis in &env.analysis.flags {
let config = &env.config.objects[&flags_analysis.full_name];
let flags = flags_analysis.type_(&env.library);

if let Some(cfg) = version_condition_string(env, flags.version, false, 0) {
mod_rs.push(cfg);
}
mod_rs.push(format!("pub use self::flags::{};", flags.name));
generate_flags(env, w, flags, config, flags_analysis)?;
}

Ok(())
});
}

#[allow(clippy::write_literal)]
fn generate_flags(env: &Env, w: &mut dyn Write, flags: &Bitfield, config: &GObject) -> Result<()> {
fn generate_flags(
env: &Env,
w: &mut dyn Write,
flags: &Bitfield,
config: &GObject,
analysis: &Info,
) -> Result<()> {
let sys_crate_name = env.main_sys_crate_name();
cfg_deprecated(w, env, flags.deprecated_version, false, 0)?;
version_condition(w, env, flags.version, false, 0)?;
Expand Down Expand Up @@ -106,12 +85,46 @@ fn generate_flags(env: &Env, w: &mut dyn Write, flags: &Bitfield, config: &GObje

writeln!(
w,
"{}",
" }
}
"
" }}
}}"
)?;

let functions = analysis
.functions
.iter()
.filter(|f| f.status.need_generate())
.collect::<Vec<_>>();

if !functions.is_empty() {
let static_tostring = analysis
.specials
.get(&crate::analysis::special_functions::Type::Display)
.and_then(|f| if f.returns_static_ref { Some(f) } else { None });

writeln!(w)?;
version_condition(w, env, flags.version, false, 0)?;
write!(w, "impl {} {{", analysis.name)?;
for func_analysis in functions {
if Some(&func_analysis.glib_name) == static_tostring.map(|t| &t.glib_name) {
function::generate_static_to_str(w, env, func_analysis)?;
} else {
function::generate(w, env, func_analysis, false, false, 1)?;
}
}
writeln!(w, "}}")?;
}

trait_impls::generate(
w,
env,
&analysis.name,
&analysis.functions,
&analysis.specials,
None,
)?;

writeln!(w)?;

version_condition(w, env, flags.version, false, 0)?;
writeln!(
w,
Expand Down