Fuzion Logo
fuzion-lang.dev — The Fuzion Language Portal
JavaScript seems to be disabled. Functionality is limited.

io/file/open.fz


# This file is part of the Fuzion language implementation.
#
# The Fuzion language implementation is free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License as published
# by the Free Software Foundation, version 3 of the License.
#
# The Fuzion language implementation is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License along with The
# Fuzion language implementation.  If not, see <https://www.gnu.org/licenses/>.


# -----------------------------------------------------------------------
#
#  Tokiwa Software GmbH, Germany
#
#  Source code of Fuzion standard library feature io.file.open
#
# -----------------------------------------------------------------------


# effect for manipulating open files
# T is used to distinguish several open files
#
module:public open(public T type,
                   private fd i64,
                   public file_name String) : simple_effect is

  # writes the content of an array of bytes to a file opened as fd
  #
  # this might overwrite parts or all of an existing file.
  #
  public write(content Sequence u8) ! io.file.write =>
    io.file.write.write fd content.as_array


  # reads all bytes from the file in the path
  # returns outcome array u8, a byte array representing the content of the file if the operation was successful
  # returns an error in case the operation fails
  #
  public read outcome (array u8) ! io.file.read =>
    io.file.read.read_file fd


  # seek in file
  #
  public seek(
       # the offset to seek from the beginning of the stream pointer
       offset i64) =>
    io.file.seek.seek fd offset


  # get the current byte position in the file
  #
  public file_position =>
    io.file.seek.file_position fd


  # install mmap effect an run code
  #
  # note: the offset must be a multiple of the pagesize which usually is 4096, windows 65536?
  # note: offset+size must not exceed size of file
  #
  # example usage:
  # _ := io.file.use unit "/some_file" io.file.mode.append ()->
  #   io.file.open.mmap (i64 0) (i64 100) ()->
  #     io.file.open.mmap[99] := 42
  #
  public mmap(R type, offset i64, size i64, code mapped_buffer->R) outcome R
  pre offset % 4096 = 0 # NYI get real page size instead of 4096.
  =>

    arr := fuzion.sys.internal_array_init i32 1
    mapped_memory := fuzion.sys.fileio.mmap fd offset size arr.data
    res := arr.as_array

    if res[0] = -1
      error "mmap failed"
    else
      r := code (mapped_buffer mapped_memory size)

      if fuzion.sys.fileio.munmap mapped_memory size = 0
        r
      else
        error "error closing the memory mapped file"


  # get a byte from a given mapped buffer
  #
  module mapped_buffer_get(memory fuzion.sys.Pointer, i i64) =>
    open.this.env.replace
    fuzion.sys.fileio.mapped_buffer_get memory i

  # set a byte of a given mapped buffer
  #
  module mapped_buffer_set(memory fuzion.sys.Pointer, i i64, o u8) =>
    open.this.env.replace
    fuzion.sys.fileio.mapped_buffer_set memory i o


  # mapped buffer gives access to the memory region a file is mapped
  # to via `mmap`.
  #
  module:public mapped_buffer
    (# internal pointer to the mapped memory
     private memory fuzion.sys.Pointer,

     # the length of this buffer
     public length i64
    )
    : container.Buffer u8 (io.file.open T) is


    # get byte at given index i
    #
    public index [ ] (i i64) u8 ! open T
      pre
        safety: i64 0 ≤ i < length
    =>
      mapped_buffer_get memory i


    # set byte at given index i to given value o
    #
    public set [ ] (i i64, o u8) unit ! io.file.open T
      pre
        safety: i64 0 ≤ i < length
    =>
      mapped_buffer_set memory i o



# short hand to get the currently
# installed open effect
# for type T from the environment.
# see `use` on how to use this.
#
public open(T type) =>
  (open T).env


# unit type used internally by open- and use-
# short hands which can be used when one does not need
# to distinguish between several open files.
private:public open_unique_type is



# short hand to get the currently
# installed open effect
# from the environment.
# see `use` on how to use this.
#
public open =>
  (open open_unique_type).env