###############
API Conventions
###############

.. _api_typedefs:

Type Definitions
================

The file *A3DSDKTypes.h* provides essential fixed-size numeric types used throughout the API:

================= ========================================================== ============================
 Type              Description                                                Standard Type Equivalent
================= ========================================================== ============================
 ``A3DBool``       Boolean descriptor. Can be ``A3D_TRUE`` or ``A3D_FALSE``   ``char``
 ``A3DUns8``       Unsigned integer type with width of exactly 8 bits         ``unsigned char``
 ``A3DInt8``       Signed integer type with width of exactly 8 bits           ``char``
 ``A3DUns16``      Unsigned integer type with width of exactly 16 bits        ``unsigned short``
 ``A3DInt16``      Signed integer type with width of exactly 16 bits          ``short``
 ``A3DInt32``      Signed integer type with width of exactly 32 bits          *implementation dependent*
 ``A3DUns32``      Unsigned integer type with width of exactly 32 bits        *implementation dependent*
 ``A3DDouble``     IEEE 754 64-bits floating-point number                     ``double``
 ``A3DFloat``      IEEE 754 32-bits floating-point number                     ``float``
 ``A3DVoid``       Void type Void type                                        ``void``
 ``A3DPtr``        Void pointer type type Void pointer type type              ``void*``
 ``A3DUTF8Char``   :ref:`UTF-8 character type <api_string>`                   ``char*``
================= ========================================================== ============================

.. _api_architecture:

Architecture
============

The HOOPS Exchange architecture is closely tied to its naming design.
Most data in your HOOPS application are manipulated through entities, such as PRC, features, or BIM entities.
Each entity type consists of:

- An enumerator value within ``A3DEEntityType`` used for identification.
- A handle type that uniquely identifies the entity within HOOPS.
- Optionally, a data structure for retrieving or editing the entity's state.

Additionally, the API may provide CRUD-like functions for each entity type to manipulate its content.
Not all entity types offer all functions, depending on relevance and indirect operations.

The following table illustrates the strict naming convention used for an entity type with some examples:

+-------------------+-----------------------------------+------------------------------+-------------------------------+-------------------------------+
|                   | **Model File**                    | **BIM Data**                 | **NURBS Curve**               | **Topo Body**                 |
+===================+===================================+==============================+===============================+===============================+
| Handle Type       | ``A3DAsmModelFile``               | ``A3DBIMData``               | ``A3DCrvNurbs``               | ``A3DTopoBody``               |
+-------------------+-----------------------------------+------------------------------+-------------------------------+-------------------------------+
| ``A3DEntityType`` | ``kA3DTypeAsmModelFile``          | ``kA3DTypeBIMData``          | ``kA3DTypeCrvNurbs``          | ``kA3DTypeTopoBody``          |
+-------------------+-----------------------------------+------------------------------+-------------------------------+-------------------------------+
| ``struct``        | :cpp:struct:`A3DAsmModelFileData` | :cpp:struct:`A3DBIMDataData` | :cpp:struct:`A3DCrvNurbsData` | :cpp:struct:`A3DTopoBodyData` |
+-------------------+-----------------------------------+------------------------------+-------------------------------+-------------------------------+
| *Create*          | :cpp:func:`A3DAsmModelFileCreate` |                              | :cpp:func:`A3DCrvNurbsCreate` |                               |
+-------------------+-----------------------------------+------------------------------+-------------------------------+-------------------------------+
| *Get*             | :cpp:func:`A3DAsmModelFileGet`    | :cpp:func:`A3DBIMDataGet`    | :cpp:func:`A3DCrvNurbsGet`    | :cpp:func:`A3DTopoBodyGet`    |
+-------------------+-----------------------------------+------------------------------+-------------------------------+-------------------------------+
| *Set*             |                                   |                              |                               | :cpp:func:`A3DTopoBodySet`    |
+-------------------+-----------------------------------+------------------------------+-------------------------------+-------------------------------+
| *Delete*          | :cpp:func:`A3DAsmModelFileDelete` |                              |                               |                               |
+-------------------+-----------------------------------+------------------------------+-------------------------------+-------------------------------+


.. _api_get_type:

Querying the Entity Type of a Handle
------------------------------------

When you have an entity handle and need to determine its underlying type, use ``A3DEntityGetType`` and match the result to ``A3DEEntityType``.
For example, to check if ``pHandle`` is a model file:

.. code-block:: c

   A3DEEntityType eType = kA3DTypeUnknown;
   A3DEntityGetType(pHandle, &eType);
   assert(eType == kA3DTypeAsmModelFile);

