Kompatibilität mit Datum- und Zeitangaben

Kompatibilität mit Datum- und Zeitangaben#

TOML Werte können Datum- und Zeitangaben representieren und sind auch über die Build-Interfaces get_value und set_value zugänglich. Die interne Repräsentation eines Datum- und Zeitwertes kann zu anderen Bibliotheken inkompatibel sein kann. Dieses Rezept zeigt wie das Build-Interface erweitert werden kann, um andere Bibliotheken zu unterstützen.

datetime-fortran#

Die datetime-fortran-Bibliothek bietet ein opaques Objekt, das eine Datum- und Zeitangabe repräsentiert und verschiedene Funktionen zur Verarbeitung und Manipulation bereitstellt. Ein fpm-Projekt, das TOML-Fortran und datetime-fortran verwendet, kann mit dem folgenden Dependencies-Abschnitt im Manifest eingerichtet werden.

[dependencies]
toml-f.git = "https://github.com/toml-f/toml-f.git"
datetime.git = "https://github.com/wavebitscientific/datetime-fortran.git"

Um eine Kompatibilität zwischen den beiden abgeleiteten Typen zu definieren, erweitern wir die get_value und set_value generische Interfaces.

src/compat.f90#
!> Compatibility module to allow working with [[datetime]] objects and TOML data structures
module demo_compat
  use datetime_module, only : datetime
  use tomlf, only : toml_table, toml_array, toml_keyval, toml_key, toml_stat, toml_datetime, &
    & get_value, set_value, add_keyval, len
  implicit none
  private

  public :: get_value, set_value
  public :: assignment(=)

  !> Getter functions to manipulate TOML values
  interface get_value
    module procedure :: get_value_datetime_fortran
    module procedure :: get_child_value_datetime_fortran
    module procedure :: get_key_value_datetime_fortran
    module procedure :: get_elem_value_datetime_fortran
  end interface get_value

  !> Setter functions to manipulate TOML values
  interface set_value
    module procedure :: set_value_datetime_fortran
    module procedure :: set_child_value_datetime_fortran
    module procedure :: set_key_value_datetime_fortran
    module procedure :: set_elem_value_datetime_fortran
  end interface set_value

  !> Define assignment operation between [[toml_datatime]] and [[datetime]] objects
  interface assignment(=)
    module procedure :: convert_to_datetime
    module procedure :: convert_from_datetime
  end interface assignment(=)

