{-# LANGUAGE QuasiQuotes, OverloadedStrings, RecordWildCards #-}
module Language.Bond.Codegen.Cpp.Grpc_h (grpc_h) where
import System.FilePath
import Data.Maybe (isNothing)
import Data.Monoid
import Prelude
import qualified Data.Text.Lazy as L
import Data.Text.Lazy.Builder
import Text.Shakespeare.Text
import Language.Bond.Util
import Language.Bond.Syntax.Types
import Language.Bond.Codegen.Util
import Language.Bond.Codegen.TypeMapping
import qualified Language.Bond.Codegen.Cpp.Util as CPP
grpc_h :: Maybe String -> MappingContext -> String -> [Import] -> [Declaration] -> (String, L.Text)
grpc_h export_attribute cpp file imports declarations = ("_grpc.h", [lt|
#pragma once
#include "#{file}_reflection.h"
#include "#{file}_types.h"
#{newlineSep 0 includeImport imports}
#{includeBondReflection}
#include <bond/core/bonded.h>
#include <bond/ext/grpc/reflection.h>
#include <bond/ext/grpc/detail/client.h>
#include <bond/ext/grpc/detail/service.h>
#include <boost/optional/optional.hpp>
#include <functional>
#include <memory>
#{CPP.openNamespace cpp}
#{doubleLineSep 1 grpc declarations}
#{CPP.closeNamespace cpp}
|])
where
includeImport (Import path) = [lt|#include "#{dropExtension (slashForward path)}_grpc.h"|]
idl = MappingContext idlTypeMapping [] [] []
cppType = getTypeName cpp
payload = maybe "void" cppType
bonded mt = bonded' (payload mt)
where
bonded' params = [lt|::bond::bonded<#{padLeft}#{params}>|]
where
paramsText = toLazyText params
padLeft = if L.head paramsText == ':' then [lt| |] else mempty
includeBondReflection =
if usesBondVoid then [lt|#include <bond/core/bond_reflection.h>|] else mempty
where usesBondVoid = any declUses declarations
declUses Service {serviceMethods = methods} = any methodUses methods
declUses _ = False
methodUses Function {methodInput = input} = isNothing (methodTypeToMaybe input)
methodUses Event {} = True
grpc s@Service{..} = [lt|
#{template}struct #{declName} final
{
struct Schema
{
#{export_attr}static const ::bond::Metadata metadata;
#{newlineSep 2 methodMetadata serviceMethods}
public: struct service
{
#{newlineSep 3 methodTemplate serviceMethods}
};
private: typedef boost::mpl::list<> methods0;
#{newlineSep 2 pushMethod indexedMethods}
public: typedef #{typename}methods#{length serviceMethods}::type methods;
#{constructor}
};
class #{proxyName} : public ::bond::ext::grpc::detail::client
{
public:
using ::bond::ext::grpc::detail::client::client;
#{doubleLineSep 2 publicProxyMethodDecl serviceMethods}
private:
#{newlineSep 2 privateProxyMethodDecl serviceMethods}
};
class #{serviceName} : public ::bond::ext::grpc::detail::service
{
public:
explicit #{serviceName}(const ::bond::ext::grpc::Scheduler& scheduler)
: ::bond::ext::grpc::detail::service(
scheduler,
{
#{commaLineSep 5 serviceMethodName serviceMethods}
})
{}
#{newlineSep 2 serviceVirtualMethod serviceMethods}
private:
void start() override
{
_data.emplace(*this);
}
struct data
{
explicit data(#{serviceName}& s)
: _s(s)
{}
#{serviceName}& _s;
#{newlineSep 3 serviceDataMember serviceMethodsWithIndex}
};
::boost::optional<data> _data;
};
};
#{onlyTemplate $ CPP.schemaMetadata cpp s}
|]
where
template = CPP.template s
onlyTemplate x = if null declParams then mempty else x
onlyNonTemplate x = if null declParams then x else mempty
typename = onlyTemplate [lt|typename |]
export_attr = onlyNonTemplate $ optional (\a -> [lt|#{a}
|]) export_attribute
methodMetadataVar m = [lt|s_#{methodName m}_metadata|]
methodMetadata m =
[lt|private: #{export_attr}static const ::bond::Metadata #{methodMetadataVar m};|]
indexedMethods :: [(String, Int)]
indexedMethods = zipWith ((,) . methodName) (reverse serviceMethods) [0..]
pushMethod (method, i) =
[lt|private: typedef #{typename}boost::mpl::push_front<methods#{i}, #{typename}service::#{method}>::type methods#{i + 1};|]
constructor = onlyTemplate [lt|Schema()
{
// Force instantiation of template statics
(void)metadata;
#{newlineSep 3 static serviceMethods}
}|]
where
static m = [lt|(void)#{methodMetadataVar m};|]
methodTemplate m = [lt|typedef struct : ::bond::ext::grpc::reflection::MethodTemplate<#{declName}, #{payload $ methodTypeToMaybe (methodInput m)}, #{resultType m}, &#{methodMetadataVar m}> {} #{methodName m};|]
proxyName = "Client" :: String
serviceName = "Service" :: String
serviceMethodsWithIndex :: [(Integer,Method)]
serviceMethodsWithIndex = zip [0..] serviceMethods
publicProxyMethodDecl Function{methodInput = Void, ..} = [lt|void Async#{methodName}(const ::std::function<void(::bond::ext::grpc::unary_call_result<#{payload (methodTypeToMaybe methodResult)}>)>& cb, ::std::shared_ptr<::grpc::ClientContext> context = {})
{
::bond::ext::grpc::detail::client::dispatch(_m#{methodName}, std::move(context), cb);
}
::std::future<::bond::ext::grpc::unary_call_result<#{payload (methodTypeToMaybe methodResult)}>> Async#{methodName}(::std::shared_ptr<::grpc::ClientContext> context = {})
{
return ::bond::ext::grpc::detail::client::dispatch<#{payload (methodTypeToMaybe methodResult)}>(_m#{methodName}, std::move(context));
}|]
publicProxyMethodDecl Function{..} = [lt|void Async#{methodName}(const #{bonded (methodTypeToMaybe methodInput)}& request, const ::std::function<void(::bond::ext::grpc::unary_call_result<#{payload (methodTypeToMaybe methodResult)}>)>& cb, ::std::shared_ptr<::grpc::ClientContext> context = {})
{
::bond::ext::grpc::detail::client::dispatch(_m#{methodName}, std::move(context), cb, request);
}
std::future<::bond::ext::grpc::unary_call_result<#{payload (methodTypeToMaybe methodResult)}>> Async#{methodName}(const #{bonded (methodTypeToMaybe methodInput)}& request, ::std::shared_ptr<::grpc::ClientContext> context = {})
{
return ::bond::ext::grpc::detail::client::dispatch<#{payload (methodTypeToMaybe methodResult)}>(_m#{methodName}, std::move(context), request);
}
void Async#{methodName}(const #{payload (methodTypeToMaybe methodInput)}& request, const ::std::function<void(::bond::ext::grpc::unary_call_result<#{payload (methodTypeToMaybe methodResult)}>)>& cb, ::std::shared_ptr<::grpc::ClientContext> context = {})
{
::bond::ext::grpc::detail::client::dispatch(_m#{methodName}, std::move(context), cb, request);
}
::std::future<::bond::ext::grpc::unary_call_result<#{payload (methodTypeToMaybe methodResult)}>> Async#{methodName}(const #{payload (methodTypeToMaybe methodInput)}& request, ::std::shared_ptr<::grpc::ClientContext> context = {})
{
return ::bond::ext::grpc::detail::client::dispatch<#{payload (methodTypeToMaybe methodResult)}>(_m#{methodName}, std::move(context), request);
}|]
publicProxyMethodDecl Event{methodInput = Void, ..} = [lt|void Async#{methodName}(::std::shared_ptr<::grpc::ClientContext> context = {})
{
::bond::ext::grpc::detail::client::dispatch(_m#{methodName}, std::move(context), {});
}|]
publicProxyMethodDecl Event{..} = [lt|void Async#{methodName}(const #{bonded (methodTypeToMaybe methodInput)}& request, ::std::shared_ptr<::grpc::ClientContext> context = {})
{
::bond::ext::grpc::detail::client::dispatch(_m#{methodName}, std::move(context), {}, request);
}
void Async#{methodName}(const #{payload (methodTypeToMaybe methodInput)}& request, ::std::shared_ptr<::grpc::ClientContext> context = {})
{
::bond::ext::grpc::detail::client::dispatch(_m#{methodName}, std::move(context), {}, request);
}|]
privateProxyMethodDecl f = [lt|const ::bond::ext::grpc::detail::client::Method _m#{methodName f}{ ::bond::ext::grpc::detail::client::make_method("/#{getDeclTypeName idl s}/#{methodName f}") };|]
serviceMethodName f = [lt|"/#{getDeclTypeName idl s}/#{methodName f}"|]
serviceDataMember (index,f) = [lt|::bond::ext::grpc::detail::service::Method _m#{index}{ _s, #{index}, ::bond::ext::grpc::detail::service::make_callback(&#{serviceName}::#{methodName f}, _s) };|]
serviceVirtualMethod f = [lt|virtual void #{methodName f}(::bond::ext::grpc::unary_call<#{payload $ methodTypeToMaybe $ methodInput f}, #{resultType f}>) = 0;|]
resultType Function{..} = payload (methodTypeToMaybe methodResult)
resultType Event{} = "::bond::reflection::nothing"
grpc _ = mempty