.. _api_get_data:

Retrieving the Data of an Entity
--------------------------------

The most common operation on an entity is retrieving its data for reading.
This involves **initializing** the data structure, **retrieving** the entity data, and **disposing** of the data structure when no longer needed.
Here's an example function that retrieves and prints the number of children product occurrences:

.. code-block:: c

   void PrintChildrenPO(const A3DAsmProductOccurrence* pHandle)
   {
     A3DAsmProductOccurrenceData sData = A3D_MAKE_DATA(A3DAsmProductOccurrenceData);
     A3DAsmProductOccurrenceGet(pHandle, &sData);

     printf("Number of children: %d\n", pData->m_uiPOccurrencesSize);

     A3DAsmProductOccurrenceGet(0, &sData);
   }

Let's detail this code line by line.
To initialize a data structure, declare it as a non-const variable use the ``A3D_MAKE_DATA`` macro:

.. code-block:: c

   A3DAsmProductOccurrenceData sData = A3D_MAKE_DATA(A3DAsmProductOccurrenceData); // don't use &

Once the structure is initialized, **use the Get function to retrieve the data**.
In the following line, ``pHandle`` is of type ``const A3DAsmProductOccurrence*``.

.. code-block:: c

   A3DAsmProductOccurrenceGet(pHandle, &sData);

Then, when the data is not needed anymore, give the data back to the API by calling **the same function**.
Set the handle parameter to *0*.

.. code-block:: c

   A3DAsmProductOccurrenceGet(0, &sData);

.. note:: Why disposing the data structure?

   HOOPS Exchange structures may contains heap allocated data such as arrays and strings.
   It is essentials to remain memory consistent by letting the API releasing it.
   See :ref:`the section about memory management <api_memory_management>` for more.

Arrays as ``struct`` Fields
---------------------------

Lists in HOOPS Exchange offer access to different data fields, like product occurrences in a model file or representation items in an ``A3DRiSet``.
To work with these lists, HOOPS Exchange uses standard C sequential array types.
Each array is composed of two parts: an ``A3DUns32`` field to store the array's size and a pointer to the array itself.

.. code-block:: c

   typedef struct {
       // ...
       A3DUns32 m_uiPOccurrencesSize;
       A3DAsmProductOccurrences** m_ppOccurrences;
       // ...
   } A3DAsmModelFile;

Some array size specifiers can describe multiple arrays, illustrating their close relationship.

Entity Hierarchy
----------------

The HOOPS architecture incorporates an **abstraction and specialization** mechanism for its entities. 
For instance, all entities can be abstracted as an ``A3DEntity`` type, while the majority of entities are specializations of ``A3DRootBase``. 
In practical terms, this means that when an entity can be abstracted into another type, it can be safely *manipulated as the abstract type.*.

Certain abstract types also have their own data structures. 
For example, any product occurrence represented as an ``A3DAsmProductOccurrence`` is also considered a *root base* entity, specifically an ``A3DRootBase``. 
Therefore, the code remains valid even if ``pHandle`` is an instance of ``A3DAsmProductOccurrence*``.

.. code-block:: c

   A3DRootBaseData sData = A3D_MAKE_DATA(A3DRootBaseData);
   A3DRootBaseGet(pHandle, &sData);

Conversely, it's possible to pass a handle of type ``A3DRootBase*`` to a function that anticipates an ``A3DAsmProductOccurrence*``. 
In such cases, the responsibility falls upon the caller to :ref:`ensure the entity's correct type <api_get_type>`. 
For instance, this example verifies the type of ``pHandle`` before passing it to the ``PrintChildrenPO`` function, as shown in the :ref:`previous example <api_get_data>`.

.. code-block:: c

   A3DEEntityType eType = kA3DTypeUnknown;
   A3DEntityGetType(pHandle, &eType);

   if (eType == kA3DTypeAsmProductOccurrence) {
     PrintChildrenPO(pHandle);
   }

Any API call using an unexpected entity type will return ``A3D_INVALID_ENTITY_TYPE``.

.. note::

   Because it's similar to but not exactly like object-oriented programming (OOP), the way entities are organized can be something confusing.
   Another way to understand the relationship between entity types is to think of HOOPS Exchange as a database. 
   For instance, in this example, the term "pHandle" would be like a key that exists in both the "ProductOccurrence" and "A3DRootBase" tables.

Structural Hierarchy
~~~~~~~~~~~~~~~~~~~~