contains

  !> Set TOML value to datetime
  subroutine set_value_datetime_fortran(self, val, stat, origin)
    !> Instance of the key-value pair
    class(toml_keyval), intent(inout) :: self
    !> Datetime value
    type(datetime), intent(in) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_datetime) :: tmp

    tmp = val
    call set_value(self, tmp, stat, origin)
  end subroutine set_value_datetime_fortran

  !> Set TOML value to datetime
  subroutine set_child_value_datetime_fortran(table, key, val, stat, origin)
    !> Instance of the TOML table
    class(toml_table), intent(inout) :: table
    !> Key in this TOML table
    character(*), intent(in) :: key
    !> Datetime value
    type(datetime), intent(in) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_keyval), pointer :: ptr

    call get_value(table, key, ptr, .true., stat, origin)

    if (associated(ptr)) then
      call set_value(ptr, val, stat, origin)
    else
      if (present(stat)) then
        if (stat == toml_stat%success) stat = toml_stat%fatal
      end if
    end if
  end subroutine set_child_value_datetime_fortran

  !> Set TOML value to datetime
  subroutine set_key_value_datetime_fortran(table, key, val, stat, origin)
    !> Instance of the TOML table
    class(toml_table), intent(inout) :: table
    !> Key in this TOML table
    type(toml_key), intent(in) :: key
    !> Datetime value
    type(datetime), intent(in) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    call set_value(table, key%key, val, stat, origin)
  end subroutine set_key_value_datetime_fortran

  !> Retrieve TOML value as datetime value
  subroutine set_elem_value_datetime_fortran(array, pos, val, stat, origin)
    !> Instance of the TOML array
    class(toml_array), intent(inout) :: array
    !> Position in the array
    integer, intent(in) :: pos
    !> Datetime value
    type(datetime), intent(in) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_keyval), pointer :: ptr

    call get_value(array, pos, ptr, stat, origin)

    if (.not.associated(ptr)) then
      if (pos == len(array) + 1) then
        call add_keyval(array, ptr, stat)
      end if
    end if

    if (associated(ptr)) then
      call set_value(ptr, val, stat, origin)
    else
      if (present(stat)) stat = toml_stat%fatal
    end if
  end subroutine set_elem_value_datetime_fortran

  !> Retrieve TOML value as datetime
  subroutine get_value_datetime_fortran(self, val, stat, origin)
    !> Instance of the key-value pair
    class(toml_keyval), intent(in) :: self
    !> Datetime value
    type(datetime), intent(out) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_datetime) :: tmp

    call get_value(self, tmp, stat, origin)
    val = tmp
  end subroutine get_value_datetime_fortran

  !> Retrieve TOML value as datetime
  subroutine get_child_value_datetime_fortran(table, key, val, default, stat, origin)
    !> Instance of the TOML table
    class(toml_table), intent(inout) :: table
    !> Key in this TOML table
    character(*), intent(in) :: key
    !> Datetime value
    type(datetime), intent(out) :: val
    !> Default datetime value
    type(datetime), intent(in), optional :: default
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_keyval), pointer :: ptr

    call get_value(table, key, ptr, present(default), stat, origin)

    if (associated(ptr)) then
      if (allocated(ptr%val)) then
        call get_value(ptr, val, stat, origin)
      else
        if (present(default)) then
          call set_value(ptr, default)
          call get_value(ptr, val, stat=stat)
        else
          if (present(stat)) stat = toml_stat%fatal
        end if
      end if
    end if
  end subroutine get_child_value_datetime_fortran

  !> Retrieve TOML value as datetime
  subroutine get_key_value_datetime_fortran(table, key, val, default, stat, origin)
    !> Instance of the TOML table
    class(toml_table), intent(inout) :: table
    !> Key in this TOML table
    type(toml_key), intent(in) :: key
    !> Datetime value
    type(datetime), intent(out) :: val
    !> Default datetime value
    type(datetime), intent(in), optional :: default
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    call get_value(table, key%key, val, default, stat, origin)
  end subroutine get_key_value_datetime_fortran

  !> Retrieve TOML value as datetime
  subroutine get_elem_value_datetime_fortran(array, pos, val, stat, origin)
    !> Instance of the TOML array
    class(toml_array), intent(inout) :: array
    !> Position in the array
    integer, intent(in) :: pos
    !> Integer value
    type(datetime), intent(out) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_keyval), pointer :: ptr

    call get_value(array, pos, ptr, stat, origin)

    if (associated(ptr)) then
      call get_value(ptr, val, stat, origin)
    else
      if (present(stat)) stat = toml_stat%fatal
    end if
  end subroutine get_elem_value_datetime_fortran

  !> Convert to a TOML representation of a datetime object
  elemental subroutine convert_to_datetime(lhs, rhs)
    !> TOML representation of datetime
    type(toml_datetime), intent(out) :: lhs
    !> Datetime-fortran representation of datetime
    type(datetime), intent(in) :: rhs

    lhs%date%year = rhs%getYear()
    lhs%date%month = rhs%getMonth()
    lhs%date%day = rhs%getDay()
    lhs%time%hour = rhs%getHour()
    lhs%time%minute = rhs%getMinute()
    lhs%time%second = rhs%getSecond()
    lhs%time%msec = rhs%getMillisecond() * 1000
  end subroutine convert_to_datetime

  !> Convert from a TOML representation of a datetime object
  elemental subroutine convert_from_datetime(lhs, rhs)
    !> Datetime-fortran representation of datetime
    type(datetime), intent(out) :: lhs
    !> TOML representation of datetime
    type(toml_datetime), intent(in) :: rhs

    integer, allocatable :: year, month, day, hour, minute, second, millisecond

    if (rhs%date%year > -1) year = rhs%date%year
    if (rhs%date%month > -1) month = rhs%date%month
    if (rhs%date%day > -1) day = rhs%date%day
    if (rhs%time%hour > -1) hour = rhs%time%hour
    if (rhs%time%minute > -1) minute = rhs%time%minute
    if (rhs%time%second > -1) second = rhs%time%second
    if (rhs%time%msec > -1) millisecond = rhs%time%msec / 1000

    lhs = datetime(year=year, month=month, day=day, hour=hour, minute=minute, &
      & second=second, millisecond=millisecond)
  end subroutine convert_from_datetime

