/* * Copyright 2019 by its authors. See AUTHORS. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef EOLIAN_MONO_FUNCTION_POINTER_HPP #define EOLIAN_MONO_FUNCTION_POINTER_HPP #include #include #include #include "function_helpers.hh" #include "documentation.hh" #include "generation_contexts.hh" #include "blacklist.hh" namespace eolian_mono { // Blacklist structs that require some kind of manual binding. template static bool is_function_ptr_blacklisted(attributes::function_def const& func, Context const& context) { std::string name = name_helpers::function_ptr_full_eolian_name(func); return blacklist::is_function_blacklisted(func, context); } struct function_pointer { template bool generate(OutputIterator sink, attributes::function_def const& f, Context const& context) const { EINA_CXX_DOM_LOG_DBG(eolian_mono::domain) << "function_pointer_generator: " << f.name << std::endl; // FIXME export Typedecl in eolian_cxx API auto funcptr_ctx = context_add_tag(class_context{class_context::function_ptr}, context); if (is_function_ptr_blacklisted(f, context)) return true; std::string return_type; if(!as_generator(eolian_mono::type(true)).generate(std::back_inserter(return_type), f.return_type, context)) return false; if (!name_helpers::open_namespaces(sink, f.namespaces, funcptr_ctx)) return false; std::string f_name = name_helpers::typedecl_managed_name(f); // C# visible delegate if (!as_generator(documentation << "[Efl.Eo.BindingEntity]\n" << "public delegate " << type << " " << string << "(" << (parameter % ", ") << ");\n") .generate(sink, std::make_tuple(f, f.return_type, f_name, f.parameters), funcptr_ctx)) return false; // "Internal" delegate, 1-to-1 with the Unamaged function type if (!as_generator(marshall_annotation(true) << "public delegate " << marshall_type(true) << " " << string // public? << "Internal(IntPtr data" << *grammar::attribute_reorder<-1, -1>((", " << marshall_annotation << " " << marshall_parameter)) << ");\n") .generate(sink, std::make_tuple(f.return_type, f.return_type, f_name, f.parameters), funcptr_ctx)) return false; // Wrapper type, with callback matching the Unamanaged one if (!as_generator("internal class " << f_name << "Wrapper : IDisposable\n" << "{\n\n" << scope_tab << "private " << f_name << "Internal _cb;\n" << scope_tab << "private IntPtr _cb_data;\n" << scope_tab << "private EinaFreeCb _cb_free_cb;\n\n" << scope_tab << "internal " << f_name << "Wrapper (" << f_name << "Internal _cb, IntPtr _cb_data, EinaFreeCb _cb_free_cb)\n" << scope_tab << "{\n" << scope_tab << scope_tab << "this._cb = _cb;\n" << scope_tab << scope_tab << "this._cb_data = _cb_data;\n" << scope_tab << scope_tab << "this._cb_free_cb = _cb_free_cb;\n" << scope_tab << "}\n\n" << scope_tab << "~" << f_name << "Wrapper()\n" << scope_tab << "{\n" << scope_tab << scope_tab << "Dispose(false);\n" << scope_tab << "}\n\n" << scope_tab << "protected virtual void Dispose(bool disposing)\n" << scope_tab << "{\n" << scope_tab << scope_tab << "if (this._cb_free_cb != null)\n" << scope_tab << scope_tab << "{\n" << scope_tab << scope_tab << scope_tab << "if (disposing)\n" << scope_tab << scope_tab << scope_tab << "{\n" << scope_tab << scope_tab << scope_tab << scope_tab << "this._cb_free_cb(this._cb_data);\n" << scope_tab << scope_tab << scope_tab << "}\n" << scope_tab << scope_tab << scope_tab << "else\n" << scope_tab << scope_tab << scope_tab << "{\n" << scope_tab << scope_tab << scope_tab << scope_tab << "Efl.Eo.Globals.ThreadSafeFreeCbExec(this._cb_free_cb, this._cb_data);\n" << scope_tab << scope_tab << scope_tab << "}\n" << scope_tab << scope_tab << scope_tab << "this._cb_free_cb = null;\n" << scope_tab << scope_tab << scope_tab << "this._cb_data = IntPtr.Zero;\n" << scope_tab << scope_tab << scope_tab << "this._cb = null;\n" << scope_tab << scope_tab << "}\n" << scope_tab << "}\n\n" << scope_tab << "public void Dispose()\n" << scope_tab << "{\n" << scope_tab << scope_tab << "Dispose(true);\n" << scope_tab << scope_tab << "GC.SuppressFinalize(this);\n" << scope_tab << "}\n\n" << scope_tab << "internal " << type << " ManagedCb(" << (parameter % ",") << ")\n" << scope_tab << "{\n" << function_definition_preamble << "_cb(_cb_data, " << (argument_invocation % ", ") << ");\n" << function_definition_epilogue << scope_tab << "}\n\n" << scope_tab << marshall_annotation(true) << scope_tab << "internal static " << marshall_type(true) << " Cb(IntPtr cb_data" << *grammar::attribute_reorder<-1, -1>((", " << marshall_annotation << " " << marshall_parameter)) << ")\n" << scope_tab << "{\n" << scope_tab << scope_tab << "GCHandle handle = GCHandle.FromIntPtr(cb_data);\n" << scope_tab << scope_tab << string << " cb = (" << string << ")handle.Target;\n" << native_function_definition_preamble << scope_tab << scope_tab << "try {\n" << scope_tab << scope_tab << scope_tab << (return_type != "void" ? "_ret_var = " : "") << "cb(" << (native_argument_invocation % ", ") << ");\n" << scope_tab << scope_tab << "} catch (Exception e) {\n" << scope_tab << scope_tab << scope_tab << "Eina.Log.Warning($\"Callback error: {e.ToString()}\");\n" << scope_tab << scope_tab << scope_tab << "Eina.Error.Set(Eina.Error.UNHANDLED_EXCEPTION);\n" << scope_tab << scope_tab << "}\n" << native_function_definition_epilogue(nullptr) << scope_tab << "}\n" << "}\n" ).generate(sink, std::make_tuple(f.return_type, f.parameters, f, f.parameters, f, f.return_type, f.return_type, f.parameters, f_name, f_name, f, f.parameters, f), funcptr_ctx)) return false; if (!name_helpers::close_namespaces(sink, f.namespaces, funcptr_ctx)) return false; return true; } }; struct function_pointer const function_pointer = {}; } #endif