diff --git a/src/analysis/bounds.rs b/src/analysis/bounds.rs index c24342570..335b0381c 100644 --- a/src/analysis/bounds.rs +++ b/src/analysis/bounds.rs @@ -13,16 +13,19 @@ use crate::{ consts::TYPE_PARAMETERS_START, env::Env, library::{Basic, Class, Concurrency, Function, ParameterDirection, Type, TypeId}, + nameutil::use_glib_type, traits::IntoString, }; #[derive(Clone, Eq, Debug, PartialEq)] pub enum BoundType { NoWrapper, + Custom(String), // lifetime IsA(Option), // lifetime <- shouldn't be used but just in case... AsRef(Option), + Into, } impl BoundType { @@ -83,11 +86,19 @@ impl Bounds { func: &Function, par: &CParameter, r#async: bool, + future: bool, concurrency: Concurrency, configured_functions: &[&config::functions::Function], ) -> (Option, Option) { + if par.has_length && par.is_gstr(env) { + return (None, None); + } let type_name = RustType::builder(env, par.typ) - .ref_mode(RefMode::ByRefFake) + .ref_mode(if par.move_ || future { + RefMode::None + } else { + RefMode::ByRefFake + }) .try_build(); if type_name.is_err() { return (None, None); @@ -97,8 +108,13 @@ impl Bounds { let mut ret = None; let mut need_is_into_check = false; + let ref_mode = if par.move_ || future { + RefMode::None + } else { + par.ref_mode + }; if !par.instance_parameter && par.direction != ParameterDirection::Out { - if let Some(bound_type) = Bounds::type_for(env, par.typ) { + if let Some(bound_type) = Bounds::type_for(env, par.typ, ref_mode, &par.c_type) { ret = Some(Bounds::get_to_glib_extra( &bound_type, *par.nullable, @@ -188,7 +204,7 @@ impl Bounds { } } } else if par.instance_parameter { - if let Some(bound_type) = Bounds::type_for(env, par.typ) { + if let Some(bound_type) = Bounds::type_for(env, par.typ, ref_mode, &par.c_type) { ret = Some(Bounds::get_to_glib_extra( &bound_type, *par.nullable, @@ -201,10 +217,28 @@ impl Bounds { (ret, callback_info) } - pub fn type_for(env: &Env, type_id: TypeId) -> Option { + pub fn type_for( + env: &Env, + type_id: TypeId, + ref_mode: RefMode, + c_type: &str, + ) -> Option { use self::BoundType::*; match env.library.type_(type_id) { Type::Basic(Basic::Filename | Basic::OsString) => Some(AsRef(None)), + Type::Basic(Basic::Utf8) => { + if ref_mode.is_ref() { + Some(Custom(use_glib_type(env, "IntoGStr"))) + } else { + Some(Into) + } + } + Type::CArray(inner) + if matches!(env.type_(*inner), Type::Basic(Basic::Utf8)) + && !matches!(c_type, "char**" | "gchar**") => + { + Some(Custom(use_glib_type(env, "IntoStrV"))) + } Type::Class(Class { is_fundamental: true, .. @@ -238,6 +272,8 @@ impl Bounds { IsA(_) if nullable && !instance_parameter => ".map(|p| p.as_ref())".to_owned(), IsA(_) if move_ => ".upcast()".to_owned(), IsA(_) => ".as_ref()".to_owned(), + Into if nullable => ".map(|p| p.into())".to_owned(), + Into => ".into()".to_owned(), _ => String::new(), } } @@ -276,7 +312,7 @@ impl Bounds { use self::BoundType::*; for used in &self.used { match used.bound_type { - NoWrapper => (), + NoWrapper | Custom(_) | Into => (), IsA(_) => imports.add("glib::prelude::*"), AsRef(_) => imports.add_used_type(&used.type_str), } diff --git a/src/analysis/child_properties.rs b/src/analysis/child_properties.rs index 9c6ef572c..5031fa151 100644 --- a/src/analysis/child_properties.rs +++ b/src/analysis/child_properties.rs @@ -1,3 +1,5 @@ +use std::fmt::Write; + use log::error; use crate::{ @@ -120,22 +122,30 @@ fn analyze_property( let mut bounds_str = String::new(); let dir = ParameterDirection::In; - let set_params = if let Some(bound) = Bounds::type_for(env, typ) { + let set_params = if let Some(bound) = Bounds::type_for(env, typ, RefMode::None, "") { let r_type = RustType::builder(env, typ) - .ref_mode(RefMode::ByRefFake) + .ref_mode(RefMode::None) .try_build() .into_string(); - let _bound = Bound { + let bound = Bound { bound_type: bound, parameter_name: TYPE_PARAMETERS_START.to_string(), alias: Some(TYPE_PARAMETERS_START.to_owned()), type_str: r_type, callback_modified: false, }; - // TODO: bounds_str push?!?! - bounds_str.push_str("TODO"); - format!("{prop_name}: {TYPE_PARAMETERS_START}") + write!( + bounds_str, + "{TYPE_PARAMETERS_START}: {}", + bound.trait_bound(false) + ) + .unwrap(); + if *nullable { + format!("{prop_name}: Option<{TYPE_PARAMETERS_START}>") + } else { + format!("{prop_name}: {TYPE_PARAMETERS_START}") + } // let mut bounds = Bounds::default(); // bounds.add_parameter("P", &r_type, bound, false); // let (s_bounds, _) = function::bounds(&bounds, &[], false); diff --git a/src/analysis/class_builder.rs b/src/analysis/class_builder.rs index f7ab0870e..0dd1f753c 100644 --- a/src/analysis/class_builder.rs +++ b/src/analysis/class_builder.rs @@ -124,7 +124,12 @@ fn analyze_property( let (get_out_ref_mode, set_in_ref_mode, nullable) = get_property_ref_modes(env, prop); let mut bounds = Bounds::default(); - if let Some(bound) = Bounds::type_for(env, prop.typ) { + if let Some(bound) = Bounds::type_for( + env, + prop.typ, + super::ref_mode::RefMode::None, + prop.c_type.as_deref().unwrap_or_default(), + ) { imports.add("glib::prelude::*"); bounds.add_parameter(&prop.name, &rust_type_res.into_string(), bound, false); } diff --git a/src/analysis/function_parameters.rs b/src/analysis/function_parameters.rs index 5cd5384de..6d7f45ef7 100644 --- a/src/analysis/function_parameters.rs +++ b/src/analysis/function_parameters.rs @@ -63,6 +63,7 @@ pub struct CParameter { pub transfer: library::Transfer, pub caller_allocates: bool, pub is_error: bool, + pub has_length: bool, pub scope: ParameterScope, /// Index of the user data parameter associated with the callback. pub user_data_index: Option, @@ -76,6 +77,25 @@ pub struct CParameter { pub move_: bool, } +impl CParameter { + pub fn is_gstr(&self, env: &Env) -> bool { + matches!( + env.type_(self.typ), + library::Type::Basic(library::Basic::Utf8) + ) && self.ref_mode.is_ref() + } + pub fn is_strv(&self, env: &Env) -> bool { + if let library::Type::CArray(inner) = env.type_(self.typ) { + matches!( + env.type_(*inner), + library::Type::Basic(library::Basic::Utf8) + ) && !matches!(self.c_type.as_str(), "char**" | "gchar**") + } else { + false + } + } +} + #[derive(Clone, Debug)] pub enum TransformationType { ToGlibDirect { @@ -89,6 +109,7 @@ pub enum TransformationType { ToGlibPointer { name: String, instance_parameter: bool, + typ: library::TypeId, transfer: library::Transfer, ref_mode: RefMode, // filled by functions @@ -110,20 +131,28 @@ pub enum TransformationType { }, IntoRaw(String), ToSome(String), + AsPtr(String), + RunWith { + name: String, + func: String, + inner: Box, + }, } impl TransformationType { pub fn is_to_glib(&self) -> bool { - matches!( - *self, + match self { Self::ToGlibDirect { .. } - | Self::ToGlibScalar { .. } - | Self::ToGlibPointer { .. } - | Self::ToGlibBorrow - | Self::ToGlibUnknown { .. } - | Self::ToSome(_) - | Self::IntoRaw(_) - ) + | Self::ToGlibScalar { .. } + | Self::ToGlibPointer { .. } + | Self::ToGlibBorrow + | Self::ToGlibUnknown { .. } + | Self::ToSome(_) + | Self::IntoRaw(_) + | Self::AsPtr(_) => true, + Self::RunWith { inner, .. } => inner.is_to_glib(), + _ => false, + } } pub fn set_to_glib_extra(&mut self, to_glib_extra_: &str) { @@ -269,6 +298,7 @@ pub fn analyze( transfer == Transfer::Full && par.direction.is_in() } }); + let mut array_par = configured_parameters.iter().find_map(|cp| { cp.length_of .as_ref() @@ -278,11 +308,18 @@ pub fn analyze( array_par = array_lengths.get(&(pos as u32)).copied(); } if array_par.is_none() && !disable_length_detect { - array_par = detect_length(env, pos, par, function_parameters); + array_par = detect_array(env, pos, par, function_parameters); } if let Some(array_par) = array_par { let mut array_name = nameutil::mangle_keywords(&array_par.name); - if let Some(bound_type) = Bounds::type_for(env, array_par.typ) { + let ref_mode = if array_par.transfer == Transfer::Full { + RefMode::None + } else { + RefMode::of(env, array_par.typ, array_par.direction) + }; + if let Some(bound_type) = + Bounds::type_for(env, array_par.typ, ref_mode, &array_par.c_type) + { array_name = (array_name.into_owned() + &Bounds::get_to_glib_extra( &bound_type, @@ -302,6 +339,9 @@ pub fn analyze( }; parameters.transformations.push(transformation); } + let has_length = par.array_length.is_some() + || (!disable_length_detect + && detect_length(env, pos, par, function_parameters).is_some()); let immutable = configured_parameters.iter().any(|p| p.constant); let ref_mode = @@ -323,6 +363,7 @@ pub fn analyze( nullable, ref_mode, is_error: par.is_error, + has_length, scope: par.scope, user_data_index: par.closure, destroy_index: par.destroy, @@ -389,6 +430,7 @@ pub fn analyze( ConversionType::Pointer => TransformationType::ToGlibPointer { name, instance_parameter: par.instance_parameter, + typ, transfer, ref_mode, to_glib_extra: Default::default(), @@ -434,6 +476,26 @@ pub fn analyze( if let Some(transformation_type) = transformation_type { transformation.transformation_type = transformation_type; } + + let c_par = parameters.c_parameters.last().unwrap(); + if c_par.is_gstr(env) && !has_length { + transformation.transformation_type = TransformationType::RunWith { + name: c_par.name.clone(), + func: if *c_par.nullable { + nameutil::use_glib_type(env, "IntoOptionalGStr::run_with_gstr") + } else { + nameutil::use_glib_type(env, "IntoGStr::run_with_gstr") + }, + inner: Box::new(transformation.transformation_type), + }; + } else if c_par.is_strv(env) { + transformation.transformation_type = TransformationType::RunWith { + name: c_par.name.clone(), + func: nameutil::use_glib_type(env, "IntoStrV::run_with_strv"), + inner: Box::new(TransformationType::AsPtr(c_par.name.clone())), + }; + } + parameters.transformations.push(transformation); } @@ -460,30 +522,33 @@ fn detect_length<'a>( par: &library::Parameter, parameters: &'a [library::Parameter], ) -> Option<&'a library::Parameter> { - if !is_length(par) || pos == 0 { + if !has_length(env, par.typ) { return None; } - parameters.get(pos - 1).and_then(|p| { - if has_length(env, p.typ) { - Some(p) - } else { - None - } - }) + parameters + .get(pos + 1) + .and_then(|p| is_length(p).then_some(p)) } -fn is_length(par: &library::Parameter) -> bool { - if par.direction != library::ParameterDirection::In { - return false; +fn detect_array<'a>( + env: &Env, + pos: usize, + par: &library::Parameter, + parameters: &'a [library::Parameter], +) -> Option<&'a library::Parameter> { + if pos == 0 || !is_length(par) { + return None; } - let len = par.name.len(); - if len >= 3 && &par.name[len - 3..len] == "len" { - return true; - } + parameters + .get(pos - 1) + .and_then(|p| has_length(env, p.typ).then_some(p)) +} - par.name.contains("length") +fn is_length(par: &library::Parameter) -> bool { + par.direction == library::ParameterDirection::In + && (par.name.ends_with("len") || par.name.contains("length")) } fn has_length(env: &Env, typ: TypeId) -> bool { diff --git a/src/analysis/functions.rs b/src/analysis/functions.rs index 62313bea1..65348af89 100644 --- a/src/analysis/functions.rs +++ b/src/analysis/functions.rs @@ -57,6 +57,7 @@ pub struct AsyncFuture { pub success_parameters: String, pub error_parameters: Option, pub assertion: SafetyAssertionMode, + pub bounds: Bounds, } #[derive(Debug)] @@ -257,6 +258,7 @@ fn fixup_gpointer_parameter( transformation_type: TransformationType::ToGlibPointer { name: parameters.rust_parameters[idx].name.clone(), instance_parameter, + typ: parameters.rust_parameters[idx].typ, transfer: Transfer::None, ref_mode: RefMode::ByRef, to_glib_extra: Default::default(), @@ -379,6 +381,7 @@ fn analyze_callbacks( func, par, false, + false, concurrency, configured_functions, ); @@ -757,6 +760,7 @@ fn analyze_function( func, par, r#async, + false, library::Concurrency::None, configured_functions, ); @@ -1055,6 +1059,19 @@ fn analyze_async( }); if !no_future { + let mut bounds: Bounds = Default::default(); + // force the bounds on async functions to be for owned types + for par in parameters.c_parameters.iter() { + bounds.add_for_parameter( + env, + func, + par, + true, + true, + library::Concurrency::None, + configured_functions, + ); + } *async_future = Some(AsyncFuture { is_method, name: format!("{}_future", codegen_name.trim_end_matches("_async")), @@ -1066,6 +1083,7 @@ fn analyze_async( // need to do it twice. _ => SafetyAssertionMode::Skip, }, + bounds, }); } true diff --git a/src/chunk/chunk.rs b/src/chunk/chunk.rs index a3225db3d..41fe86a01 100644 --- a/src/chunk/chunk.rs +++ b/src/chunk/chunk.rs @@ -29,6 +29,11 @@ pub enum Chunk { array_length_name: Option, call: Box, }, + RunWith { + name: String, + func: String, + body: Box, + }, Let { name: String, is_mut: bool, diff --git a/src/codegen/bound.rs b/src/codegen/bound.rs index 7a5d998aa..c4772bcf3 100644 --- a/src/codegen/bound.rs +++ b/src/codegen/bound.rs @@ -52,10 +52,12 @@ impl Bound { format!("Option<{ref_str}{trait_bound}>") } BoundType::IsA(_) => format!("{ref_str}{trait_bound}"), - BoundType::AsRef(_) if *nullable => { + BoundType::AsRef(_) | BoundType::Custom(_) | BoundType::Into if *nullable => { format!("Option<{trait_bound}>") } - BoundType::NoWrapper | BoundType::AsRef(_) => trait_bound, + BoundType::NoWrapper | BoundType::AsRef(_) | BoundType::Custom(_) | BoundType::Into => { + trait_bound + } } } @@ -68,9 +70,10 @@ impl Bound { /// Returns the trait bound, usually of the form `SomeTrait` /// or `IsA`. - pub(super) fn trait_bound(&self, r#async: bool) -> String { - match self.bound_type { + pub fn trait_bound(&self, r#async: bool) -> String { + match &self.bound_type { BoundType::NoWrapper => self.type_str.clone(), + BoundType::Custom(bound) => bound.clone(), BoundType::IsA(lifetime) => { if r#async { assert!(lifetime.is_none(), "Async overwrites lifetime"); @@ -78,7 +81,7 @@ impl Bound { let is_a = format!("IsA<{}>", self.type_str); let lifetime = r#async - .then(|| " + Clone + 'static".to_string()) + .then(|| " + 'static".to_string()) .or_else(|| lifetime.map(|l| format!(" + '{l}"))) .unwrap_or_default(); @@ -86,6 +89,7 @@ impl Bound { } BoundType::AsRef(Some(_ /* lifetime */)) => panic!("AsRef cannot have a lifetime"), BoundType::AsRef(None) => format!("AsRef<{}>", self.type_str), + BoundType::Into => format!("Into<{}>", self.type_str), } } } diff --git a/src/codegen/child_properties.rs b/src/codegen/child_properties.rs index 0296db7cc..872305463 100644 --- a/src/codegen/child_properties.rs +++ b/src/codegen/child_properties.rs @@ -127,6 +127,7 @@ fn body(env: &Env, prop: &ChildProperty, in_trait: bool, is_get: bool) -> Chunk .name(&prop.name) .in_trait(in_trait) .var_name(&prop.prop_name) + .type_id(prop.typ) .is_get(is_get); if let Ok(type_) = RustType::try_new(env, prop.typ) { diff --git a/src/codegen/function.rs b/src/codegen/function.rs index 1443d4f5b..7cb77f4ae 100644 --- a/src/codegen/function.rs +++ b/src/codegen/function.rs @@ -17,7 +17,7 @@ use super::{ special_functions, }; use crate::{ - analysis::{self, bounds::Bounds, try_from_glib::TryFromGlib}, + analysis::{self, bounds::Bounds, ref_mode::RefMode, try_from_glib::TryFromGlib}, chunk::{ffi_function_todo, Chunk}, env::Env, library::{self, TypeId}, @@ -263,7 +263,7 @@ pub fn declaration_futures(env: &Env, analysis: &analysis::functions::Info) -> S if c_par.name == "callback" || c_par.name == "cancellable" { skipped += 1; - if let Some(alias) = analysis + if let Some(alias) = async_future .bounds .get_parameter_bound(&c_par.name) .and_then(|bound| bound.type_parameter_reference()) @@ -277,11 +277,11 @@ pub fn declaration_futures(env: &Env, analysis: &analysis::functions::Info) -> S param_str.push_str(", "); } - let s = c_par.to_parameter(env, &analysis.bounds, true); + let s = c_par.to_parameter(env, &async_future.bounds, true); param_str.push_str(&s); } - let (bounds, _) = bounds(&analysis.bounds, skipped_bounds.as_ref(), true, false); + let (bounds, _) = bounds(&async_future.bounds, skipped_bounds.as_ref(), true, false); format!( "fn {}{}({}){}", @@ -405,8 +405,6 @@ pub fn body_chunk_futures( ) -> StdResult { use std::fmt::Write; - use crate::analysis::ref_mode::RefMode; - let async_future = analysis.async_future.as_ref().unwrap(); let mut body = String::new(); @@ -429,7 +427,8 @@ pub fn body_chunk_futures( // Skip the instance parameter for par in analysis.parameters.rust_parameters.iter().skip(skip) { - if par.name == "cancellable" || par.name == "callback" { + let name = &par.name; + if name == "cancellable" || name == "callback" { continue; } @@ -438,16 +437,12 @@ pub fn body_chunk_futures( let type_ = env.type_(par.typ); let is_str = matches!(*type_, library::Type::Basic(library::Basic::Utf8)); - if *c_par.nullable { - writeln!( - body, - "let {} = {}.map(ToOwned::to_owned);", - par.name, par.name - )?; - } else if is_str { - writeln!(body, "let {} = String::from({});", par.name, par.name)?; - } else if c_par.ref_mode != RefMode::None { - writeln!(body, "let {} = {}.clone();", par.name, par.name)?; + if is_str { + if *c_par.nullable { + writeln!(body, "let {name} = {name}.map(|s| s.into());",)?; + } else { + writeln!(body, "let {name} = {name}.into();",)?; + } } } @@ -479,14 +474,21 @@ pub fn body_chunk_futures( continue; } else { let c_par = &analysis.parameters.c_parameters[par.ind_c]; + let type_ = env.type_(par.typ); + let is_str = matches!(*type_, library::Type::Basic(library::Basic::Utf8)); + let ref_mode = if c_par.move_ { + RefMode::None + } else { + c_par.ref_mode + }; - if *c_par.nullable { + if !is_str && *c_par.nullable { writeln!( body, "\t\t{}.as_ref().map(::std::borrow::Borrow::borrow),", par.name )?; - } else if c_par.ref_mode != RefMode::None { + } else if !is_str && ref_mode.is_ref() { writeln!(body, "\t\t&{},", par.name)?; } else { writeln!(body, "\t\t{},", par.name)?; diff --git a/src/codegen/function_body_chunk.rs b/src/codegen/function_body_chunk.rs index 8a1253e40..d5d48dca5 100644 --- a/src/codegen/function_body_chunk.rs +++ b/src/codegen/function_body_chunk.rs @@ -332,7 +332,8 @@ impl Builder { } else { Chunk::Unsafe(body) }); - Chunk::BlockHalf(chunks) + let chunk = self.generate_run_withs(Chunk::Chunks(chunks)); + Chunk::BlockHalf(vec![chunk]) } fn remove_extra_assume_init( @@ -978,6 +979,21 @@ impl Builder { params, } } + fn generate_run_withs(&self, mut call: Chunk) -> Chunk { + for trans in self.transformations.iter().rev() { + let par = &self.parameters[trans.ind_c]; + if let In = par { + if let TransformationType::RunWith { name, func, .. } = &trans.transformation_type { + call = Chunk::RunWith { + name: name.clone(), + func: func.clone(), + body: Box::new(call), + }; + } + } + } + call + } fn generate_call_conversion( &self, call: Chunk, diff --git a/src/codegen/parameter.rs b/src/codegen/parameter.rs index efdada344..78a310516 100644 --- a/src/codegen/parameter.rs +++ b/src/codegen/parameter.rs @@ -13,7 +13,7 @@ pub trait ToParameter { impl ToParameter for CParameter { fn to_parameter(&self, env: &Env, bounds: &Bounds, r#async: bool) -> String { - let ref_mode = if self.move_ { + let ref_mode = if self.move_ || (r#async && !self.instance_parameter) { RefMode::None } else { self.ref_mode diff --git a/src/codegen/properties.rs b/src/codegen/properties.rs index 5ae3abe57..6a96e7fac 100644 --- a/src/codegen/properties.rs +++ b/src/codegen/properties.rs @@ -126,6 +126,7 @@ fn body(env: &Env, prop: &Property, in_trait: bool) -> Chunk { .name(&prop.name) .in_trait(in_trait) .var_name(&prop.var_name) + .type_id(prop.typ) .is_get(prop.is_get); if let Ok(type_) = RustType::try_new(env, prop.typ) { diff --git a/src/codegen/property_body.rs b/src/codegen/property_body.rs index b18a7c716..e613c9c9f 100644 --- a/src/codegen/property_body.rs +++ b/src/codegen/property_body.rs @@ -1,6 +1,7 @@ use crate::{ chunk::Chunk, env::Env, + library, nameutil::{use_glib_type, use_gtk_type}, }; @@ -11,6 +12,7 @@ pub struct Builder<'a> { is_get: bool, is_child_property: bool, type_: String, + type_id: library::TypeId, env: &'a Env, } @@ -24,6 +26,7 @@ impl<'a> Builder<'a> { is_get: Default::default(), is_child_property: Default::default(), type_: Default::default(), + type_id: Default::default(), } } @@ -36,6 +39,7 @@ impl<'a> Builder<'a> { var_name: Default::default(), is_get: Default::default(), type_: Default::default(), + type_id: Default::default(), } } @@ -64,6 +68,11 @@ impl<'a> Builder<'a> { self } + pub fn type_id(&mut self, type_id: library::TypeId) -> &mut Self { + self.type_id = type_id; + self + } + pub fn generate(&self) -> Chunk { let chunks = if self.is_get { self.chunks_for_get() @@ -105,18 +114,28 @@ impl<'a> Builder<'a> { fn chunks_for_set(&self) -> Vec { if self.is_child_property { + let is_str = matches!( + self.env.type_(self.type_id), + library::Type::Basic(library::Basic::Utf8) + ); let self_ = if self.in_trait { "self.as_ref()" } else { "self" }; + let var_name = if is_str { + // string properties are always nullable + format!("{}.map(|p| p.into())", self.var_name) + } else { + self.var_name.clone() + }; vec![Chunk::Custom(format!( "{}::child_set_property({}, &item.clone().upcast(),\"{}\", &{})", use_gtk_type(self.env, "prelude::ContainerExtManual"), self_, self.name, - self.var_name + var_name ))] } else { let self_ = if self.in_trait { diff --git a/src/codegen/translate_to_glib.rs b/src/codegen/translate_to_glib.rs index 2d3b4afaf..686ece69e 100644 --- a/src/codegen/translate_to_glib.rs +++ b/src/codegen/translate_to_glib.rs @@ -50,6 +50,8 @@ impl TranslateToGlib for TransformationType { ToGlibUnknown { ref name } => format!("/*Unknown conversion*/{name}"), ToSome(ref name) => format!("Some({name})"), IntoRaw(ref name) => format!("Box_::into_raw({name}) as *mut _"), + AsPtr(ref name) => format!("{name}.as_ptr() as *mut _"), + RunWith { ref inner, .. } => inner.translate_to_glib(), _ => unreachable!("Unexpected transformation type {:?}", self), } } diff --git a/src/writer/to_code.rs b/src/writer/to_code.rs index 8b7c16fe7..d453e4437 100644 --- a/src/writer/to_code.rs +++ b/src/writer/to_code.rs @@ -60,6 +60,19 @@ impl ToCode for Chunk { let s = format_block_one_line(&prefix, &suffix, &call_strings, "", ""); vec![s] } + RunWith { + ref name, + ref func, + ref body, + } => { + let mut body = body.to_code(env); + for line in &mut body { + line.insert(0, '\t'); + } + body.insert(0, format!("{func}({name}, |{name}| {{")); + body.push("})".into()); + body + } Let { ref name, is_mut,