Commit f6a513a9 authored by mredlek's avatar mredlek Committed by Federico Mena Quintero

Avoid trampolines.

It creates a new extension-traits with can contain the implementation
parent 140dad63
......@@ -14,6 +14,21 @@ test = false
# If this feature is enabled, it executes the tests with the
# rust files generated during an earlier run.
test-generated = []
single-test = []
single-test-argument-types = [ "single-test" ]
single-test-basic = [ "single-test" ]
single-test-c_derive = [ "single-test" ]
single-test-counter_c_impl = [ "single-test" ]
single-test-drop = [ "single-test" ]
single-test-floating-refs = [ "single-test" ]
single-test-gir = [ "single-test" ]
single-test-interfaces = [ "single-test" ]
single-test-memory-layout = [ "single-test" ]
single-test-no-instance-private = [ "single-test" ]
single-test-override = [ "single-test" ]
single-test-properties = [ "single-test" ]
single-test-signals = [ "single-test" ]
single-test-variant = [ "single-test" ]
[dependencies]
glib = "0.5.0"
......
......@@ -103,6 +103,7 @@ impl<'ast, T: Boilerplate<'ast>> BoilerplateExt<'ast> for T {
extern crate libc;
#[allow(unused_imports)]
use glib::IsA;
#[allow(unused_imports)]
......@@ -139,6 +140,8 @@ impl<'ast, T: Boilerplate<'ast>> BoilerplateExt<'ast> for T {
let instance = crate::gen::instance::Instance::new(self);
let public = crate::gen::public::Public::new(self);
let public_imp = crate::gen::public::PublicImp::new(self);
let instance_ext = self.names().instance_ext();
let private = crate::gen::private::Private::new(self);
quote! {
#[allow(non_snake_case)] // "oddly" named module above
......@@ -162,6 +165,9 @@ impl<'ast, T: Boilerplate<'ast>> BoilerplateExt<'ast> for T {
#[allow(unused_imports)]
use glib::translate::*;
use glib::object::ObjectExt;
#[allow(unused_imports)]
use glib::IsA;
#[allow(unused_imports)]
use std::ffi::CString;
......@@ -174,12 +180,17 @@ impl<'ast, T: Boilerplate<'ast>> BoilerplateExt<'ast> for T {
#private_static
#public_imp
#private
}
#public
}
pub use #ModuleName::*;
pub use #ModuleName::imp::#instance_ext;
}
}
......
use crate::hir::FnSig;
use proc_macro2::TokenStream;
pub trait FnSigExt
{
fn signal_definition(&self) -> TokenStream;
}
impl<'ast> FnSigExt for FnSig<'ast>
{
fn signal_definition(&self) -> TokenStream
{
let name = self.name.clone();
let inputs = &self.inputs;
let output = &self.output;
quote! {
fn #name(#(#inputs),*) -> #output
}
}
}
......@@ -72,7 +72,7 @@ pub fn slot_trait_impls<'ast>(names: &Names, slots: &[Slot<'ast>]) -> Vec<TokenS
let arg_names = sig.input_args_to_glib_types();
let value = quote! {
unsafe {
imp::#ffi_name(self.to_glib_none().0,
imp::#ffi_name(self.to_glib_none().0
#arg_names)
}
};
......
......@@ -9,6 +9,7 @@ mod boilerplateext;
mod class;
mod cstringliteral;
pub mod gir;
mod fnsig_ext;
mod imp;
mod instance;
mod instance_ext;
......@@ -17,9 +18,11 @@ mod privatestatic;
mod properties;
mod property_ext;
mod public;
mod private;
mod signals;
mod signatures;
mod slots;
mod slot_ext;
mod writer;
pub use self::boilerplate::Boilerplate;
......@@ -27,11 +30,14 @@ pub use self::boilerplateext::BoilerplateExt;
pub use self::class::Class;
pub use self::instance::Instance;
pub use self::interface::Interface;
pub use self::property_ext::PropertyGenExt;
pub use self::private::Private;
use self::writer::RustWriter;
use crate::hir::Program;
pub use self::ancestorext::AncestorRefExt;
use self::slot_ext::SlotExt;
use self::property_ext::PropertyGenExt;
use self::fnsig_ext::FnSigExt;
pub fn codegen(program: &Program<'_>) -> TokenStream {
let mut writer = RustWriter::new();
......
use super::boilerplate;
use super::SlotExt;
use crate::gen::boilerplateext::BoilerplateExt;
use proc_macro2::TokenStream;
use quote::ToTokens;
use std::marker::PhantomData;
/// This class can generate the public part of the boilerplate code for objects
pub struct Private<'lt, 'ast: 'lt, Boilerplate: boilerplate::Boilerplate<'ast> + 'lt> {
boilerplate: &'lt Boilerplate,
phantom: PhantomData<&'ast ()>,
}
impl<'lt, 'ast: 'lt, Boilerplate: boilerplate::Boilerplate<'ast>> Private<'lt, 'ast, Boilerplate> {
pub fn new(boilerplate: &'lt Boilerplate) -> Self {
let phantom = PhantomData;
Private {
boilerplate,
phantom,
}
}
}
impl<'lt, 'ast: 'lt, Boilerplate: boilerplate::Boilerplate<'ast>> ToTokens for Private<'lt, 'ast, Boilerplate>
{
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.extend(self.gen_def_trait_ext_priv());
}
}
impl<'lt, 'ast: 'lt, Boilerplate: boilerplate::Boilerplate<'ast>> Private<'lt, 'ast, Boilerplate>
{
fn gen_def_trait_ext_priv(&self) -> TokenStream {
let instance_ext_priv = self.boilerplate.names().instance_ext_priv();
let name = self.boilerplate.names().instance();
let ancestors = self.boilerplate.ancestors().iter().filter(|anc| !anc.is_fundamental()).map(|anc| anc.instance());
let get_priv_def = self.gen_get_priv_def();
let get_priv_impl = self.gen_get_priv_impl();
let slot_def = self.boilerplate.slots().iter().filter(|slot| !slot.public())
.map(|slot| slot.trait_definition());
let slot_impl = self.boilerplate.slots().iter().filter(|slot| !slot.public())
.map(|slot| slot.trait_implementation(self.boilerplate.names()));
let signal_emit_methods =
crate::gen::signals::signal_emit_methods(self.boilerplate.signals());
let signal_emit_methods_declarations =
crate::gen::signals::signal_emit_methods_declaration(self.boilerplate.signals());
quote! {
trait #instance_ext_priv {
#get_priv_def
#(#slot_def)*
#signal_emit_methods_declarations
}
impl<T: IsA<#name> #(+ IsA<#ancestors>)* + IsA<::glib::Object> + ::glib::value::SetValue> #instance_ext_priv for T
{
#get_priv_impl
#(#slot_impl)*
#signal_emit_methods
}
}
}
fn gen_get_priv_def(&self) -> TokenStream {
if !self.boilerplate.has_private() {
return TokenStream::new();
}
let instance_private = self.boilerplate.names().instance_private();
quote! {
fn get_priv(&self) -> &#instance_private;
}
}
fn gen_get_priv_impl(&self) -> TokenStream {
if !self.boilerplate.has_private() {
return TokenStream::new();
}
let instance_private = self.boilerplate.names().instance_private();
let instance_ffi = self.boilerplate.names().instance_ffi();
quote! {
#[allow(dead_code)]
fn get_priv(&self) -> &#instance_private {
let glib : *mut #instance_ffi = self.to_glib_none().0;
unsafe {
&*((glib as *const u8).wrapping_offset(PRIV.private_offset as isize) as *const #instance_private)
}
}
}
}
}
\ No newline at end of file
......@@ -115,13 +115,8 @@ where
let type_ = prop.type_;
quote! {
fn #name(&self, v: #type_) {
unsafe {
gobject_ffi::g_object_set_property(
self.to_glib_none().0,
#name_str.to_glib_none().0,
glib::Value::from(&v).to_glib_none().0);
}
fn #name(&self, v: #type_) -> Result<(), ::glib::error::BoolError> {
::glib::ObjectExt::set_property(self, #name_str, &v)
}
}
})
......@@ -143,14 +138,7 @@ where
quote! {
fn #name(&self) -> #type_ {
let mut value = glib::Value::from(&#type_::default());
unsafe {
gobject_ffi::g_object_get_property(
self.to_glib_none().0,
#name_str.to_glib_none().0,
value.to_glib_none_mut().0);
}
value.get::<#type_>().unwrap()
::glib::ObjectExt::get_property(self, #name_str).unwrap().get::<#type_>().unwrap()
}
}
})
......@@ -170,7 +158,7 @@ where
let type_ = prop.type_;
quote! {
fn #name(&self, v: #type_);
fn #name(&self, v: #type_) -> Result<(), ::glib::error::BoolError>;
}
})
}
......
......@@ -5,6 +5,7 @@ use crate::gen::boilerplateext::BoilerplateExt;
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use std::marker::PhantomData;
use super::SlotExt;
/// This class can generate the public part of the boilerplate code for objects
pub struct Public<'lt, 'ast: 'lt, Boilerplate: boilerplate::Boilerplate<'ast>> {
......@@ -24,8 +25,8 @@ impl<'lt, 'ast: 'lt, Boilerplate: boilerplate::Boilerplate<'ast>> ToTokens
{
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.extend(self.gen_public_new());
tokens.extend(self.gen_def_trait_ext());
tokens.extend(self.gen_impl_trait_ext());
//tokens.extend(self.gen_def_trait_ext());
//tokens.extend(self.gen_impl_trait_ext());
tokens.extend(self.gen_signal_trampolines());
}
}
......@@ -34,7 +35,9 @@ impl<'lt, 'ast: 'lt, Boilerplate: boilerplate::Boilerplate<'ast>> ToTokens
for PublicImp<'lt, 'ast, Boilerplate>
{
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.extend(self.gen_external_methods());
tokens.extend(self.gen_trait_ext());
}
}
......@@ -130,3 +133,38 @@ impl<'lt, 'ast: 'lt, Boilerplate: boilerplate::Boilerplate<'ast>>
quote!{ #(#imp_extern_methods)* }
}
}
impl<'lt, 'ast: 'lt, Boilerplate: boilerplate::Boilerplate<'ast>> PublicImp<'lt, 'ast, Boilerplate>
{
fn gen_trait_ext(&self) -> TokenStream {
let name = self.boilerplate.names().instance();
let ancestors = self.boilerplate.ancestors().iter().filter(|anc| !anc.is_fundamental()).map(|anc| anc.instance());
let instance_ext = self.boilerplate.names().instance_ext();
let slot_def = self.boilerplate.slots().iter().filter(|slot| slot.public())
.map(|slot| slot.trait_definition());
let slot_impl = self.boilerplate.slots().iter().filter(|slot| slot.public())
.map(|slot| slot.trait_implementation(self.boilerplate.names()));
let set_properties_fn = properties::set_properties_fn(self.boilerplate.properties().iter());
let get_properties_fn = properties::get_properties_fn(self.boilerplate.properties().iter());
let set_properties = properties::set_properties(self.boilerplate.properties().iter());
let get_properties = properties::get_properties(self.boilerplate.properties().iter());
quote! {
pub trait #instance_ext {
#(#slot_def)*
#(#get_properties_fn)*
#(#set_properties_fn)*
}
impl<T: IsA<#name> #(+ IsA<#ancestors>)* + IsA<::glib::Object> + ::glib::value::SetValue> #instance_ext for T
{
#(#slot_impl)*
#(#get_properties)*
#(#set_properties)*
}
}
}
}
......@@ -9,10 +9,26 @@ use crate::glib_utils::*;
use crate::hir::names::Names;
use crate::hir::{FnArg, Signal, Ty};
pub fn signal_emit_methods_declaration<'ast>(
signals: impl Iterator<Item = &'ast Signal<'ast>>,
) -> TokenStream {
let signals = signals
.map(|signal| {
let emit_name = emit_signalname(signal);
let rust_params = &signal.sig.inputs;
let rust_return_ty = &signal.sig.output;
quote! {
fn #emit_name(#(#rust_params),*) -> #rust_return_ty;
}
});
quote!{ #(#signals)* }
}
pub fn signal_emit_methods<'ast>(
signals: impl Iterator<Item = &'ast Signal<'ast>>,
) -> Vec<TokenStream> {
signals
) -> TokenStream {
let signals = signals
.map(|signal| {
let emit_name = emit_signalname(signal);
let signal_id_name = signal_id_name(&signal);
......@@ -62,8 +78,8 @@ pub fn signal_emit_methods<'ast>(
}
}
}
})
.collect()
});
quote!{ #(#signals)* }
}
pub fn signal_id_names<'ast>(signals: impl Iterator<Item = &'ast Signal<'ast>>) -> Vec<Ident> {
......
use crate::hir::{Method,Signal,Slot,VirtualMethod,FnSig};
use crate::hir::names::Names;
use proc_macro2::TokenStream;
use quote::ToTokens;
use super::FnSigExt;
use crate::gen::signals;
pub trait SlotExt
{
fn trait_definition(&self) -> TokenStream;
fn trait_implementation(&self, names: &Names) -> TokenStream;
fn public(&self) -> bool;
}
trait SlotInnerExt
{
fn sig(&self) -> &FnSig;
fn body(&self, names: &Names) -> TokenStream;
}
trait SignalExt
{
fn connect_def(&self) -> TokenStream;
fn connect_impl(&self) -> TokenStream;
}
impl<'ast> SlotExt for Slot<'ast>
{
fn trait_definition(&self) -> TokenStream {
let sig = match self {
Slot::VirtualMethod(ref method) => method.sig(),
Slot::Method(ref method) => method.sig(),
Slot::Signal(ref method) => { return method.connect_def(); },
}.signal_definition();
quote!{
#sig;
}
}
fn trait_implementation(&self, names: &Names) -> TokenStream {
let (sig, body) = match self {
Slot::VirtualMethod(ref method) => (method.sig(), method.body(names)),
Slot::Method(ref method) => (method.sig(), method.body(names)),
Slot::Signal(ref method) => { return method.connect_impl(); },
};
let sig = sig.signal_definition();
quote!{
#sig #body
}
}
fn public(&self) -> bool
{
match self {
Slot::Method(ref method) => method.public,
_ => true,
}
}
}
impl<'ast> SlotInnerExt for Method<'ast>
{
fn sig(&self) -> &FnSig {
&self.sig
}
fn body(&self, _names: &Names) -> TokenStream
{
self.body.clone().into_token_stream()
}
}
impl<'ast> SlotInnerExt for VirtualMethod<'ast>
{
fn sig(&self) -> &FnSig {
&self.sig
}
fn body(&self, names: &Names) -> TokenStream
{
if self.body.is_some() {
let name = &self.sig.name;
let args = self.sig.input_args_to_glib_types();
let instance_ffi = names.instance_ffi();
let ret = quote!{ret};
let ret_from_glib_fn = self.sig.ret_from_glib_fn(&ret);
quote! { {
let ffi: *mut #instance_ffi = <Self as glib::translate::ToGlibPtr<'_, *mut #instance_ffi>>::to_glib_none(self).0;
let vtable = unsafe { (*ffi).get_vtable() };
// We unwrap() because vtable.method_name is always set to a method_trampoline
let ret = unsafe { (vtable.#name.as_ref().unwrap())(ffi, #args) };
#ret_from_glib_fn
} }
} else {
let panic_msg = format!("Called abstract method {} with no implementation", &self.sig.name);
quote! { { panic!(#panic_msg) } }
}
}
}
impl<'ast> SignalExt for Signal<'ast>
{
fn connect_def(&self) -> TokenStream
{
let connect_signalname = signals::connect_signalname(self);
let sig = &self.sig;
let input_types = self.sig.input_arg_types();
let output = &sig.output;
quote! {
fn #connect_signalname<F: Fn(&Self, #input_types) -> #output + 'static>(&self, f: F) ->
glib::SignalHandlerId;
}
}
fn connect_impl(&self) -> TokenStream
{
let connect_signalname = signals::connect_signalname(self);
let signalname_trampoline = signals::signal_trampoline_name(self);
let sig = &self.sig;
let signalname_str = format!("{}", sig.name);
let input_types = self.sig.input_arg_types();
let output = &sig.output;
quote! {
fn #connect_signalname<F: Fn(&Self, #input_types) -> #output + 'static>(&self, f: F) ->
glib::SignalHandlerId
{
unsafe {
let f: Box<Box<Fn(&Self, #input_types) -> #output + 'static>> =
Box::new(Box::new(f));
glib::signal::connect(self.to_glib_none().0,
#signalname_str,
mem::transmute(super::#signalname_trampoline::<Self> as usize),
Box::into_raw(f) as *mut _)
}
}
}
}
}
......@@ -118,6 +118,11 @@ impl Names {
self.instance.with_suffix("Ext")
}
/// Returns the name of the private trait with method names
pub fn instance_ext_priv(&self) -> Ident {
self.instance.with_suffix("ExtPriv")
}
/// Returns the name of a C-callable function name for a method
///
/// If the `Names` was created with an instance name of "FooBar",
......
#![cfg(any(not(feature = "single-test"), feature = "single-test-argument-types"))]
#![deny(warnings)]
extern crate gobject_gen;
......
#![cfg(any(not(feature = "single-test"), feature = "single-test-basic"))]
#![deny(warnings)]
extern crate gobject_gen;
......
#![cfg(any(not(feature = "single-test"), feature = "single-test-c_derive"))]
//#![feature(trace_macros)]
//#![deny(warnings)]
......
#![cfg(any(not(feature = "single-test"), feature = "single-test-counter_c_impl"))]
extern crate glib_sys;
extern crate gobject_gen;
extern crate gobject_gen_test;
......
#![cfg(any(not(feature = "single-test"), feature = "single-test-drop"))]
#![deny(warnings)]
extern crate gobject_gen;
......
#![cfg(any(not(feature = "single-test"), feature = "single-test-floating-refs"))]
extern crate glib_sys;
extern crate gobject_gen;
......
#![cfg(any(not(feature = "single-test"), feature = "single-test-gir"))]
#![deny(warnings)]
extern crate gobject_gen;
......
#![cfg(any(not(feature = "single-test"), feature = "single-test-interfaces"))]
//#![feature(extern_prelude)]
extern crate gobject_gen;
extern crate gobject_sys;
......
#![cfg(any(not(feature = "single-test"), feature = "single-test-memory-layout"))]
#![deny(warnings)]
extern crate gobject_gen;
......
#![cfg(any(not(feature = "single-test"), feature = "single-test-no-instance-private"))]
#![deny(warnings)]
extern crate gobject_gen;
......
#![cfg(any(not(feature = "single-test"), feature = "single-test-override"))]
//#![deny(warnings)]
extern crate gobject_gen;
......@@ -45,5 +46,6 @@ fn test() {
assert!(one.one() == 1);
assert!(one.get(0, 0) == 1);
assert!(two.one() == 1);
println!("Test");
assert!(two.get(0, 0) == 2);
}
#![cfg(any(not(feature = "single-test"), feature = "single-test-properties"))]
extern crate gobject_gen;