Many complex structures in HOOPS Exchange are organized like trees.
For instance, the :doc:`PRC tree </guide/basic_operations/prc_basics>` contains all the parts that make up a model file. 
And the :doc:`Feature tree </guide/feature_trees>` arranges all the steps a CAD application takes to create the final part. 
Within these structures, one entity instance can be the "parent" of one or more other entities.

Although there's no direct connection between the structural and type hierarchies, it's worth noting that entities in the same tree usually belong to the same entity type. 
For example, entities in a PRC tree can be things like ``A3DAsmProductOccurrence,`` ``A3DRiRepresentationItem,`` or ``A3DRiPart`` (and others), but they're all types of ``A3DRootBase.``

.. _api_memory_management:

Memory Management
-----------------

Since HOOPS Exchange is a C API, you **need to explicitly free any memory that's allocated** during runtime after you're done using it. 
Many functions and data structures provide such memory, but it's up to your application to decide when to release it. 

One common scenario for memory cleanup is when you're retrieving entity data, as shown in the :ref:`example for entity data retrieval <api_get_data>`. 
If the *Get* function allocates memory, it's important to note that these memory blocks are specific to that particular function call. 
For example, in the following case, ``sData0.m_pcName`` and ``sData1.m_pcName`` point to different memory locations, even though they belong to the same entity. 
This happens because the *Name* of a root base is copied into the A3DRootBaseData parameter internally.

.. code-block:: c

   A3DRootBaseData sData0 = A3D_MAKE_DATA(A3DRootBaseData);
   A3DRootBaseData sData1 = A3D_MAKE_DATA(A3DRootBaseData);

   A3DRootBaseGet(pHandle, &sData0);
   A3DRootBaseGet(pHandle, &sData1);

.. code-block:: c

   assert(sData0.m_pcName != sData1.m_pcName);

After you've finished using the code, you need to return both ``sData0`` and ``sData1`` to the library so that it can properly clean up the allocated memory. 
You can do this by making another call to ``A3DRootBaseGet`` with *0* as the handle.

.. code-block:: c

   A3DRootBaseGet(0, &sData1);
   A3DRootBaseGet(0, &sData0);

.. warning::

   Even if a data structure currently doesn't use dynamically allocated memory, it might in future API versions.
   To ensure your code remains robust and avoids tricky memory leaks due to changes, it's a good practice to **always clean up your data structures**, regardless of their type.
   
   Certain functions also provide dynamically allocated memory using "out parameters"
   In these cases, you can find details on how to release that memory in the function's documentation.

Providing the Memory Functions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you want to control how memory is allocated within HOOPS API functions, you can set your own allocation and deallocation functions:

.. code-block:: c

   A3DPtr CustomAlloc(size_t uiSize)
   {
     return malloc(uiSize);
   }

   A3DVoid CustomFree(A3DPtr pBlock) {
     free(pBlock);
   }

   A3DDllSetCallbacksMemory(CustomAlloc, CustomFree);

``A3DDllSetCallbacksMemory`` must be called before ``A3DDllInitialize``.

Deleting Entities
~~~~~~~~~~~~~~~~~

Deleting an entity itself isn't a common operation in HOOPS Exchange, but some entity types do offer a delete function.

When you use :cpp:func:`A3DModelFileDelete` on a model file entity, it gets entirely removed.
This action includes all the ``A3DRootBase`` entities that make up the PRC structure.
Most of the time, this is the only delete function you need.

The more general-purpose :cpp:func:`A3DEntityDelete` function can be used to delete a specific entity.
It removes the entity itself and any child entities in the case of an ``A3DRootBase``.
It's important to note that this function doesn't check whether the given entity exists somewhere in the PRC tree.

Some specific entities provide their own *Delete()* function:

*  ``A3DFaceUVPointInsideManagerDelete``
*  ``A3DFileContextDelete``
*  ``A3DMiscCascadedAttributesDelete``
*  ``A3DMkpRTFDelete``
*  ``A3DMkpRTFFieldDelete``
*  ``A3DProjectPointCloudManagerDelete``

Garbage Collection
~~~~~~~~~~~~~~~~~~

When you :doc:`shut down the library </guide/basic_operations/initialize-hoops-exchange>`, the HOOPS context takes care of releasing any remaining memory blocks.
This includes internal buffers and unlinked entities.

Error Management
----------------

HOOPS manages errors by returning a status code from all its functions.
If a function completes without errors, it returns the value ``A3D_SUCCESS`` (which is *0*).
Any non-zero value indicates an error.

