//
// Copyright (c) 2009-2014,2017,2022,2025 LAAS/CNRS
// All rights reserved.
//
// Permission to use, copy, modify,  and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE  SOFTWARE  IS  PROVIDED  "AS  IS" AND  THE  AUTHOR  DISCLAIMS  ALL
// WARRANTIES  WITH  REGARD  TO   THIS  SOFTWARE  INCLUDING  ALL  IMPLIED
// WARRANTIES  OF MERCHANTABILITY  AND  FITNESS. IN  NO  EVENT SHALL  THE
// AUTHOR BE  LIABLE FOR ANY SPECIAL, DIRECT,  INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER  RESULTING FROM LOSS OF USE, DATA OR
// PROFITS,  WHETHER  IN  AN  ACTION  OF CONTRACT,  NEGLIGENCE  OR  OTHER
// TORTIOUS  ACTION, ARISING  OUT OF  OR IN  CONNECTION WITH  THE  USE OR
// PERFORMANCE OF THIS SOFTWARE.
//
//                                      Anthony Mallet on Fri Jun 25 2010
//

ifdef::sidebartoc[]
include::_Sidebar.adoc[]
endif::[]

`C` mappings: From IDL types to `C` types
-----------------------------------------

[[scoped_names]]
=== Scoped names

The `C` mappings always use the global name for a type or a constant.
The `C` global name corresponding to a `genom3` IDL global name is
derived by converting occurrences of "::" to "_" (an underscore) and
eliminating the leading underscore.

[[constant]]
=== Mapping for constants

In `C`, constants defined in dotgen are mapped to a `C`
constant. For instance, the following IDL:
----
      const long longint = 1;
      const string str = "string example";
----

would map into
----
      const uint32_t longint = 1;
      const char *str = "string example";
----

The  identifier can  be referenced  at any  point in  the user's  code  where a
literal of that type is legal.

[[basic_type]]
=== Mapping for basic data types

The basic data types have the mappings shown in the table below.
Integer types use the `C99` fixed size integer types as provided
by the `stdint.h` standard header. Users do not have to include
this header: the template mapping generation procedure output the
appropriate `#include` directive along with the mappings for the
integer types.

.Basic data types mappings in C
[width="60%",cols="^,1",frame="topbot",options="header"]
|==================================================================
| IDL                  | C
| `boolean`            | `bool`
| `unsigned short`     | `uint16_t`
| `short`              | `int16_t`
| `unsigned long`      | `uint32_t`
| `long`               | `int32_t`
| `unsigned long long` | `uint64_t`
| `long long`          | `int64_t`
| `float`              | `float`
| `double`             | `double`
| `char`               | `int8_t`
| `octet`              | `uint8_t`
| `any`                | type any not implemented yet
|==================================================================

[[enumerated_type]]
=== Mapping for enumerated types

The C mapping of an IDL `enum` type is an unsigned, 32 bits wide
integer.  Each enumerator in an enum is defined in an anonymous
`enum` with an appropriate unsigned integer value conforming to
the ordering constraints.

For instance, the following IDL:
----
      module m {
        enum e {
          value1,
          value2
        };
      };
----

would map, according to the scoped names rules, into
----
      typedef uint32_t m_e;
      enum {
        m_value1 = 0
        m_value2 = 1
      };
----

[[string]]
=== Mapping for strings

`genom3`  IDL bounded  strings are  mapped to  nul terminated  character arrays
(i.e., C strings). Unbounded strings are mapped to a pointer on such a
character array.

For instance, the following OMG IDL declarations:
----
      typedef string unbounded;
      typedef string\<16> bounded;
----

would map into
----
      typedef char *unbounded;
      typedef char bounded[16];
----

[[array]]
=== Mapping for arrays

`genom3` IDL arrays map directly to C arrays. All array indices run from 0 to
`size-1`.

For instance, the following IDL:
----
      typedef long array[4][16];
----

would map into
----
      typedef int32_t array[4][16];
----

[[struct]]
=== Mapping for structure types

`genom3` IDL structures map directly onto C `struct`s. Note that these
structures may potentially include padding.

For instance, the following IDL:
----
      struct s {
         long a;
         long b;
      };
----

would map into
----
      typedef struct {
         int32_t a;
         int32_t b;
      } s;
----

[[union]]
=== Mapping for union types

`genom3`  IDL unions map onto  C `struct`. The discriminator in the enum
is referred to as `_d`, the union itself is referred to as `_u`.

For instance, the following IDL:
----
      union u switch(long) {
         case 1: long a;
         case 2: float b;
         default: char c;
      };
----

would map into
----
      typedef struct {
         int32_t _d;
         union {
            int32_t a;
            float b;
            char c;
         } _u;
      } u;
----

[[sequence]]
=== Mapping for sequence types

`genom3`  IDL  sequences  mapping  differ  slightly  for  bounded  or  unbouded
variations of the sequence. Both types maps  onto a C `struct`,
with a `_maximum`, `_length` and `_buffer` members.

For unbounded sequences, `buffer` points to a buffer of at most
`_maximum` elements and containing `_length` valid
elements. An additional member ` _release` is a function pointer
that can be used to release the storage associated to the `
_buffer` and reallocate it.  It is the responsibility of the user to
maintain the consistency between those members.

For bounded  sequences, ` buffer` is  an array of  at most  `_maximum`
elements and containing `_length`  valid elements. Since `_buffer` is
an array, no memory management is necessary for this data type.

