Slice Metadata Directives
Overview
Slice has the concept of a metadata directive. For example:
["java:type:java.util.LinkedList<Integer>"] sequence<int> IntSeq;
A metadata directive can appear as a prefix to any Slice definition. Metadata directives appear in a pair of square brackets and contain one or more string literals separated by commas. For example, the following is a syntactically valid metadata directive containing two strings:
["a", "b"] interface Example {}
Metadata directives are not part of the Slice language per se: the presence of a metadata directive has no effect on the client-server contract, that is, metadata directives do not change the Slice type system in any way. Instead, metadata directives are targeted at specific back-ends, such as the code generator for a particular language mapping. In the preceding example, the java:
prefix indicates that the directive is targeted at the Slice to Java compiler.
Metadata directives permit you to provide supplementary information that does not change the Slice types being defined, but somehow influences how the compiler will generate code for these definitions. For example, a metadata directive java:type:java.util.LinkedList<T>
instructs the Slice to Java compiler to map a sequence to a linked list instead of an array (which is the default).
Metadata directives are also used to create skeletons that support Asynchronous Method Dispatch (AMD) in some languages.
Apart from metadata directives that are attached to a specific definition, there are also file metadata directives. For example:
[["cpp:dll-export:WIDGET_API"]]
Note that a file metadata directive is enclosed by double square brackets, whereas a local metadata directive (one that is attached to a specific definition) is enclosed by single square brackets. File metadata directives are used to pass instructions that affect the entire Slice file. File metadata directives must precede any definitions in a file (but can appear following any #include
directives).
We describe below the metadata directives you can use.
General Metadata Directives
amd
This directive applies to interfaces and operations. It enables code generation for asynchronous method dispatch. (See Operations for details).
deprecated[:message]
deprecate[:message]
This directive allows you to emit a deprecation warning for Slice constructs.
format
This directive defines the encoding format used for any classes or exceptions marshaled as the arguments or results of an operation. The tag can be applied to an interface, which affects all of its operations, or to individual operations. Legal values for the tag are format:sliced
, format:compact
, and format:default
. A tag specified for an operation overrides any setting applied to its enclosing interface. The Ice.Default.SlicedFormat property defines the behavior when no tag is present.
marshaled-result
This directive applies to operations and changes the return type of mapped skeleton methods in C++, C#, and Java. It has no effect on the client-side mapping.
With this directive, the mapped skeleton method returns a “marshaled result” struct or class that marshals the return value and out parameters immediately in its constructor. This allows you to perform the marshaling in a thread-safe manner, typically while holding a mutex lock.
For example:
sequence<int> IntSeq;
sequence<IntSeq> IntIntSeq;
sequence<string> StringSeq;
class Grid
{
StringSeq xLabels;
StringSeq yLabels;
IntIntSeq values;
}
interface GridIntf
{
// We want to marshal the returned Grid object within a lock,
// and return a consistent object not affected by concurrent calls to
// clearValues.
["marshaled-result"]
["cs:identifier:GetGrid"]
Grid getGrid();
void clearValues();
}
The mapped skeleton member function for getGrid
is:
GetGridMarshaledResult getGrid(const Ice::Current& current) = 0;
where GetGridMarshaledResult
is a generated class with a constructor that accepts a parameter for the return value, followed by Current
:
// Generated server-side code
class GetGridMarshaledResult : public Ice::MarshaledResult
{
public:
// Marshals returnValue immediately.
GetGridMarshaledResult(const GridPtr& returnValue, const Ice::Current& current);
};
A typical implementation of the getGrid
operation in your servant would be:
GetGridMarshaledResult
GridServant::getGrid(const Ice::Current& current)
{
lock_guard lock(_mutex);
// marshal _grid data member within synchronization
return GetGridMarshaledResult{_grid, current};
}
A marshaled-result instance is specific to a request. Do not cache a marshaled result and return it for another request.
suppress-warning
This file directive allows to suppress Slice compiler warnings. It applies to all definitions in the Slice file that includes this directive. If one or more categories are specified (for example "suppress-warning:invalid-metadata"
or "suppress-warning:deprecated, invalid-metadata"
) only warnings matching these categories will be suppressed, otherwise all warnings are suppressed. The categories are described in the following table:
Suppress Warning Category | Description |
---|---|
| Suppress all Slice compiler warnings. Equivalent to |
| Suppress warnings related to deprecated features. |
| Suppress warnings related to invalid doc-comments. |
Language-Specific Metadata Directives
The metadata directives for C++ uses the cpp
prefix.
cpp:array
This directive applies to sequence parameters in operations. It directs the Slice compiler to map these parameters to pairs of pointers.
cpp:const
This directive applies to operations. It directs the Slice compiler to create a const
pure virtual member function for the skeleton class.
The generated skeleton code calls servant member functions using a shared_ptr<non-const-T>
. Adding this const
only affects your own servant implementation code.
cpp:custom-print
This directive applies to enumerations, structs, classes and exceptions. It tells the Slice compiler that you want to implement your own “custom print” for this type, and not rely on the compiler-generated print implementation.
For an enum E, the Slice compiler generates a declaration for std::ostream& operator<<(std::ostream&, E)
in the enclosing namespace, but does not implement this operator.
For a struct S, the Slice compiler generates a declaration for std::ostream& operator<<(std::ostream&, const S&)
in the enclosing namespace, but does not implement this operator.
For a class or exception C, the Slice compiler generates a declaration for the member function void ice_print(std::ostream& os) const override
in the mapped C++ class, but does not implement this member function.
cpp:dll-export:SYMBOL
This file directive applies to all definitions in a Slice file.
Use SYMBOL
to control the export and import of symbols from DLLs on Windows and shared libraries on other platforms. This option allows you to export symbols from the generated code, and place such generated code in a DLL (on Windows) or shared library (on other platforms). As an example, compiling a Slice file Widget.ice
with:
[["cpp:dll-export:WIDGET_API"]]
results in the following additional code being generated into Widget.h
:
#ifndef WIDGET_API
# if defined(ICE_STATIC_LIBS)
# define WIDGET_API /**/
# ifdef WIDGET_API_EXPORTS
# define WIDGET_API ICE_DECLSPEC_EXPORT
# else
# define WIDGET_API ICE_DECLSPEC_IMPORT
# endif
#endif
The generated code also includes the provided SYMBOL
name (WIDGET_API
in our example) in the declaration of classes and functions that need to be exported (when building a DLL or shared library) or imported (when using such library).
ICE_DECLSPEC_EXPORT
and ICE_DECLSPEC_IMPORT
are macros that expand to compiler-specific attributes. For example, for Visual Studio, they are defined as:
#if defined(_MSC_VER)
# define ICE_DECLSPEC_EXPORT __declspec(dllexport)
# define ICE_DECLSPEC_IMPORT __declspec(dllimport)
With GCC and clang, they are defined as:
#elif defined(__GNUC__) || defined(__clang__)
# define ICE_DECLSPEC_EXPORT __attribute__((visibility ("default")))
# define ICE_DECLSPEC_IMPORT __attribute__((visibility ("default")))
The generated .cpp file (Widget.cpp
in our example) defines SYMBOL_EXPORTS
; this way, you don't need to do anything special when compiling generated files.
cpp:doxygen:include:c++-header
This file directive instructs the Slice compiler to generate a doc-comment with @headerfile
and the specified C++ header for all generated C++ classes.
cpp:header-ext:c++-ext
This file directive allows you to use a file extension for C++ header files other than the default .h
extension.
cpp:identifier:c++-identifier
This directive applies to all Slice constructs, and instructs the Slice compiler to use the specified c++-identifier
.
For example:
struct Descriptor
{
["cpp:identifier:blueprint"]
string template;
}
The cpp:identifier
directive ensures the field template
is mapped to blueprint
in C++. We can’t use the default mapping (template
) since it’s a C++ keyword.
cpp:ice_print
This directive applies to exceptions. It is a deprecated alias for cpp:custom-print
.
cpp:include:c++-header
This file directive allows you inject additional #include
directives into the generated C++ header file. This is useful for custom types.
cpp:source-ext:c++-ext
This file directive allows you to use a file extension for C++ source files other than the default .cpp
extension.
cpp:source-include:c++-header
This file directive allows you inject additional #include
directives into the generated C++ source file. This is required to make forward declared types visible to the source files.
cpp:type:c++-type
This directive applies to sequences and dictionaries. It directs the Slice compiler to map the Slice type or parameter to the provided C++ type.
cpp:type:string
and cpp:type:wstring
These directives apply to fields of type string as well as to containers, such as structures, classes and exceptions. String fields map by default to std::string
. You can use the cpp:type:wstring
metadata to cause a string field (or all string fields in a structure, class or exception) to map to std::wstring
instead. Use the cpp:type:string
metadata to force string fields to use the default mapping regardless of any enclosing metadata.
module A
{
["cpp:type:wstring"] struct Struct1
{
string s1; // Maps to std::wstring
["cpp:type:string"] string s2; // Maps to std::string
}
}
cpp:view-type:c++-view-type
This directive applies to sequence parameters. It directs the Slice compiler to map this parameter to the provided C++ type when this parameter does not need to hold any memory, for example when mapping an in-parameter to a proxy function.