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

add a flag for generating variant traits for flags/enums #1418

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 9 additions & 0 deletions book/src/config_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ single_version_file = true
# which do not have an override for `generate_display_trait`
# (defaults to "true")
generate_display_trait = true
# Generation of Variant serialization traits enabled for all enums and flags which do not
# have an override for `generate_variant_traits`. Generates traits for StaticVariantType,
# ToVariant, FromVariant, and Into<Variant>. Can be "none" to skip generating traits,
# "repr" to serialize to INT (for enums) and UINT (for flags), or "string" to serialize to
# string values.
# (defaults to "none")
generate_variant_traits = "repr"
# Trust the nullability information about return values. If this is disabled
# then any pointer return type is assumed to be nullable unless there is an
# explicit override for it.
Expand Down Expand Up @@ -110,6 +117,8 @@ version = "3.12"
cfg_condition = "mycond"
# if you want to override default option Ex. for write your own Display implementation
generate_display_trait = false
# if you want to override default option Ex. for write your own Variant serialization
generate_variant_traits = "none"
# if you want to generate builder with name SomeClassBuilder
generate_builder = true
# trust return value nullability annotations for this specific type.
Expand Down
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") {
jf2048 marked this conversation as resolved.
Show resolved Hide resolved
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