For instance, the following IDL:
----
      typedef sequence<long> unbounded;
      typedef sequence<long,16> bounded;
----

would map into
----
      typedef struct {
         uint32_t _maximum, _length;
         int32_t *_buffer;
         void (*_release)(void *_buffer);
      } unbounded;

      typedef struct {
         uint32_t _maximum, _length;
         int32_t _buffer[16];
      } bounded;
----

A helper function for reserving space in unbounded sequences is
available. It is defined as follow:

----
      int genom_sequence_reserve(sequence_type *s, uint32_t length);
----
where `sequence_type` is the actual type name of the sequence.

Given a pointer `s` on a valid, unbouded sequence,
`genom_sequence_reserve` will allocate storage for up to
`length` elements. If needed, the previous storage is first
released using the function pointed to by `_release`. If the
sequence already had enough space available,
`genom_sequence_reserve` does nothing. New storage is allocated
using `malloc()`, and the `_release` member is updated to
point on the `free()` function. The `_maximum` member is
updated to reflect the new maximum number of elements that the
sequence may hold. Finally, the function returns 0 on success, or -1
if no memory could be allocated (in this case, the global variable
`errno` is updated with the value `ENOMEM`).

Beware that `genom_sequence_reserve` is able to shrink a sequence
if the `length` parameter happens to be smaller than the current
length of a sequence. In this case, any elements previously stored
beyond the new effective length will be definitely lost. The
`_length` member will be updated accordingly.

The use of this function to reserve space in a sequence is purely
optional. Any storage allocation strategy can be used, provided it
maintains the consistency between the `_maximum`, `_release`
and `_buffer` elements.

[[optional]]
=== Mapping for optional types

`genom3`  IDL optional types map onto  C `struct` with a
`_present` and `_value` members.

For instance, the following IDL:
----
      typedef optional< long > opt;
----

would map into
----
      typedef struct {
         bool _present;
         int32_t _value;
      } opt;
----

The `_present` member, when `true`, indicates the presence of
valid data in `_value`. When `_present` is `false`, the
`_value` should be ignored.

[[port]]
=== Mapping for port types

Simple ports map onto an object-like C `struct` with a
`data()` and `read()` or `write()` function
members. The `data()` function takes no parameter and returns a
pointer on the current port data. Input ports may refresh their data
by invoking the `read()` method, while output ports may publish
new data by invoking the `write()` method. Both `read()` and
`write()` return `genom_ok` on success, or a
`genom_event` exception representing an error code.

Ports defined with the `multiple` flag map onto a similar
`struct`, with the difference that `data()`, `read()`
and `write()` methods take an additional string (`const char
*`) parameter representing the port element name. Multiple output
ports have two additional `open()` and `close()` members
(also accepting a single string parameter) that dynamically create or
destroy ports.

For instance, the following IDL:
----
      port in double in_port;
      port multiple in double multi_in_port;
      port out double out_port;
      port multiple out double multi_out_port;
----

would map into
----
      typedef struct {
         double * (*data)(genom_context self);
         genom_event (*read)(genom_context self);
      } in_port;

      typedef struct {
         double * (*data)(const char *id, genom_context self);
         genom_event (*read)(const char *id, genom_context self);
      } multi_in_port;

      typedef struct {
         double * (*data)(genom_context self);
         genom_event (*write)(genom_context self);
      } out_port;

      typedef struct {
         double * (*data)(const char *id, genom_context self);
         genom_event (*write)(const char *id, genom_context self);
         genom_event (*open)(const char *id, genom_context self);
         genom_event (*close)(const char *id, genom_context self);
      } multi_out_port;
----

[[remote]]
=== Mapping for remote services

Remote objects map onto an object-like C `struct` providing a
`call()` method. `call()` takes the same parameters as the
corresponing service definition and returns `genom_ok` on
success, or a `genom_event` exception representing an error code.

For instance, the following IDL:
----
      interface i {
        function f(in long i, out double o);
      };

      component c {
        uses i;
      };
----

would map into
----
      typedef struct c_f {
        genom_event (*call)(uint32_t i, double *o, genom_context self);
      } c_f;
----

The remote service is invoked in a synchronous manner.

[[native]]
=== Mapping for native types

`genom3` IDL native types map to a C `struct`. The mapping
provides only a forward declaration, and the user has to provide the
actual definition.

For instance, the following IDL:
----
      native opaque;
----

would map into
----
      typedef struct opaque opaque;
----

The definition of the structure body is free, and will typically use
native C types that cannot be described in IDL. When used as a
parameter of a function, a native type will be passed around as a
pointer on the structure data. Memory management associated with that
pointer must be handled by the user.

[[exception]]
=== Mapping for exceptions

Each defined exception type is defined as a `struct` tag and a
`typedef` with the C global name for the exception suffixed by
`_detail`. An identifier for the exception is also defined, as is
a type-specific function for raising the exception. For example:

----
      exception foo {
        long dummy;
      };
----

yields the following C declarations:
----
      genom_event foo_id = <unique identifier for exception>;

      typedef struct foo_detail {
        uint32_t dummy;
      } foo_detail;

      genom_event foo(const foo_detail *detail, genom_context self);
----

The identifier for the exception uniquely identifies this exception
type, so that any data of type `genom_event` can be compared to
an exception id with the `==` operator.

The function throwing the exception returns a `genom_event`
that should be used as the return value of a codel. It makes a copy of
the exception details.

Since exceptions are allowed to have no members, but C structs must
have at least one member, exceptions with no members map to the C
`void` type and the type-specific throw function takes no
argument.