end module demo_compat

M_time#

Die M_time-Bibliothek bietet ein transparentes Objekt, das eine Datum- und Zeitangabe repräsentiert, mit einem reichhaltigen Funktions- und Objektorientierten API zur Inspektion und Manipulation. Ein fpm-Projekt, das TOML-Fortran und M_time verwendet, kann mit dem folgenden Dependencies-Abschnitt im Manifest eingerichtet werden.

[dependencies]
toml-f.git = "https://github.com/toml-f/toml-f.git"
M_time.git = "https://github.com/urbanjost/M_time.git"

Um eine Kompatibilität zwischen den beiden abgeleiteten Typen zu definieren, erweitern wir die get_value und set_value generische Interfaces.

src/compat.f90#
!> Compatibility module to allow working with [[date_time]] objects and TOML data structures
module demo_compat
  use m_time_oop, only : date_time
  use tomlf, only : toml_table, toml_array, toml_keyval, toml_key, toml_stat, toml_datetime, &
    & get_value, set_value, add_keyval, len
  implicit none
  private

  public :: get_value, set_value
  public :: assignment(=)

  !> Getter functions to manipulate TOML values
  interface get_value
    module procedure :: get_value_datetime_m_time
    module procedure :: get_child_value_datetime_m_time
    module procedure :: get_key_value_datetime_m_time
    module procedure :: get_elem_value_datetime_m_time
  end interface get_value

  !> Setter functions to manipulate TOML values
  interface set_value
    module procedure :: set_value_datetime_m_time
    module procedure :: set_child_value_datetime_m_time
    module procedure :: set_key_value_datetime_m_time
    module procedure :: set_elem_value_datetime_m_time
  end interface set_value

  !> Define assignment operation between [[toml_datatime]] and M_time [[date_time]] objects
  interface assignment(=)
    module procedure :: convert_to_datetime
    module procedure :: convert_from_datetime
  end interface assignment(=)

