Skip to content

Commit

Permalink
add a flag for generating variant traits for flags/enums
Browse files Browse the repository at this point in the history
  • Loading branch information
jf2048 committed Dec 12, 2022
1 parent 81c03ad commit 047ecef
Show file tree
Hide file tree
Showing 5 changed files with 311 additions and 25 deletions.
58 changes: 50 additions & 8 deletions src/codegen/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ use crate::{
cfg_deprecated, derives, doc_alias, version_condition, version_condition_no_doc,
version_condition_string,
},
generate_default_impl,
generate_default_impl, generate_variant_impls,
},
config::gobjects::GObject,
config::{config::VariantTraitMode, gobjects::GObject},
env::Env,
file_saver,
library::*,
Expand Down Expand Up @@ -387,14 +387,14 @@ impl FromGlib<{sys_crate_name}::{ffi_name}> for {name} {{
)?;
}

let configured_functions = config.functions.matched("get_type");
let version = std::iter::once(enum_.version)
.chain(configured_functions.iter().map(|f| f.version))
.max()
.flatten();

// Generate StaticType trait implementation.
if let Some(ref get_type) = enum_.glib_get_type {
let configured_functions = config.functions.matched("get_type");
let version = std::iter::once(enum_.version)
.chain(configured_functions.iter().map(|f| f.version))
.max()
.flatten();

version_condition(w, env, None, version, false, 0)?;
cfg_condition_no_doc(w, config.cfg_condition.as_ref(), false, 0)?;
allow_deprecated(w, enum_.deprecated_version, false, 0)?;
Expand Down Expand Up @@ -506,5 +506,47 @@ impl FromGlib<{sys_crate_name}::{ffi_name}> for {name} {{
},
)?;

match config.generate_variant_traits {
VariantTraitMode::Repr => generate_variant_impls(
w,
env,
config,
&enum_.name,
version,
enum_.deprecated_version,
"i",
"match unsafe { FromGlib::from_glib(variant.get::<i32>()?) } {
Self::__Unknown(_) => None,
value => Some(value),
}",
"self.into_glib().to_variant()",
)?,
VariantTraitMode::String => {
let enumclass = use_glib_type(env, "EnumClass");
generate_variant_impls(
w,
env,
config,
&enum_.name,
version,
enum_.deprecated_version,
"s",
&format!(
"if !variant.is::<String>() {{
return None;
}}
let enum_class = {enumclass}::new(<Self as StaticType>::static_type()).unwrap();
let value = enum_class.value_by_nick(variant.str()?)?.value();
Some(unsafe {{ FromGlib::from_glib(value) }})",
),
&format!(
"let enum_class = {enumclass}::new(<Self as StaticType>::static_type()).unwrap();
enum_class.value(self.into_glib()).unwrap().nick().to_variant()",
)
)?
}
_ => {}
}

Ok(())
}
54 changes: 46 additions & 8 deletions src/codegen/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ use crate::{
cfg_deprecated, derives, doc_alias, version_condition, version_condition_doc,
version_condition_no_doc, version_condition_string,
},
generate_default_impl,
generate_default_impl, generate_variant_impls,
},
config::gobjects::GObject,
config::{config::VariantTraitMode, gobjects::GObject},
env::Env,
file_saver,
library::*,
Expand Down Expand Up @@ -258,13 +258,13 @@ impl FromGlib<{sys_crate_name}::{ffi_name}> for {name} {{
assert = assert
)?;

if let Some(ref get_type) = flags.glib_get_type {
let configured_functions = config.functions.matched("get_type");
let version = std::iter::once(flags.version)
.chain(configured_functions.iter().map(|f| f.version))
.max()
.flatten();
let configured_functions = config.functions.matched("get_type");
let version = std::iter::once(flags.version)
.chain(configured_functions.iter().map(|f| f.version))
.max()
.flatten();

if let Some(ref get_type) = flags.glib_get_type {
version_condition(w, env, None, version, false, 0)?;
cfg_condition_no_doc(w, config.cfg_condition.as_ref(), false, 0)?;
allow_deprecated(w, flags.deprecated_version, false, 0)?;
Expand Down Expand Up @@ -357,5 +357,43 @@ impl FromGlib<{sys_crate_name}::{ffi_name}> for {name} {{
writeln!(w)?;
}

match config.generate_variant_traits {
VariantTraitMode::Repr => generate_variant_impls(
w,
env,
config,
&flags.name,
version,
flags.deprecated_version,
"u",
"Some(Self::from_bits(variant.get::<u32>()?)?)",
"self.into_glib().to_variant()",
)?,
VariantTraitMode::String => {
let flagsclass = use_glib_type(env, "FlagsClass");
generate_variant_impls(
w,
env,
config,
&flags.name,
version,
flags.deprecated_version,
"s",
&format!(
"if !variant.is::<String>() {{
return None;
}}
let flags_class = {flagsclass}::new(<Self as StaticType>::static_type()).unwrap();
Self::from_bits(flags_class.from_nick_string(variant.str()?).ok()?)",
),
&format!(
"let flags_class = {flagsclass}::new(<Self as StaticType>::static_type()).unwrap();
flags_class.to_nick_string(self.into_glib()).to_variant()",
)
)?
}
_ => {}
}

Ok(())
}
82 changes: 82 additions & 0 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::{
env::Env,
file_saver::*,
library::Member,
nameutil::use_glib_type,
version::Version,
};

Expand Down Expand Up @@ -43,6 +44,8 @@ mod trampoline;
mod trampoline_from_glib;
mod visibility;
pub use visibility::Visibility;

use self::general::{allow_deprecated, cfg_condition_no_doc};
mod trampoline_to_glib;
pub mod translate_from_glib;
pub mod translate_to_glib;
Expand Down Expand Up @@ -168,3 +171,82 @@ pub fn generate_default_impl<
Ok(())
}
}

