Skip to content

Quickstart

Kelly Schultz edited this page Jul 4, 2023 · 6 revisions

fortran-messagepack

This library exposes MessagePack utilities with OOP via a single module called messagepack. This module relies upon iso_fortran_env and ieee_arithmetic. Interaction with the library is done with the msgpack class.

program test
    use messagepack
    implicit none

    class(msgpack), allocatable :: mp

    mp = msgpack()
end program

An abstract base class called mp_value_type is used to represent MessagePack data. A pointer type called mp_value_type_ptr is used to support the "container-like" formats that contain other MessagePack values. The following derived types are exposed to the user:

Derived Type MessagePack Format Family Associated Fortran Types
mp_nil_type nil -
mp_bool_type bool logical
mp_int_type int integer(kind=int64)
mp_float_type float real(kind=real32), real(kind=real64)
mp_str_type str character(:)
mp_bin_type bin byte, dimension(:)
mp_arr_type array mp_value_type_ptr
mp_map_type map mp_value_type_ptr, mp_value_type_ptr
mp_ext_type ext byte, dimension(:)
mp_timestamp_type ext built-in -

Data that is unpacked with be stored with these classes, and data that is to be packed must be assembled with these classes.

Unpacking

msgpack expects that serialized data will be passed into it as a byte array. There is one note here that users need to keep in mind: fortran does not support unsigned integers, and large portions of the MessagePack spec utilize unsigned integers. We'll get back to that later, but when printing serialized messagepack data to the console, use the provided print_bytes_as_hex function to print the data as unsigned hex values.

subroutine print_bytes_as_hex(bytes, addhexmark)
    ! prints a buffer of bytes as the unsigned hex version
    ! @param[in] bytes - byte buffer to print
    ! @param[in] addhexmark - If true, print with 0x prepended
    byte, dimension(:), allocatable, intent(in) :: bytes
    logical, intent(in) :: addhexmark

Produces something like this:

[ 0x85 0xA3 0x72 0x61 0x74 0x05 ...

msgpack attemps to handle this under the hood, but in certain cases requires the user to intervene.

Simple unpack

Unpacking messagepack from a known set of data and print it to the console.

program test
    use messagepack
    intrinsic none

    class(msgpack), allocatable :: mp
    class(mp_value_type), allocatable :: mpv
    bytes, dimension(:), allocatable :: buffer

    ! known messagepack
    allocate(buffer(19))
    buffer = (/-127,-93,109,115,103,-109,-91,104,101,108,108,111,-91,119,111,114,108,100,3/)
    call print_bytes_as_hex(buffer, .true.)

    mp = msgpack()
    call mp%unpack(buffer, mpv)
    if (mp%failed()) then
        print *, mp%error_message
        stop 1
    endif()

    call mp%print_value(mpv) ! pretty print the messagepack object to console
end program

this will output to the console:

[ 0x81 0xA3 0x6D 0x73 0x67 0x93 0xA5 0x68 0x65 0x6C 0x6C 0x6F 0xA5 0x77 0x6F 0x72 0x6C 0x64 0x03  ]
{
  "msg" => ["hello", "world", 3, ] ,
},

Basic Packing

Example: assemble an array of various values and serialize it. The class used to support this is mp_arr_type:

type, extends(mp_value_type) :: mp_arr_type
        class(mp_value_type_ptr), allocatable, dimension(:) :: value
...

This class uses the mp_value_type_ptr class, which is defined as so:

type :: mp_value_type_ptr
    class(mp_value_type), allocatable :: obj
end type

The constructor for mp_arr_type takes in an integer parameter representing the number of values that it needs to contain. To see this in action, follow the example program below:

program test
    use iso_fortran_env
    use messagepack
    intrinsic none

    class(msgpack), allocatable :: mp
    class(mp_arr_type), allocatable :: mp_arr
    bytes, dimension(:), allocatable :: buffer

    mp = msgpack()

    mp_arr = mp_arr_type(5) ! an array of 5 elements
    mp_arr%value(1)%obj = mp_bool_type(.true.)
    mp_arr%value(2)%obj = mp_str_type("hello world")
    mp_arr%value(3)%obj = mp_int_type(3500)
    mp_arr%value(4)%obj = mp_nil_type()
    mp_arr%value(5)%obj = mp_int_type(-4)

    call mp%pack_alloc(mp_arr, buffer)
    if (mp%failed()) then
        print *, mp%error_message
        stop 1
    end if
    call print_bytes_as_hex(buffer, .true.)
end program

This program will (should) output the following to the console:

[ 0x95 0xC3 0xAB 0x68 0x65 0x6C 0x6C 0x6F 0x20 0x77 0x6F 0x72 0x6C 0x64 0xCD 0x0D 0xAC 0xC0 0xF5 ]

Pass this into a free messagepack to json convert (like this one to try this out yourself!

Complications

Unsigned integers

Fortran does not natively support unsigned integers. The library has utilities to deal with this and make the conversion largely transparent, TODO

128 bit integers

...

Clone this wiki locally