Compare commits
6 Commits
v8.0.0.rc2
...
master
Author | SHA1 | Date |
---|---|---|
|
5a1b01ea20 | |
|
1287703435 | |
|
0c234c9103 | |
|
f86576293e | |
|
24bd6fd6f9 | |
|
ab4a7f7fe7 |
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"name": "bit/metagen_cs",
|
||||
"description": "C# codgen support from meta descriptions",
|
||||
"description": "C# codegen support from meta descriptions",
|
||||
"homepage": "https://git.bit5.ru/bit/metagen_cs",
|
||||
"require": {
|
||||
"php": ">=7.4",
|
||||
"twig/twig" : "v3.4.3",
|
||||
"bit/metagen" : "^v3.0.0"
|
||||
"twig/twig" : "^v3.4.3",
|
||||
"bit/metagen" : "^v4.0.0"
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
|
|
|
@ -25,9 +25,6 @@ function supported_tokens() : array
|
|||
'cs_obsolete',
|
||||
//TODO:
|
||||
//'i18n'
|
||||
|
||||
'cs_service_call_builder',
|
||||
'cs_service_client',
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -44,6 +41,8 @@ function codegen(?string $cache_dir, \mtgMetaInfo $meta, array $options = []) :
|
|||
$options['meta'] = $meta;
|
||||
if(!isset($options['namespace']))
|
||||
$options['namespace'] = 'BitGames.Autogen';
|
||||
if(!isset($options['uses']))
|
||||
$options['uses'] = [];
|
||||
|
||||
$sliced_units = slice_units($meta->getUnits(), 50);
|
||||
|
||||
|
@ -59,40 +58,11 @@ function codegen(?string $cache_dir, \mtgMetaInfo $meta, array $options = []) :
|
|||
|
||||
$output['factory.cs'] = $twig->render('codegen_factory.twig', $options);
|
||||
|
||||
$output['services.cs'] = codegen_services($cache_dir, filter_services_meta($meta), $options);
|
||||
$output['services.cs'] = $twig->render('codegen_services.twig', $options);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
function filter_services_meta(\mtgMetaInfo $meta) : \mtgMetaInfo
|
||||
{
|
||||
$res = new \mtgMetaInfo();
|
||||
|
||||
foreach($meta->getUnits() as $u)
|
||||
{
|
||||
if($u->object instanceof \mtgMetaService)
|
||||
$res->addUnit($u);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
function codegen_services(?string $cache_dir, \mtgMetaInfo $meta, array $options = []) : string
|
||||
{
|
||||
$twig = get_twig();
|
||||
|
||||
if(!empty($cache_dir))
|
||||
$twig->setCache($cache_dir);
|
||||
|
||||
$options['meta'] = $meta;
|
||||
if(!isset($options['namespace']))
|
||||
$options['namespace'] = 'BitGames.Autogen';
|
||||
if(!isset($options['uses']))
|
||||
$options['uses'] = [];
|
||||
|
||||
return $twig->render('codegen_services.twig', $options);
|
||||
}
|
||||
|
||||
function get_twig(array $inc_path = []) : \Twig\Environment
|
||||
{
|
||||
array_unshift($inc_path, __DIR__ . "/../tpl/");
|
||||
|
|
|
@ -33,10 +33,8 @@ static public class AutogenBundle
|
|||
{
|
||||
switch(class_id)
|
||||
{
|
||||
{%- for u in meta.getunits ~%}
|
||||
{%- if u.object is instanceof('\\mtgMetaStruct')~%}
|
||||
case {{u.object.classid}}: { return typeof({{u.object.name}}); }
|
||||
{%- endif ~%}
|
||||
{%- for t in meta.factorytypes ~%}
|
||||
case {{t.classid}}: { return typeof({{t.fullname}}); }
|
||||
{%- endfor ~%}
|
||||
default:
|
||||
{
|
||||
|
|
|
@ -4,15 +4,93 @@ using System.Threading.Tasks;
|
|||
using System.Collections.Generic;
|
||||
using metagen;
|
||||
using BitGames.Bits;
|
||||
#if USE_UNITASK
|
||||
using Cysharp.Threading.Tasks;
|
||||
#endif
|
||||
{%- for use in uses ~%}
|
||||
using {{use}};
|
||||
{%- endfor ~%}
|
||||
|
||||
{% import "service_macro.twig" as macro %}
|
||||
{% import "service_macro.twig" as svc_macro %}
|
||||
{% import "macro.twig" as cs_macro %}
|
||||
|
||||
namespace {{namespace}}
|
||||
{
|
||||
|
||||
public interface IRpcCaller
|
||||
{
|
||||
#if USE_UNITASK
|
||||
UniTask
|
||||
#else
|
||||
Task
|
||||
#endif
|
||||
CallRpc(metagen.IRpc rpc);
|
||||
}
|
||||
|
||||
public interface IApiBase
|
||||
{
|
||||
public IRpcCaller Caller { get; }
|
||||
}
|
||||
|
||||
public interface IRpcCallBuilder<TRpc> where TRpc : metagen.IRpc
|
||||
{
|
||||
public
|
||||
|
||||
#if USE_UNITASK
|
||||
UniTask<TRpc>
|
||||
#else
|
||||
Task<TRpc>
|
||||
#endif
|
||||
|
||||
Call();
|
||||
}
|
||||
|
||||
public struct RpcCallBuilder<TRpc> : IRpcCallBuilder<TRpc> where TRpc : IRpc
|
||||
{
|
||||
private IRpcCaller clt;
|
||||
private TRpc rpc;
|
||||
|
||||
public RpcCallBuilder(IRpcCaller clt, TRpc rpc)
|
||||
{
|
||||
this.clt = clt;
|
||||
this.rpc = rpc;
|
||||
}
|
||||
|
||||
public async
|
||||
#if USE_UNITASK
|
||||
UniTask<TRpc>
|
||||
#else
|
||||
Task<TRpc>
|
||||
#endif
|
||||
Call()
|
||||
{
|
||||
await clt.CallRpc(rpc);
|
||||
return rpc;
|
||||
}
|
||||
}
|
||||
|
||||
public struct MockRpcCallBuilder<TRpc> : IRpcCallBuilder<TRpc> where TRpc : IRpc
|
||||
{
|
||||
public TRpc Rpc { get; }
|
||||
|
||||
public MockRpcCallBuilder(TRpc rpc)
|
||||
{
|
||||
this.Rpc = rpc;
|
||||
}
|
||||
|
||||
#if USE_UNITASK
|
||||
public UniTask<TRpc> Call()
|
||||
{
|
||||
return UniTask.FromResult(Rpc);
|
||||
}
|
||||
#else
|
||||
public Task<TRpc> Call()
|
||||
{
|
||||
return Task.FromResult(Rpc);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
{%- for unit in meta.units %}
|
||||
|
||||
{% if unit.object is instanceof('\\mtgMetaService') %}
|
||||
|
@ -20,9 +98,44 @@ namespace {{namespace}}
|
|||
namespace {{unit.object.name}}
|
||||
{
|
||||
|
||||
{{macro.gen_client(unit.object)}}
|
||||
//constrained local interface,
|
||||
//(this way we don't have to change anything in generated
|
||||
//structs below)
|
||||
public interface IRpc : metagen.IRpc
|
||||
{}
|
||||
|
||||
{{macro.gen_server(unit.object)}}
|
||||
{%- for rpc in unit.object.rpcs %}
|
||||
{{cs_macro.decl_rpc(rpc, false)}}
|
||||
{%- endfor ~%}
|
||||
|
||||
{%- for utype in unit.object.usertypes %}
|
||||
{%- if utype is instanceof('\\mtgMetaStruct') -%}
|
||||
{{cs_macro.decl_struct(utype)}}
|
||||
{% elseif utype is instanceof('\\mtgMetaEnum') %}
|
||||
{{cs_macro.decl_enum(utype)}}
|
||||
{% endif %}
|
||||
{%- endfor ~%}
|
||||
|
||||
public static class Factory
|
||||
{
|
||||
public static IRpc CreateRPC(int code)
|
||||
{
|
||||
switch(code)
|
||||
{
|
||||
{%- for rpc in unit.object.rpcs ~%}
|
||||
|
||||
case {{rpc.code}}: return new {{rpc.name}}();
|
||||
|
||||
{%- endfor ~%}
|
||||
}
|
||||
|
||||
throw new Exception("Unsupported RPC code: " + code);
|
||||
}
|
||||
}
|
||||
|
||||
{{svc_macro.gen_client(unit.object)}}
|
||||
|
||||
{{svc_macro.gen_server(unit.object)}}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,87 +1,33 @@
|
|||
|
||||
{%- macro gen_client(obj) ~%}
|
||||
|
||||
{% import "macro.twig" as cs_macro %}
|
||||
|
||||
//constrained local interface
|
||||
public interface IRpc : metagen.IRpc
|
||||
{}
|
||||
|
||||
{%- for rpc in obj.rpcs %}
|
||||
{{cs_macro.decl_rpc(rpc, false)}}
|
||||
{%- endfor ~%}
|
||||
|
||||
{%- for utype in obj.usertypes %}
|
||||
{%- if utype is instanceof('\\mtgMetaStruct') -%}
|
||||
{{cs_macro.decl_struct(utype)}}
|
||||
{% elseif utype is instanceof('\\mtgMetaEnum') %}
|
||||
{{cs_macro.decl_enum(utype)}}
|
||||
{% endif %}
|
||||
{%- endfor ~%}
|
||||
|
||||
public static class Factory
|
||||
public interface IApi : IApiBase
|
||||
{
|
||||
public static IRpc CreateRPC(int code)
|
||||
{
|
||||
switch(code)
|
||||
{
|
||||
{%- for rpc in obj.rpcs ~%}
|
||||
|
||||
case {{rpc.code}}: return new {{rpc.name}}();
|
||||
|
||||
{%- endfor ~%}
|
||||
}
|
||||
|
||||
throw new Exception("Unsupported RPC code: " + code);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IRpcCaller
|
||||
{
|
||||
Task CallRpc(metagen.IRpc rpc);
|
||||
}
|
||||
|
||||
public struct RpcCallBuilder<TRpc> where TRpc : IRpc
|
||||
{
|
||||
private IRpcCaller clt;
|
||||
private TRpc rpc;
|
||||
|
||||
public RpcCallBuilder(IRpcCaller clt, TRpc rpc)
|
||||
{
|
||||
this.clt = clt;
|
||||
this.rpc = rpc;
|
||||
}
|
||||
|
||||
public async Task<TRpc> Call()
|
||||
{
|
||||
await clt.CallRpc(rpc);
|
||||
return rpc;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IApi
|
||||
{
|
||||
public {{token_or(obj, 'cs_service_client', 'IRpcCaller')}} Client { get; }
|
||||
|
||||
{%- for rpc in obj.rpcs ~%}
|
||||
public {{token_or(obj, 'cs_service_call_builder', 'RpcCallBuilder')}}<{{rpc.name}}> Begin({{rpc.name}} rpc);
|
||||
public IRpcCallBuilder<{{rpc.name}}> Begin({{rpc.name}} rpc);
|
||||
{%- endfor ~%}
|
||||
}
|
||||
|
||||
public class Api : IApi
|
||||
{
|
||||
public {{token_or(obj, 'cs_service_client', 'IRpcCaller')}} Client { get; private set; }
|
||||
public IRpcCaller Caller { get; }
|
||||
|
||||
public Api({{token_or(obj, 'cs_service_client', 'IRpcCaller')}} client)
|
||||
public Api(IRpcCaller caller)
|
||||
{
|
||||
this.Client = client;
|
||||
this.Caller = caller;
|
||||
}
|
||||
|
||||
public virtual IRpcCallBuilder<T> CreateCallBuilder<T>(metagen.IRpc rpc) where T : IRpc
|
||||
{
|
||||
return new RpcCallBuilder<T>(Caller, (T)rpc);
|
||||
}
|
||||
|
||||
{%- for rpc in obj.rpcs ~%}
|
||||
|
||||
public {{token_or(obj, 'cs_service_call_builder', 'RpcCallBuilder')}}<{{rpc.name}}> Begin({{rpc.name}} rpc)
|
||||
public IRpcCallBuilder<{{rpc.name}}> Begin({{rpc.name}} rpc)
|
||||
{
|
||||
return new {{token_or(obj, 'cs_service_call_builder', 'RpcCallBuilder')}}<{{rpc.name}}>(Client, rpc);
|
||||
var builder = CreateCallBuilder<{{rpc.name}}>(rpc);
|
||||
return builder;
|
||||
}
|
||||
|
||||
{%- endfor ~%}
|
||||
|
@ -91,7 +37,7 @@ public class Api : IApi
|
|||
public class ApiDecoratorBase : IApi
|
||||
{
|
||||
private IApi orig;
|
||||
public {{token_or(obj, 'cs_service_client', 'IRpcCaller')}} Client => orig.Client;
|
||||
public IRpcCaller Caller => orig.Caller;
|
||||
|
||||
public ApiDecoratorBase(IApi orig)
|
||||
{
|
||||
|
@ -103,7 +49,7 @@ public class ApiDecoratorBase : IApi
|
|||
|
||||
{%- for rpc in obj.rpcs ~%}
|
||||
|
||||
public virtual {{token_or(obj, 'cs_service_call_builder', 'RpcCallBuilder')}}<{{rpc.name}}> Begin({{rpc.name}} rpc)
|
||||
public virtual IRpcCallBuilder<{{rpc.name}}> Begin({{rpc.name}} rpc)
|
||||
{
|
||||
OnBefore(rpc);
|
||||
return orig.Begin(rpc);
|
||||
|
@ -115,16 +61,21 @@ public class ApiDecoratorBase : IApi
|
|||
|
||||
public class MockApiBase : IApi
|
||||
{
|
||||
public {{token_or(obj, 'cs_service_client', 'IRpcCaller')}} Client { get; private set; }
|
||||
public IRpcCaller Caller { get; private set; }
|
||||
|
||||
public MockApiBase({{token_or(obj, 'cs_service_client', 'IRpcCaller')}} client)
|
||||
static protected IRpcCallBuilder<T> Result<T>(T rpc) where T : metagen.IRpc
|
||||
{
|
||||
this.Client = client;
|
||||
return new MockRpcCallBuilder<T>(rpc);
|
||||
}
|
||||
|
||||
public MockApiBase(IRpcCaller caller)
|
||||
{
|
||||
this.Caller = caller;
|
||||
}
|
||||
|
||||
{%- for rpc in obj.rpcs ~%}
|
||||
|
||||
public virtual {{token_or(obj, 'cs_service_call_builder', 'RpcCallBuilder')}}<{{rpc.name}}> Begin({{rpc.name}} rpc)
|
||||
public virtual IRpcCallBuilder<{{rpc.name}}> Begin({{rpc.name}} rpc)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
@ -150,7 +101,7 @@ static public class ApiExtensions
|
|||
return __rpc;
|
||||
}
|
||||
|
||||
static public {{token_or(obj, 'cs_service_call_builder', 'RpcCallBuilder')}}<{{rpc.name}}> {{rpc.name}}(this IApi __api{%- if rpc.req.fields|length > 0 -%},{%-endif-%}
|
||||
static public IRpcCallBuilder<{{rpc.name}}> {{rpc.name}}(this IApi __api{%- if rpc.req.fields|length > 0 -%},{%-endif-%}
|
||||
{%- for fld in rpc.req.fields ~%}
|
||||
{{fld.type|cs_type}} {% if has_token(fld, 'default') -%} {{ var_reset(fld.name, fld.type, token(fld, 'default'))|trim(';', 'right') }} {%-else-%} {{fld.name}} {%-endif-%}
|
||||
{%- if not loop.last -%},{%-endif-%}
|
||||
|
@ -174,8 +125,6 @@ static public class ApiExtensions
|
|||
|
||||
{%- macro gen_server(obj) ~%}
|
||||
|
||||
{% import "macro.twig" as cs_macro %}
|
||||
|
||||
public interface IServer<TConn, TRet>
|
||||
{
|
||||
|
||||
|
@ -196,7 +145,7 @@ public static class Router<TConn, TRet>
|
|||
{%- endfor ~%}
|
||||
}
|
||||
|
||||
static public TRet DispatchRequest(IServer<TConn, TRet> server, TConn conn, IRpc rpc)
|
||||
static public TRet DispatchRequest(IServer<TConn, TRet> server, TConn conn, metagen.IRpc rpc)
|
||||
{
|
||||
switch(rpc.GetCode())
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue