Skip to content

Commit

Permalink
[#13] Implement services (without reflectable parts)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mi-La committed Jan 24, 2025
1 parent 3f22428 commit 1058776
Show file tree
Hide file tree
Showing 20 changed files with 1,269 additions and 2 deletions.
2 changes: 1 addition & 1 deletion cmake/compiler_utils.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ function(compiler_get_warnings_as_errors_setup VARNAME)
)
string(REPLACE ";" " " WARNINGS_SETUP "${WARNINGS_SETUP} ${WARNINGS_SETUP_LIST}")
endif ()
if (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL "14.0.0")
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "14.0.0")
set(WARNINGS_SETUP_LIST
"-Wno-error=reserved-identifier" # identifier is reserved because it starts with '_' ...
"-Wno-error=deprecated-copy-with-dtor" # definition of implicit copy constructor is deprecated
Expand Down
112 changes: 112 additions & 0 deletions extension/freemarker/Service.cpp.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<#include "FileHeader.inc.ftl">
<#include "Service.inc.ftl">
<@file_header generatorDescription/>

#include <zserio/SerializeUtil.h>
<@type_includes types.bitBuffer/>
<@system_includes cppSystemIncludes/>

<@user_include package.path, "${name}.h"/>
<@user_includes cppUserIncludes, false/>
<@namespace_begin package.path/>
<@namespace_begin [name]/>

Service::Service(const AllocatorType& allocator) :
::zserio::AllocatorHolder<${types.allocator.default}>(allocator)
{}

${types.serviceDataPtr.name} Service::callMethod(
::std::string_view methodName, ::zserio::Span<const uint8_t> requestData, void* context)
{
<#list methodList as method>
if (methodName == methodNames()[${method?index}])
{
return ${method.name}Method(requestData, context);
}
</#list>
throw ::zserio::ServiceException("${serviceFullName}: Method '") << methodName << "' does not exist!";
}

::std::string_view Service::serviceFullName() noexcept
{
static const ::std::string_view serviceFullName = "${serviceFullName}";
return serviceFullName;
}

const ::std::array<::std::string_view, ${methodList?size}>& Service::methodNames() noexcept
{
static constexpr ::std::array<::std::string_view, ${methodList?size}> names =
{
<#list methodList as method>
"${method.name}"<#if method?has_next>,</#if>
</#list>
};

return names;
}
<#list methodList as method>

${types.serviceDataPtr.name} Service::${method.name}Method(
::zserio::Span<const uint8_t> requestData, void* context)
{
<#if !method.requestTypeInfo.isBytes>
${method.requestTypeInfo.typeFullName} request(get_allocator_ref());
zserio::deserializeFromBytes(requestData, request);

</#if>
<#if method.responseTypeInfo.isBytes>
return ::std::allocate_shared<${types.rawServiceDataHolder.name}>(get_allocator_ref(),
${method.name}Impl(request<#if method.requestTypeInfo.isBytes>Data</#if>, context));
<#else>
class ResponseData : public ${types.serviceDataPtr.name}::element_type
{
public:
ResponseData(${method.responseTypeInfo.typeFullName}&& response, const AllocatorType& allocator) :
m_serviceData(response, allocator)
{}

::zserio::Span<const uint8_t> getData() const override
{
return m_serviceData.getData();
}

private:
${types.objectServiceData.name} m_serviceData;
};

return ::std::allocate_shared<ResponseData>(get_allocator_ref(),
${method.name}Impl(request<#if method.requestTypeInfo.isBytes>Data</#if>, context), <#rt>
<#lt>get_allocator_ref());
</#if>
}
</#list>

Client::Client(${types.serviceClient.name}& service, const AllocatorType& allocator) :
::zserio::AllocatorHolder<${types.allocator.default}>(allocator),
m_service(service)
{
}
<#list methodList as method>

${method.responseTypeInfo.typeFullName} Client::${method.name}Method(<#rt>
<#lt><@service_arg_type_name method.requestTypeInfo/> request, void* context)
{
<#if method.requestTypeInfo.isBytes>
const ${types.rawServiceDataView.name} requestData(request);
<#else>
const ${types.objectServiceData.name} requestData(request, get_allocator_ref());
</#if>

auto responseData = m_service.callMethod("${method.name}", requestData, context);
<#if method.responseTypeInfo.isBytes>
return responseData;
<#else>

${method.responseTypeInfo.typeFullName} response(get_allocator_ref());
zserio::deserializeFromBytes(responseData, response);
return response;
</#if>
}
</#list>
<@namespace_end [name]/>
<@namespace_end package.path/>
155 changes: 155 additions & 0 deletions extension/freemarker/Service.h.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
<#include "FileHeader.inc.ftl">
<#include "DocComment.inc.ftl">
<#include "Service.inc.ftl">
<@file_header generatorDescription/>

<@include_guard_begin package.path, name/>

<@runtime_version_check generatorVersion/>

#include <array>
#include <zserio/Types.h>
<@type_includes types.service/>
#include <zserio/AllocatorHolder.h>
#include <zserio/ServiceException.h>
<@system_includes headerSystemIncludes/>
<@user_includes headerUserIncludes/>
<@namespace_begin package.path/>
<@namespace_begin [name]/>

/**
* Service part of the service ${name}.
*
<#if docComments??>
* \b Description
*
<@doc_comments_inner docComments/>
</#if>
*/
class Service :
public ${types.service.name},
public ::zserio::AllocatorHolder<${types.allocator.default}>
{
public:
/**
* Default constructor.
*
* \param allocator Allocator to construct from.
*/
explicit Service(const AllocatorType& allocator = AllocatorType());

/** Default destructor. */
~Service() override = default;

/** Disables copy constructor. */
Service(const Service&) = delete;
/** Disables assignment operator. */
Service& operator=(const Service&) = delete;

/** Default move constructor. */
Service(Service&&) = default;
/** Disables move assignment operator. */
Service& operator=(Service&&) = delete;

/**
* Calls method with the given name synchronously.
*
* \param methodName Name of the service method to call.
* \param requestData Request data to be passed to the method.
* \param context Context specific for particular service.
*
* \return Created response data.
*
* \throw ServiceException if the call fails.
*/
${types.serviceDataPtr.name} callMethod(
::std::string_view methodName, ::zserio::Span<const uint8_t> requestData,
void* context) override;

/**
* Gets the service full qualified name.
*
* \return Service name together with its package name.
*/
static ::std::string_view serviceFullName() noexcept;

/**
* Gets all method names of the service.
*
* \return Array of all method names of the service.
*/
static const ::std::array<::std::string_view, ${methodList?size}>& methodNames() noexcept;

private:
<#if methodList?has_content>
<#list methodList as method>
virtual ${method.responseTypeInfo.typeFullName} ${method.name}Impl(<#rt>
<#lt><@service_arg_type_name method.requestTypeInfo/> request, void* context) = 0;
</#list>

<#list methodList as method>
${types.serviceDataPtr.name} ${method.name}Method(
::zserio::Span<const uint8_t> requestData, void* context);
</#list>
</#if>
};

/**
* Client part of the service ${name}.
*
<#if docComments??>
* \b Description
*
<@doc_comments_inner docComments/>
</#if>
*/
class Client : public ::zserio::AllocatorHolder<${types.allocator.default}>
{
public:
/**
* Constructor from the service client backend.
*
* \param service Interface for service client backend.
* \param allocator Allocator to construct from.
*/
explicit Client(${types.serviceClient.name}& service, const AllocatorType& allocator = AllocatorType());

/** Default destructor. */
~Client() = default;

/** Disables copy constructor. */
Client(const Client&) = delete;
/** Disables assignment operator. */
Client& operator=(const Client&) = delete;

/** Default move constructor. */
Client(Client&&) = default;
/** Disables move assignment operator. */
Client& operator=(Client&&) = delete;
<#list methodList as method>

/**
* Calls method ${method.name}.
*
<#if method.docComments??>
* \b Description
*
<@doc_comments_inner method.docComments, 1/>
*
</#if>
* \param request Request to be passed to the method.
* \param context Context specific for particular service.
*
* \return Response returned from the method.
*/
${method.responseTypeInfo.typeFullName} ${method.name}Method(<#rt>
<#lt><@service_arg_type_name method.requestTypeInfo/> request, void* context = nullptr);
</#list>

private:
${types.serviceClient.name}& m_service;
};
<@namespace_end [name]/>
<@namespace_end package.path/>

<@include_guard_end package.path, name/>
7 changes: 7 additions & 0 deletions extension/freemarker/Service.inc.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<#macro service_arg_type_name typeInfo>
<#if typeInfo.isBytes>
::zserio::BytesView<#t>
<#else>
const ${typeInfo.typeFullName}&<#t>
</#if>
</#macro>
1 change: 1 addition & 0 deletions extension/src/zserio/extension/cpp17/Cpp17Extension.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ public void process(Root rootNode, ExtensionParameters parameters) throws Zserio
emitters.add(new ConstEmitter(outputFileManager, cppParameters, context));
emitters.add(new BitmaskEmitter(outputFileManager, cppParameters, context));
emitters.add(new EnumerationEmitter(outputFileManager, cppParameters, context));
emitters.add(new ServiceEmitter(outputFileManager, cppParameters, context));
emitters.add(new StructureEmitter(outputFileManager, cppParameters, context));
emitters.add(new ChoiceEmitter(outputFileManager, cppParameters, context));
emitters.add(new UnionEmitter(outputFileManager, cppParameters, context));
Expand Down
54 changes: 53 additions & 1 deletion extension/src/zserio/extension/cpp17/CppNativeMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ public CppNativeMapper(TypesContext typesContext)
bytesType = new NativeAllocType(typesContext.getBytes(), allocatorDefinition);
stringType = new NativeAllocType(typesContext.getString(), allocatorDefinition, "char");
vectorType = new NativeAllocType(typesContext.getVector(), allocatorDefinition);

serviceType = new NativeAllocType(typesContext.getService(), allocatorDefinition, "uint8_t");
serviceClientType =
new NativeAllocType(typesContext.getServiceClient(), allocatorDefinition, "uint8_t");
serviceDataPtrType =
new NativeAllocType(typesContext.getServiceDataPtr(), allocatorDefinition, "uint8_t");
objectServiceDataType =
new NativeAllocType(typesContext.getObjectServiceData(), allocatorDefinition, "uint8_t");
rawServiceDataHolderType =
new NativeAllocType(typesContext.getRawServiceDataHolder(), allocatorDefinition, "uint8_t");
rawServiceDataViewType =
new NativeAllocType(typesContext.getRawServiceDataView(), allocatorDefinition, "uint8_t");
}

public CppNativeSymbol getCppSymbol(AstNode symbol) throws ZserioExtensionException
Expand Down Expand Up @@ -164,6 +176,36 @@ public NativeAllocType getVectorType()
return vectorType;
}

public NativeAllocType getServiceType()
{
return serviceType;
}

public NativeAllocType getServiceClientType()
{
return serviceClientType;
}

public NativeAllocType getServiceDataPtrType()
{
return serviceDataPtrType;
}

public NativeAllocType getObjectServiceDataType()
{
return objectServiceDataType;
}

public NativeAllocType getRawServiceDataHolderType()
{
return rawServiceDataHolderType;
}

public NativeAllocType getRawServiceDataViewType()
{
return rawServiceDataViewType;
}

private CppNativeType mapArray(ArrayInstantiation instantiation) throws ZserioExtensionException
{
final TypeInstantiation elementInstantiation = instantiation.getElementTypeInstantiation();
Expand Down Expand Up @@ -615,7 +657,10 @@ public void visitExternType(ExternType type)
@Override
public void visitServiceType(ServiceType type)
{
thrownException = new ZserioExtensionException("TODO Unhandled type '" + type.getClass().getName());
final PackageName packageName = type.getPackage().getPackageName();
final String name = type.getName();
final String includeFileName = getIncludePath(packageName, name);
cppType = new NativeUserType(packageName, name, includeFileName);
}

@Override
Expand Down Expand Up @@ -709,6 +754,13 @@ private void mapAliasType(ZserioType aliasType, TypeReference referencedType)
private final NativeAllocType stringType;
private final NativeAllocType vectorType;

private final NativeAllocType serviceType;
private final NativeAllocType serviceClientType;
private final NativeAllocType serviceDataPtrType;
private final NativeAllocType objectServiceDataType;
private final NativeAllocType rawServiceDataHolderType;
private final NativeAllocType rawServiceDataViewType;

private final static NativeNumericWrapperType booleanType = new NativeNumericWrapperType("Bool", "bool");
private final static NativeNumericWrapperType float16Type =
new NativeNumericWrapperType("Float16", "float");
Expand Down
Loading

0 comments on commit 1058776

Please sign in to comment.