[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void RejectedEventCallback(string endPoint, string port_name, IntPtr data);
+ //typedef void (*rpc_port_proxy_received_event_cb) (const char* ep, const char* port_name, void* data);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate void ReceivedEventCallback(string endPoint, string port_name, IntPtr data);
+
//int rpc_port_proxy_create(rpc_port_proxy_h *h);
[DllImport(Libraries.RpcPort, EntryPoint = "rpc_port_proxy_create")]
internal static extern int Create(out IntPtr handle);
//int rpc_port_proxy_add_rejected_event_cb(rpc_port_proxy_h h, rpc_port_proxy_rejected_event_cb cb, void* data);
[DllImport(Libraries.RpcPort, EntryPoint = "rpc_port_proxy_add_rejected_event_cb")]
internal static extern int AddRejectedEventCb(IntPtr handle, RejectedEventCallback cb, IntPtr data);
+
+ //int rpc_port_proxy_add_received_event_cb(rpc_port_proxy_h h, rpc_port_proxy_received_event_cb cb, void* data);
+ [DllImport(Libraries.RpcPort, EntryPoint = "rpc_port_proxy_add_received_event_cb")]
+ internal static extern int AddReceivedEventCb(IntPtr handle, ReceivedEventCallback cb, IntPtr data);
}
{"char", "byte"}, {"int", "int"}, {"short", "short"},
{"long", "long"}, {"string", "string"}, {"bool", "bool"},
{"list", "List"}, {"float","float"}, {"double", "double"},
- {"bundle", "Bundle"}
+ {"bundle", "Bundle"}, {"void", "void"}
};
parcel_type_map_ = {
ret = n + " ";
ret += id + " = new " + n +"();\n";
+ if (IsDelegateType(type.ToString()))
+ ret += "CallbackBase.";
ret += "Deserialize(" + parcel + ", " + id +");\n";
return ret;
}
if (type.IsUserDefinedType() ||
type.GetMetaType() != nullptr) {
+ if (IsDelegateType(type.ToString()))
+ return "CallbackBase.Serialize(" + parcel + ", " + id + ");\n";
return "Serialize(" + parcel + ", " + id + ");\n";
}
void CsGeneratorBase::GenMethodId(std::ofstream& stream, const Interface& iface) {
stream << Tab(3) << "private enum MethodId : int" << NLine(1);
GenBrace(stream, TAB_SIZE * 3, [&]() {
+ int cnt = 2;
+ stream << Tab(4) << "Result = 0," << NLine(1);
+ stream << Tab(4) << "Callback = 1," << NLine(1);
+ for (auto& i : iface.GetDeclarations().GetDecls()) {
+ if (i->GetMethodType() == Declaration::MethodType::DELEGATE)
+ continue;
+ stream << Tab(4)
+ << i->GetID() << " = " << cnt++ << "," << NLine(1);
+ }
+ });
+ stream << NLine(1);
+}
+
+void CsGeneratorBase::GenDelegateId(std::ofstream& stream, const Interface& iface) {
+ stream << Tab(3) << "private enum DelegateId : int" << NLine(1);
+ GenBrace(stream, TAB_SIZE * 3, [&]() {
int cnt = 1;
for (auto& i : iface.GetDeclarations().GetDecls()) {
+ if (i->GetMethodType() != Declaration::MethodType::DELEGATE)
+ continue;
stream << Tab(4)
<< i->GetID() << " = " << cnt++ << "," << NLine(1);
}
}
}
+void CsGeneratorBase::GenCallbacks(std::ofstream& stream,
+ const Interface& iface) {
+ const char block[] =
+ "public abstract class CallbackBase\n" \
+ "{\n" \
+ " internal int Id;\n" \
+ " internal int SeqId;\n" \
+ " private static int _seqNum = 0;\n" \
+ "\n" \
+ " public CallbackBase(int delegateId)\n" \
+ " {\n" \
+ " Id = delegateId;\n" \
+ " SeqId = _seqNum++;\n" \
+ " }\n" \
+ "\n" \
+ " internal abstract void OnReceivedEvent(IntPtr port);\n" \
+ "\n" \
+ " internal static void Serialize(IntPtr h, CallbackBase param)\n" \
+ " {\n" \
+ " Interop.LibRPCPort.Parcel.WriteInt32(h, (int)param.Id);\n" \
+ " Interop.LibRPCPort.Parcel.WriteInt32(h, (int)param.SeqId);\n" \
+ " }\n" \
+ "\n" \
+ " internal static void Deserialize(IntPtr h, CallbackBase param)\n" \
+ " {\n" \
+ " Interop.LibRPCPort.Parcel.ReadInt32(h, out var id);\n" \
+ " param.Id = id;\n" \
+ " Interop.LibRPCPort.Parcel.ReadInt32(h, out var seqId);\n" \
+ " param.SeqId = seqId;\n" \
+ " }\n" \
+ "}\n";
+ stream << AddIndent(TAB_SIZE * 3, block) << NLine(1);
+
+ for (auto& i : iface.GetDeclarations().GetDecls()) {
+ if (i->GetMethodType() != Declaration::MethodType::DELEGATE)
+ continue;
+ GenCallback(stream, *i);
+ }
+}
+
+void CsGeneratorBase::GenCallback(std::ofstream& stream,
+ const Declaration& decl) {
+ stream << Tab(3) << "public sealed class " << decl.GetID()
+ << " : CallbackBase" << NLine(1);
+ GenBrace(stream, TAB_SIZE * 3, [&]() {
+ const char ctor[] =
+ "public $$() : base((int)DelegateId.$$)\n" \
+ "{\n" \
+ "}\n" \
+ "\n" \
+ "internal $$(IntPtr port) : base((int)DelegateId.$$)\n" \
+ "{\n" \
+ " _port = port;\n" \
+ "}\n";
+
+ GenTemplate(AddIndent(TAB_SIZE * 4, ctor), stream,
+ [&]()->std::string {
+ return decl.GetID();
+ },
+ [&]()->std::string {
+ return decl.GetID();
+ },
+ [&]()->std::string {
+ return decl.GetID();
+ },
+ [&]()->std::string {
+ return decl.GetID();
+ }
+ );
+ stream << NLine(1);
+
+ stream << Tab(4) << "private IntPtr _port = IntPtr.Zero;" << NLine(1);
+ stream << Tab(4) << "public delegate void Callback(";
+ GenParameters(stream, decl.GetParameters());
+ stream << ");" << NLine(1);
+ stream << Tab(4) << "public event Callback Received;" << NLine(2);
+
+ GenReceivedEvent(stream, decl);
+ GenInvokeMethod(stream, decl);
+ });
+ stream << NLine(1);
+}
+
+void CsGeneratorBase::GenReceivedEvent(std::ofstream& stream,
+ const Declaration& decl) {
+ stream << Tab(4) << "internal override void OnReceivedEvent(IntPtr parcel)"
+ << NLine(1);
+ GenBrace(stream, TAB_SIZE * 4, [&]() {
+ int cnt = 1;
+ for (auto& i : decl.GetParameters().GetParams()) {
+ std::string v = "param" + std::to_string(cnt);
+ std::string c = ConvertTypeToDeserializer(
+ i->GetParameterType().GetBaseType(), v, "parcel");
+ stream << AddIndent(TAB_SIZE * 5, c);
+ cnt++;
+ }
+
+ cnt = 1;
+ stream << Tab(5) << "Received?.Invoke(";
+ for (int i = 0; i < decl.GetParameters().GetParams().size(); i++) {
+ if (cnt != 1) {
+ stream << ", ";
+ }
+ std::string v = "param" + std::to_string(cnt);
+ stream << v;
+ cnt++;
+ }
+ stream << ");" << NLine(1);
+ });
+ stream << NLine(1);
+}
+
+void CsGeneratorBase::GenInvokeMethod(std::ofstream& stream,
+ const Declaration& decl) {
+ const char* pre =
+ "if (_port == IntPtr.Zero)\n" \
+ " throw new InvalidOperationException(\"Not connected!\");\n" \
+ "\n" \
+ "Interop.LibRPCPort.Parcel.Create(out IntPtr p);\n" \
+ "Interop.LibRPCPort.Parcel.WriteInt32(p, (int)MethodId.Callback);\n" \
+ "Serialize(p, this);\n";
+
+ const char* mid =
+ "// Send\n" \
+ "Interop.LibRPCPort.Parcel.Send(p, _port);\n" \
+ "Interop.LibRPCPort.Parcel.Destroy(p);\n";
+
+ stream << Tab(4) << "public void Invoke(";
+ GenParameters(stream, decl.GetParameters());
+ stream << ")" << NLine(1);
+ GenBrace(stream, TAB_SIZE * 4, [&]() {
+ stream << AddIndent(TAB_SIZE * 5, pre);
+ std::string m;
+ for (auto& i : decl.GetParameters().GetParams()) {
+ auto& pt = i->GetParameterType();
+ m += ConvertTypeToSerializer(pt.GetBaseType(), i->GetID(), "p");
+ }
+
+ stream << AddIndent(TAB_SIZE * 5, m) << NLine(1);
+ stream << AddIndent(TAB_SIZE * 5, mid);
+ });
+}
+
+bool CsGeneratorBase::IsDelegateType(const std::string type_name) {
+ for (auto& i : GetDocument().GetBlocks()) {
+ if (i->GetType() != Block::TYPE_INTERFACE)
+ continue;
+ Interface& iface = static_cast<Interface&>(*i);
+
+ for (auto& j : iface.GetDeclarations().GetDecls()) {
+ if (j->GetMethodType() == Declaration::MethodType::DELEGATE) {
+ if (j->GetID() == type_name)
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
} // namespace tidl
void GenListSerializer(std::ofstream& stream);
void GenListSerializer(std::ofstream& stream, const BaseType& type);
void GenMethodId(std::ofstream& stream, const Interface& iface);
+ void GenDelegateId(std::ofstream& stream, const Interface& iface);
void GenDeclaration(std::ofstream& stream,
const Declaration& decl, bool semicol = true);
void GenParameters(std::ofstream& stream, const Parameters& ps);
+ void GenCallbacks(std::ofstream& stream, const Interface& iface);
std::string ConvertTypeToString(const BaseType& type);
std::string ConvertTypeToDeserializer(const BaseType& type,
std::string ConvertTypeToSerializer(const BaseType& type,
std::string id, std::string parcel);
std::string ConvertTypeToParcelType(const std::string& key);
+ bool IsDelegateType(const std::string type_name);
std::string Tab(int cnt);
std::string NLine(int cnt);
private:
void GenWriteBundle(std::ofstream& stream, const std::string& id);
void AddSerializerList(const BaseType& type);
+ void GenCallback(std::ofstream& stream, const Declaration& decl);
+ void GenReceivedEvent(std::ofstream& stream, const Declaration& decl);
+ void GenInvokeMethod(std::ofstream& stream, const Declaration& decl);
private:
std::map<std::string, std::string> type_map_;
"private IntPtr _proxy;\n" \
"private IntPtr _port;\n" \
"private bool _online = false;\n" \
- "private string _appId;\n";
+ "private string _appId;\n" \
+ "private List<CallbackBase> _delegateList = new List<CallbackBase>();\n" \
+ "private Interop.LibRPCPort.Proxy.ConnectedEventCallback _connectedEventCallback;\n" \
+ "private Interop.LibRPCPort.Proxy.DisconnectedEventCallback _disconnectedEventCallback;\n" \
+ "private Interop.LibRPCPort.Proxy.RejectedEventCallback _rejectedEventCallback;\n" \
+ "private Interop.LibRPCPort.Proxy.ReceivedEventCallback _receivedEventCallback;\n";
const char* eventMethods =
"private void OnConnectedEvent(string endPoint, string port_name, IntPtr port, IntPtr data)\n" \
"private void OnRejectedEvent(string endPoint, string port_name, IntPtr data)\n" \
"{\n" \
" Rejected?.Invoke(this, null);\n" \
+ "}\n" \
+ "\n" \
+ "private void OnReceivedEvent(string endPoint, string port_name, IntPtr data)\n" \
+ "{\n" \
+ " if (Interop.LibRPCPort.Parcel.CreateFromPort(out IntPtr parcel_received, _port) != 0)\n" \
+ " return;\n" \
+ "\n" \
+ " Interop.LibRPCPort.Parcel.ReadInt32(parcel_received, out int cmd);\n" \
+ " if (cmd != (int)MethodId.Callback)\n" \
+ " {\n" \
+ " Interop.LibRPCPort.Parcel.Destroy(parcel_received);\n" \
+ " //TODO\n" \
+ " return;\n" \
+ " }\n" \
+ "\n" \
+ " Interop.LibRPCPort.Parcel.ReadInt32(parcel_received, out int id);\n" \
+ " Interop.LibRPCPort.Parcel.ReadInt32(parcel_received, out int seqId);\n" \
+ "\n" \
+ " foreach (var i in _delegateList)\n" \
+ " {\n" \
+ " if ((int)i.Id == id && i.SeqId == seqId)\n" \
+ " {\n" \
+ " i.OnReceivedEvent(parcel_received);\n" \
+ " break;\n" \
+ " }\n" \
+ " }\n" \
+ "\n" \
+ " Interop.LibRPCPort.Parcel.Destroy(parcel_received);\n" \
"}\n";
stream << Tab(2) << "public class " << iface.GetID()
<< " : IDisposable" << NLine(1);
GenBrace(stream, TAB_SIZE * 2, [&]() {
stream << AddIndent(TAB_SIZE * 3, prop) << NLine(1);
+ GenCallbacks(stream, iface);
+ GenDelegateId(stream, iface);
GenMethodId(stream, iface);
stream << AddIndent(TAB_SIZE * 3, eventMethods) << NLine(1);
GenSerializer(stream);
"public void Connect()\n" \
"{\n" \
" Interop.LibRPCPort.Proxy.Create(out _proxy);\n" \
- " Interop.LibRPCPort.Proxy.AddConnectedEventCb(_proxy, OnConnectedEvent, IntPtr.Zero);\n" \
- " Interop.LibRPCPort.Proxy.AddDisconnectedEventCb(_proxy, OnDisconnectedEvent, IntPtr.Zero);\n" \
- " Interop.LibRPCPort.Proxy.AddRejectedEventCb(_proxy, OnRejectedEvent, IntPtr.Zero);\n" \
+ " _connectedEventCallback = new Interop.LibRPCPort.Proxy.ConnectedEventCallback(OnConnectedEvent);\n" \
+ " _disconnectedEventCallback = new Interop.LibRPCPort.Proxy.DisconnectedEventCallback(OnDisconnectedEvent);\n" \
+ " _rejectedEventCallback = new Interop.LibRPCPort.Proxy.RejectedEventCallback(OnRejectedEvent);\n" \
+ " _receivedEventCallback = new Interop.LibRPCPort.Proxy.ReceivedEventCallback(OnReceivedEvent);\n" \
+ " Interop.LibRPCPort.Proxy.AddConnectedEventCb(_proxy, _connectedEventCallback, IntPtr.Zero);\n" \
+ " Interop.LibRPCPort.Proxy.AddDisconnectedEventCb(_proxy, _disconnectedEventCallback, IntPtr.Zero);\n" \
+ " Interop.LibRPCPort.Proxy.AddRejectedEventCb(_proxy, _rejectedEventCallback, IntPtr.Zero);\n" \
+ " Interop.LibRPCPort.Proxy.AddReceivedEventCb(_proxy, _receivedEventCallback, IntPtr.Zero);\n" \
" if (Interop.LibRPCPort.Proxy.Connect(_proxy, _appId, \"$$\") != 0)\n" \
" throw new InvalidOperationException(\"Connection failed\");\n" \
"}";
if (pt.GetDirection() == ParameterType::Direction::OUT)
continue;
m += ConvertTypeToSerializer(pt.GetBaseType(), i->GetID(), "p");
+ if (IsDelegateType(pt.GetBaseType().ToString()))
+ m += "_delegateList.Add(" + i->GetID() + ");\n";
}
stream << AddIndent(TAB_SIZE * 4, m) << NLine(1);
stream << Tab(4)
<< "Interop.LibRPCPort.Parcel.CreateFromPort(out IntPtr parcel_received, _port);"
<< NLine(1);
+ stream << Tab(4)
+ << "Interop.LibRPCPort.Parcel.ReadInt32(parcel_received, out int cmd);"
+ << NLine(1);
+ stream << Tab(4)
+ << "if (cmd != (int)MethodId.Result)" << NLine(1);
+ GenBrace(stream, TAB_SIZE * 4, [&]() {
+ //TODO
+ });
+ stream << NLine(1);
for (auto& i : decl.GetParameters().GetParams()) {
if (i->GetParameterType().GetDirection() == ParameterType::Direction::IN) {
void CsStubGen::GenInterface(std::ofstream& stream, const Interface& iface) {
stream << Tab(2) << "public sealed class " << iface.GetID() << NLine(1);
GenBrace(stream, TAB_SIZE * 2, [&]() {
- GenServiceBase(stream, iface);
- stream << Tab(3)
- << "private IntPtr _stub;" << NLine(2);
+ stream << Tab(3) << "private IntPtr _stub;" << NLine(1);
stream << Tab(3)
<< "private List<ServiceBase> _services = new List<ServiceBase>();"
+ << NLine(1);
+ stream << Tab(3) << "private Type _serviceType;" << NLine(1);
+ stream << Tab(3) << "private Interop.LibRPCPort.Stub.ConnectedEventCallback _connectedEventCallback;"
+ << NLine(1);
+ stream << Tab(3) << "private Interop.LibRPCPort.Stub.DisconnectedEventCallback _disconnectedEventCallback;"
+ << NLine(1);
+ stream << Tab(3) << "private Interop.LibRPCPort.Stub.ReceivedEventCallback _receivedEventCallback;"
<< NLine(2);
- stream << Tab(3)
- << "private Type _serviceType;" << NLine(2);
+ GenServiceBase(stream, iface);
+ GenCallbacks(stream, iface);
+ GenDelegateId(stream, iface);
GenMethodId(stream, iface);
GenSerializer(stream);
GenListSerializer(stream);
void CsStubGen::GenDeclarations(std::ofstream& stream,
const Declarations& decls) {
for (auto& i : decls.GetDecls()) {
+ if (i->GetMethodType() == Declaration::MethodType::DELEGATE)
+ continue;
stream << Tab(4) << "public abstract ";
GenDeclaration(stream, *i);
stream << NLine(1);
return;
cnt = 0;
- m = "";
+ m = "Interop.LibRPCPort.Parcel.WriteInt32(result, (int)MethodId.Result);\n";
for (auto& i : decl.GetParameters().GetParams()) {
auto& pt = i->GetParameterType();
cnt++;
"public $$()\n" \
"{\n" \
" Interop.LibRPCPort.Stub.Create(out _stub, \"$$\");\n" \
- " Interop.LibRPCPort.Stub.AddReceivedEventCb(_stub, OnReceivedEvent, IntPtr.Zero);\n" \
- " Interop.LibRPCPort.Stub.AddConnectedEventCb(_stub, OnConnectedEvent, IntPtr.Zero);\n" \
- " Interop.LibRPCPort.Stub.AddDisconnectedEventCb(_stub, OnDisconnectedEvent, IntPtr.Zero);\n";
+ " _connectedEventCallback = new Interop.LibRPCPort.Stub.ConnectedEventCallback(OnConnectedEvent);\n" \
+ " _disconnectedEventCallback = new Interop.LibRPCPort.Stub.DisconnectedEventCallback(OnDisconnectedEvent);\n" \
+ " _receivedEventCallback = new Interop.LibRPCPort.Stub.ReceivedEventCallback(OnReceivedEvent);\n" \
+ " Interop.LibRPCPort.Stub.AddReceivedEventCb(_stub, _receivedEventCallback, IntPtr.Zero);\n" \
+ " Interop.LibRPCPort.Stub.AddConnectedEventCb(_stub, _connectedEventCallback, IntPtr.Zero);\n" \
+ " Interop.LibRPCPort.Stub.AddDisconnectedEventCb(_stub, _disconnectedEventCallback, IntPtr.Zero);\n";
GenTemplate(AddIndent(TAB_SIZE * 3, ctor), stream,
[&]()->std::string {
"out" { return yy::parser::token::T_OUT; }
"ref" { return yy::parser::token::T_REF; }
"async" { return yy::parser::token::T_ASYNC; }
+"delegate" { return yy::parser::token::T_DELEGATE; }
"<" { return yy::parser::token::T_META_OPEN; }
">" { return yy::parser::token::T_META_CLOSE; }
"list" {
return yy::parser::token::T_SB_CLOSE;
}
"=" { return yy::parser::token::T_EQUAL; }
-"delegate" { return yy::parser::token::T_DELEGATE; }
+
%%
delete $1;
delete $2;
}
- | T_VOID T_ID T_LEFT parameter_list T_RIGHT T_DELEGATE T_SEMICOLON {
+ | T_VOID T_ID T_LEFT parameter_list T_RIGHT T_DELEGATE T_SEMICOLON {
$$ = new tidl::Declaration($2->ToString(),
new tidl::BaseType("void", $1->GetComments()), $4,
$1->GetComments(), @1.begin.line,