contains

  !> Set TOML value to datetime
  subroutine set_value_datetime_m_time(self, val, stat, origin)
    !> Instance of the key-value pair
    class(toml_keyval), intent(inout) :: self
    !> Datetime value
    type(date_time), intent(in) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_datetime) :: tmp

    tmp = val
    call set_value(self, tmp, stat, origin)
  end subroutine set_value_datetime_m_time

  !> Set TOML value to datetime
  subroutine set_child_value_datetime_m_time(table, key, val, stat, origin)
    !> Instance of the TOML table
    class(toml_table), intent(inout) :: table
    !> Key in this TOML table
    character(*), intent(in) :: key
    !> Datetime value
    type(date_time), intent(in) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_keyval), pointer :: ptr

    call get_value(table, key, ptr, .true., stat, origin)

    if (associated(ptr)) then
      call set_value(ptr, val, stat, origin)
    else
      if (present(stat)) then
        if (stat == toml_stat%success) stat = toml_stat%fatal
      end if
    end if
  end subroutine set_child_value_datetime_m_time

  !> Set TOML value to datetime
  subroutine set_key_value_datetime_m_time(table, key, val, stat, origin)
    !> Instance of the TOML table
    class(toml_table), intent(inout) :: table
    !> Key in this TOML table
    type(toml_key), intent(in) :: key
    !> Datetime value
    type(date_time), intent(in) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    call set_value(table, key%key, val, stat, origin)
  end subroutine set_key_value_datetime_m_time

  !> Retrieve TOML value as datetime value
  subroutine set_elem_value_datetime_m_time(array, pos, val, stat, origin)
    !> Instance of the TOML array
    class(toml_array), intent(inout) :: array
    !> Position in the array
    integer, intent(in) :: pos
    !> Datetime value
    type(date_time), intent(in) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_keyval), pointer :: ptr

    call get_value(array, pos, ptr, stat, origin)

    if (.not.associated(ptr)) then
      if (pos == len(array) + 1) then
        call add_keyval(array, ptr, stat)
      end if
    end if

    if (associated(ptr)) then
      call set_value(ptr, val, stat, origin)
    else
      if (present(stat)) stat = toml_stat%fatal
    end if
  end subroutine set_elem_value_datetime_m_time

  !> Retrieve TOML value as datetime
  subroutine get_value_datetime_m_time(self, val, stat, origin)
    !> Instance of the key-value pair
    class(toml_keyval), intent(in) :: self
    !> Datetime value
    type(date_time), intent(out) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_datetime) :: tmp

    call get_value(self, tmp, stat, origin)
    val = tmp
  end subroutine get_value_datetime_m_time

  !> Retrieve TOML value as datetime
  subroutine get_child_value_datetime_m_time(table, key, val, default, stat, origin)
    !> Instance of the TOML table
    class(toml_table), intent(inout) :: table
    !> Key in this TOML table
    character(*), intent(in) :: key
    !> Datetime value
    type(date_time), intent(out) :: val
    !> Default datetime value
    type(date_time), intent(in), optional :: default
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_keyval), pointer :: ptr

    call get_value(table, key, ptr, present(default), stat, origin)

    if (associated(ptr)) then
      if (allocated(ptr%val)) then
        call get_value(ptr, val, stat, origin)
      else
        if (present(default)) then
          call set_value(ptr, default)
          call get_value(ptr, val, stat=stat)
        else
          if (present(stat)) stat = toml_stat%fatal
        end if
      end if
    end if
  end subroutine get_child_value_datetime_m_time

  !> Retrieve TOML value as datetime
  subroutine get_key_value_datetime_m_time(table, key, val, default, stat, origin)
    !> Instance of the TOML table
    class(toml_table), intent(inout) :: table
    !> Key in this TOML table
    type(toml_key), intent(in) :: key
    !> Datetime value
    type(date_time), intent(out) :: val
    !> Default datetime value
    type(date_time), intent(in), optional :: default
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    call get_value(table, key%key, val, default, stat, origin)
  end subroutine get_key_value_datetime_m_time

  !> Retrieve TOML value as datetime
  subroutine get_elem_value_datetime_m_time(array, pos, val, stat, origin)
    !> Instance of the TOML array
    class(toml_array), intent(inout) :: array
    !> Position in the array
    integer, intent(in) :: pos
    !> Integer value
    type(date_time), intent(out) :: val
    !> Status of operation
    integer, intent(out), optional :: stat
    !> Origin in the data structure
    integer, intent(out), optional :: origin

    type(toml_keyval), pointer :: ptr

    call get_value(array, pos, ptr, stat, origin)

    if (associated(ptr)) then
      call get_value(ptr, val, stat, origin)
    else
      if (present(stat)) stat = toml_stat%fatal
    end if
  end subroutine get_elem_value_datetime_m_time

  !> Convert to a TOML representation of a datetime object
  elemental subroutine convert_to_datetime(lhs, rhs)
    !> TOML representation of datetime
    type(toml_datetime), intent(out) :: lhs
    !> M_time representation of datetime
    type(date_time), intent(in) :: rhs

    lhs%date%year = rhs%year
    lhs%date%month = rhs%month
    lhs%date%day = rhs%day
    lhs%time%hour = rhs%hour
    lhs%time%minute = rhs%minute
    lhs%time%second = rhs%second
    lhs%time%msec = rhs%millisecond * 1000
  end subroutine convert_to_datetime

  !> Convert from a TOML representation of a datetime object
  elemental subroutine convert_from_datetime(lhs, rhs)
    !> M_time representation of datetime
    type(date_time), intent(out) :: lhs
    !> TOML representation of datetime
    type(toml_datetime), intent(in) :: rhs

    if (rhs%date%year > -1) lhs%year = rhs%date%year
    if (rhs%date%month > -1) lhs%month = rhs%date%month
    if (rhs%date%day > -1) lhs%day = rhs%date%day
    if (rhs%time%hour > -1) lhs%hour = rhs%time%hour
    if (rhs%time%minute > -1) lhs%minute = rhs%time%minute
    if (rhs%time%second > -1) lhs%second = rhs%time%second
    if (rhs%time%msec > -1) lhs%millisecond = rhs%time%msec / 1000
  end subroutine convert_from_datetime

end module demo_compat