You can find a comprehensive list of error codes in the ``A3DStatus`` enumeration within the *A3DSDKErrorCodes.h* file.

It's important to note that the same error code might have different meanings depending on the function that returns it.
For detailed information about a value returned by a specific function call, consult the documentation of that function.

:cpp:func:`A3DMiscGetErrorMsg` can be used to obtain a description of the error code:

.. code-block:: c

   // ...
   A3DStatus iStatus = A3DAsmModelFileLoadFromFile(pcPath, &sLoadData, &pHandle);

   if (iStatus) {
     fprintf(stderr, "Cannot load model file: '%s'\n", A3DMiscGetErrorMsg(iStatus));
   }

.. _api_string:

String Encoding
---------------

HOOPS uses standard C-Strings for handling text, which are in-memory arrays of characters with a null-termination character (*0*).

When dealing with character data, **HOOPS Exchange adopts UTF-8 encoding**.
Therefore, any function or structure that needs strings as input must ensure proper conversion to UTF-8 before use.
The API offers utility functions for these conversions:

*  ``A3DMiscUTF16ToUTF8``
*  ``A3DMiscUTF8ToUTF16``
*  ``A3DMiscUTF8ToUnicode``
*  ``A3DMiscUnicodeToUTF8``

Code Conventions
================

HOOPS Exchange is a C API, which means any source code, including our headers, is assured to compile with a C or C++ compliant compiler.
To get detailed information about the compiler requirements, you can refer to the :doc:`platform requirements page </start/supported-platforms>`.

Header Files
------------

All the header files can be found directly under the *include/* folder of your HOOPS installation.
These files are named using *PascalCase* and have one of the following prefixes:

- *A3DSDK* for most of our SDK.
- *A3DPDF* for files specific to the Advanced Publishing SDK.
- *A3DCommon* for code that is common to both APIs.

.. sidebar:: License

   You can find more information about setting the license in :ref:`tuto_init_license`.

The only exception is *hoops_license.h*.
This file should be replaced with the one typically obtained from `the license file generator <https://developer.techsoft3d.com/license-generator/>`__.

All our header files contain only the declarations and inclusions they need for compilation.
They are also designed to be *self-sufficient*, meaning they don't depend on the inclusion context to work correctly, as long as the ``#include`` directive is at the global scope.

To compile a source file using HOOPS declarations, you only need to include the relevant header file that contains the declaration you require.
For example, including *A3DSDKStructure.h* is sufficient to compile a source code that uses the :cpp:struct:`A3DAsmModelFileData` structure.

If you want to include all API header files in one go, you can use the convenience header *A3DSDKIncludes.h*.
This file is also included within *A3DSDKLoader.h* to ensure that :doc:`all functions are loaded correctly during initialization </guide/basic_operations/initialize-hoops-exchange>`.

Naming Conventions
------------------

The API follows certain naming conventions:

- Symbol names are in *PascalCase*, with the exception of macro definitions and ``A3DStatus`` values, which use *CAPITAL_CASE*.

- Variables, formal parameters, and struct members use a naming convention known as **Systems Hungarian Notation**:

  - Struct members begin with ``m_``, followed by:
  - ``p`` for pointer type, and then
  - A prefix based on the data type:

    - ``b`` for ``A3DBool``
    - ``i`` for ``A3DInt8``, ``A3DInt16``, and ``A3DInt32``
    - ``ui`` for ``A3DUns8``, ``A3DUns16``, and ``A3DUns32``
    - ``f`` and ``d`` for ``A3DFloat`` and ``A3DDouble``, respectively
    - ``c`` for ``A3DUTF8Char``
    - ``e`` for enumerations
    - ``s`` for structures

Namespacing
-----------

All data types and functions are organized using a series of prefixes. 

The primary prefix is always ``A3D``, and it's followed by additional prefixes to create sub-namespaces for functions and related symbols. 

For example, :cpp:func:`A3DTess3DCreate` and :cpp:func:`A3DTessMarkupCreate` share the same base name but belong to different sub-namespaces, namely ``Tess3D`` and ``TessMarkup``, respectively.

Associated symbols also follow the same naming pattern:

- ``A3DAsmModelFile``: This represents an :ref:`entity handle <api_architecture>` for an assembly model file.
- :cpp:struct:`A3DAsmModelFileData`: This is a data structure that describes a model file.
- :cpp:func:`A3DAsmModelFileLoadFromFile`: This function is responsible for loading a model file into memory.