pub fn generate_variant_impls(
w: &mut dyn Write,
env: &Env,
config: &GObject,
type_name: &str,
type_version: Option<Version>,
deprecated_version: Option<Version>,
static_variant_type_str: &str,
from_variant_impl: &str,
to_variant_impl: &str,
) -> Result<()> {
let assert = if env.config.generate_safety_asserts {
"skip_assert_initialized!();\n\t\t"
} else {
""
};
let gvariant = use_glib_type(env, "Variant");
let tovariant = use_glib_type(env, "ToVariant");

version_condition(w, env, None, type_version, false, 0)?;
cfg_condition_no_doc(w, config.cfg_condition.as_ref(), false, 0)?;
allow_deprecated(w, deprecated_version, false, 0)?;
writeln!(
w,
"impl {staticvarianttype} for {type_name} {{
fn static_variant_type() -> std::borrow::Cow<'static, {variantty}> {{
{assert}std::borrow::Cow::Borrowed(unsafe {{
{variantty}::from_str_unchecked(\"{static_variant_type_str}\")
}})
}}
}}",
staticvarianttype = use_glib_type(env, "StaticVariantType"),
variantty = use_glib_type(env, "VariantTy"),
)?;
writeln!(w)?;

version_condition(w, env, None, type_version, false, 0)?;
cfg_condition_no_doc(w, config.cfg_condition.as_ref(), false, 0)?;
allow_deprecated(w, deprecated_version, false, 0)?;
writeln!(
w,
"impl {fromvariant} for {type_name} {{
fn from_variant(variant: &{gvariant}) -> Option<Self> {{
{assert}{from_variant_impl}
}}
}}",
fromvariant = use_glib_type(env, "FromVariant"),
)?;
writeln!(w)?;

version_condition(w, env, None, type_version, false, 0)?;
cfg_condition_no_doc(w, config.cfg_condition.as_ref(), false, 0)?;
allow_deprecated(w, deprecated_version, false, 0)?;
writeln!(
w,
"impl {tovariant} for {type_name} {{
fn to_variant(&self) -> {gvariant} {{
{assert}{to_variant_impl}
}}
}}"
)?;
writeln!(w)?;

version_condition(w, env, None, type_version, false, 0)?;
cfg_condition_no_doc(w, config.cfg_condition.as_ref(), false, 0)?;
allow_deprecated(w, deprecated_version, false, 0)?;
writeln!(
w,
"impl From<{type_name}> for {gvariant} {{
fn from(v: {type_name}) -> Self {{
{assert}{tovariant}::to_variant(&v)
}}
}}",
)?;
writeln!(w)?;

Ok(())
}
43 changes: 43 additions & 0 deletions src/config/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,38 @@ impl GirVersion {
}
}

#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum VariantTraitMode {
#[default]
None,
Repr,
String,
}

impl VariantTraitMode {
pub fn is_none(self) -> bool {
self == Self::None
}
pub fn is_repr(self) -> bool {
self == Self::Repr
}
pub fn is_string(self) -> bool {
self == Self::String
}
}

impl FromStr for VariantTraitMode {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"none" => Ok(Self::None),
"repr" => Ok(Self::Repr),
"string" => Ok(Self::String),
e => Err(format!("Wrong variant trait mode: \"{}\"", e)),
}
}
}

#[derive(Debug)]
pub struct Config {
pub work_mode: WorkMode,
Expand All @@ -113,6 +145,7 @@ pub struct Config {
pub concurrency: library::Concurrency,
pub single_version_file: Option<PathBuf>,
pub generate_display_trait: bool,
pub generate_variant_traits: VariantTraitMode,
pub trust_return_value_nullability: bool,
pub docs_rs_features: Vec<String>,
pub disable_format: bool,
Expand Down Expand Up @@ -255,6 +288,13 @@ impl Config {
None => true,
};

let generate_variant_traits = match toml.lookup("options.generate_variant_traits") {
Some(v) => v
.as_result_str("options.generate_variant_traits")?
.parse()?,
None => Default::default(),
};

let trust_return_value_nullability =
match toml.lookup("options.trust_return_value_nullability") {
Some(v) => v.as_result_bool("options.trust_return_value_nullability")?,
Expand All @@ -281,6 +321,7 @@ impl Config {
t,
concurrency,
generate_display_trait,
generate_variant_traits,
generate_builder,
trust_return_value_nullability,
)
Expand All @@ -291,6 +332,7 @@ impl Config {
&toml,
concurrency,
generate_display_trait,
generate_variant_traits,
generate_builder,
trust_return_value_nullability,
);
Expand Down Expand Up @@ -367,6 +409,7 @@ impl Config {
concurrency,
single_version_file,
generate_display_trait,
generate_variant_traits,
trust_return_value_nullability,
docs_rs_features,
disable_format,
Expand Down
Loading

0 comments on commit 047ecef

Please sign in to comment.