11.2 Automatic Maps

Automatic mapping is used when all the fields of the external format will be included in the internal format. This does not preclude explicit mapping of selected fields or types. Automatic mapping complies with the following steps for each field in the external format:

  1. Evaluate if the in_map contains an explicit mapping for the external field. If so, use that explicit mapping.
     

  2. If the preceding step fails, evaluate if the internal format (if specified) contains a field name that is identical to the external field name. If so, create with appropriate type conversions, a mapping between the two field names.
     

  3. If the preceding step fails and the external field is not marked as external_only, create a new field (with the same field name and the appropriate type) in the target_internal. Then create a mapping from the external field to this new internal field.

The type of the created internal field is controlled by the external field type.


External Type

Ultra Type mapped to

Primitive external

Maps to the corresponding primitive internal type. This depends on the external format specification.

External format (sub-record)

Unless a using in_map specification is applicable, a new in_map is automatically created to handle the mapping between the external sub-record and the internal field. The automatic map has by default no specified internal or target_internal name, however this can be modified with automatic mapping specifications.

List

Maps to an internal list type, where the list element type is deduced from the external list element type according to these rules (recursively).

target_internal

When using automatic, a new internal format may be automatically generated if any new internal fields are needed for the automatic mapping. The name of this new internal format is given by the target_internal specification of an in_map declaration. If no target_internal name specification is given, the format will still be generated if needed, however without usable name (that is, the format cannot be directly referred to in APL).

If a target_internal name has been given, this format will be created even if no new fields are created.

If the in_map has a specified internal format, the generated format is a subtype of this format (hence, inherits all its fields).

Automatic Mapping Specifications

It is possible to modify the behavior of the automatic mapping algorithm when generating the sub-maps. The most direct way to do this is to specify how each external type will be mapped, either by explicitly specifying the sub-map or specifying the internal and/or target_internal name.

The syntax for the two forms of  mapping specifications  is declared as follows:

<external type>: <in_map (target_)internal options> ;

and

<external type>: using in_map <map name>;

Example - Automatic mapping specifications

internal IntBase {
    int recordSequenceNumber;
};
asn_block {
    ExtDataFile ::= CHOICE(
        mc MobileCall,
        dp DataPacket)
    MobileCall ::= SET ( ... )
    DataPacket ::= SET ( ... )
};

in_map InMapDataFile :
    external(ExtDataFile),
    target_internal(IntDataFile) {
        automatic;
};  

In this case two new internal types will automatically be generated for MobileCall and DataPacket. However, they must usually be given a name or in other cases inherit the fields of some declared base internal format. This can be accomplished by adding some automatic mapping specifications:


Example - Adding automatic mapping specifications

in_map InMapDataFile :
external(ExtDataFile),
target_internal(IntDataFile) {
    automatic {
        MobileCall: internal(BaseInt),
            target_internal(TIMobileCall);
        DataPacket: internal(BaseInt),
            target_internal(TIDataPacket);
    };
}; 

This could also be done by specifying a using in_map declaration. For instance, the previous example is equivalent to the more complicated one:


Example - using in_map declaration

in_map MobileCallMap: internal(BaseInt),
    target_internal(TIMobileCall) {
        automatic;
};

in_map DataPacketMap: internal(BaseInt),
    target_internal(TIDataPacket) {
        automatic;
};

in_map InMapDataFile :
external(ExtDataFile),
target_internal(IntDataFile) {
    automatic {
        MobileCall: using in_map MobileCallMap;
        DataPacket: using in_map DataPacketMap;
    };
};

The type map specifications are inherited by every automatically generated sub-map:


Example - type map specifications inherited

asn_block { 
 ... 
     MobileCall ::= SET (location Location;) 
 ... 
 }; 
 external Location { 
     int longitude; 
     int latitude; 
 };

             
 in_map InMapDataFile : 
     external(ExtDataFile), 
     target_internal(IntDataFile) { 
     automatic { 
         MobileCall: internal(BaseInt), 
             target_internal(TIMobileCall); 
         DataPacket: internal(BaseInt), 
             target_internal(TIDataPacket); 
         Location: internal(BaseInt), 
             target_internal(TILocation); 
     }; 
 };

In this example, even though Location is not a part of the direct mapping of ExtDataFile itself, the type map information will still be considered when creating TIMobileCall.

use_external_names Automatic Option

When declaring a target_internal name for a large number of sub-formats the use_external_names option on the automatic block is a useful option. It will give all generated maps a target_internal name identical to the name of the external format.

Example - use_external_names option on the automatic block

in_map AMARecord_Map : external(AMARecord), 
                        target_internal(AMARecord) { 
    automatic { 
        RecordOwnerType : target_internal(RecordOwnerType); 
        RecordOwnerDN    : target_internal(RecordOwnerDN); 
        Package_100      : target_internal(Package_100); 
        Package_101      : target_internal(Package_101); 
        Package_102      : target_internal(Package_102); 
    }; 
 };

The use_external_names specification will ease the syntax by removing the need of all the target_internal specifications. The general syntax for a use_external_names declaration is as follows:

use_external_names(<external 1>, <external 2>, ...)

The previous example includes all of the specified external definitions within the file. Hence, the in_map could be rewritten as:


Example - in_map

in_map AMARecord_Map : external(AMARecord),
                       target_internal(AMARecord) {
   automatic : use_external_names;
};            

It is possible to combine this with automatic mapping specifications. In this case the explicit specifications will override the use_external_names behavior.

Automatic Block Internal Specification

It is also possible to append internal type specifications to the constructed in_maps:

Example - Internal type specifications

in_map AMARecord_Map : external(AMARecord), 
                        target_internal(AMARecord) { 
    automatic : use_external_names, internal(myInternal); 
 };

If automatic mapping specifications are in use, these will override the internal specifications on the automatic level (even if they only specify target_internal).