.. Mars Documentation
Copyright (C) 2010 Matt Giuca
.. This program 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, either version 3 of the License, or
(at your option) any later version.
.. This program 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 this program. If not, see .
:mod:`native` --- Native interface functions
============================================
.. sectionauthor:: Matt Giuca
.. moduleauthor:: Matt Giuca
.. module:: native
:synopsis: Provides functions which offer a low-level interface for the
purpose of marshalling data between Mars and foreign (native)
code.
This module provides functions which offer a low-level interface for the
purpose of marshalling data between Mars and foreign (native) code. These
functions provide conversions between the regular :type:`Num` and foreign
:type:`CInt` types, as well as pointer allocation, manipulation, and
dereferencing.
.. warning::
Mars is, fundamentally, a pure language. This means that no function can
modify an existing value or global state, only return a value (and perform
input/output, which while technically impure, isn't considered "impure" in
Mars).
The functions in this module break that purity by providing direct access
to memory via pointers. They can also be used to crash the program or
violate type constraints. They should not be considered part of the
language semantics, and are not intended to be used by most code. They are
provided to allow compatibility with code written in other languages. Use
at your own risk.
Conversion functions
--------------------
These functions convert back and forth between :type:`Num` and each of the
native types. The conversions from :type:`Num` raise an error if the value is
out of range of the target type. The integral types have separate signed and
unsigned conversion functions.
.. function:: num_cschar(value :: Num) :: CChar
Converts a :type:`Num` to a signed :type:`CChar`. It is an error if *value*
is not an integer in the range [-128, 127].
.. function:: cschar_num(value :: CChar) :: Num
Converts a signed :type:`CChar` to a :type:`Num`.
.. function:: num_cuchar(value :: Num) :: CChar
Converts a :type:`Num` to an unsigned :type:`CChar`. It is an error if
*value* is not an integer in the range [0, 255].
.. function:: cuchar_num(value :: CChar) :: Num
Converts an unsigned :type:`CChar` to a :type:`Num`.
.. function:: num_csshort(value :: Num) :: CShort
Converts a :type:`Num` to a signed :type:`CShort`. It is an error if
*value* is not an integer in the range [-32768, 32767].
.. function:: csshort_num(value :: CShort) :: Num
Converts a signed :type:`CShort` to a :type:`Num`.
.. function:: num_cushort(value :: Num) :: CShort
Converts a :type:`Num` to an unsigned :type:`CShort`. It is an error if
*value* is not an integer in the range [0, 65535].
.. function:: cushort_num(value :: CShort) :: Num
Converts an unsigned :type:`CShort` to a :type:`Num`.
.. function:: num_csint(value :: Num) :: CInt
Converts a :type:`Num` to a signed :type:`CInt`. It is an error if *value*
is not an integer that can be represented in :const:`sizeof_cint` bytes.
.. function:: csint_num(value :: CInt) :: Num
Converts a signed :type:`CInt` to a :type:`Num`.
.. warning::
If the value's magnitude is greater than 2^53, this may result in
rounding errors. (This is only a possibility if :const:`sizeof_cint` >=
7.)
.. function:: num_cuint(value :: Num) :: CInt
Converts a :type:`Num` to an unsigned :type:`CInt`. It is an error if
*value* is not a positive integer that can be represented in
:const:`sizeof_cint` bytes.
.. function:: cuint_num(value :: CInt) :: Num
Converts an unsigned :type:`CInt` to a :type:`Num`.
.. warning::
If the value's magnitude is greater than 2^53, this may result in
rounding errors. (This is only a possibility if :const:`sizeof_cint` >=
7.)
.. function:: num_cfloat(value :: Num) :: CFloat
Converts a :type:`Num` to a :type:`CFloat`.
.. warning::
This may result in rounding errors. Furthermore, values too large to be
represented in a single-precision float will be rounded to negative or
positive infinity.
.. function:: cfloat_num(value :: CFloat) :: Num
Converts a :type:`CFloat` to a :type:`Num`.
.. function:: num_cdouble(value :: Num) :: CDouble
Converts a :type:`Num` to a :type:`CDouble`.
.. function:: cdouble_num(value :: CDouble) :: Num
Converts a :type:`CDouble` to a :type:`Num`.
.. function:: num_cptr(value :: Num) :: CPtr
Converts a :type:`Num` to a :type:`CPtr`. It is an error if *value* is not
a positive integer that can be represented in :const:`sizeof_cptr` bytes.
.. note::
This can be used to fabricate a pointer at any address. This is almost
never a good idea. Pointers should usually be created using
:func:`malloc`, and the null pointer can be obtained with
:const:`nullptr`. Be aware that :type:`Num` cannot precisely represent
all possible pointer values on a 64-bit system.
.. function:: cptr_num(value :: CPtr) :: Num
Converts a :type:`CPtr` to a :type:`Num`.
.. warning::
On a 64-bit system, this may result in rounding errors. Therefore, this
function should generally be avoided. Never attempt to pass the result
of this function back to :func:`num_cptr`, because the rounding error
may alter the pointer's address. Pointer arithmetic should be performed
using :func:`cptr_add` and :func:`cptr_diff` instead.
Size constants
--------------
These constants get the size, in bytes, of each native type. This is
equivalent to the ``sizeof`` operator in C. These should be used with
:func:`malloc` to determine how much memory to allocate for a native value or
an array of them. These should also be used with :func:`cptr_add` when
indexing into an array.
.. constant:: sizeof_cchar :: Num
The number of bytes of memory used by a :type:`CChar`. This is always 1.
This is equivalent to the C expression ``sizeof(char)``.
.. constant:: sizeof_cshort :: Num
The number of bytes of memory used by a :type:`CChar`. This is 2 on all
supported platforms. This is equivalent to the C expression
``sizeof(short)``.
.. constant:: sizeof_cint :: Num
The number of bytes of memory used by a :type:`CInt`. This is typically 4,
on both 32-bit and 64-bit machines. This is equivalent to the C expression
``sizeof(int)``.
.. constant:: sizeof_cfloat :: Num
The number of bytes of memory used by a :type:`CFloat`. This is 4 on all
supported platforms. This is equivalent to the C expression
``sizeof(float)``.
.. constant:: sizeof_cdouble :: Num
The number of bytes of memory used by a :type:`CDouble`. This is 8 on all
supported platforms. This is equivalent to the C expression
``sizeof(double)``.
.. constant:: sizeof_cptr :: Num
The number of bytes of memory used by a :type:`CPtr`. On 32-bit machines,
this will be 4. On 64-bit machines, this will be 8. This is equivalent to
the C expression ``sizeof(void*)``.
Pointer arithmetic functions
----------------------------
These functions directly manipulate pointers, without having to convert back
and forth to :type:`Num`.
.. function:: cptr_add(pointer :: CPtr, offset :: Num) :: CPtr
Adds *offset* bytes to *pointer* and returns the result. The *offset* may
be a negative number. It is an error if *offset* is not a whole number. If
the result is less than 0 or larger than the maximum pointer value,
behaviour is undefined (typically wraps).
This is the preferred way to perform pointer arithmetic, such as when
indexing into arrays. This is equivalent to the C expression ``(char*)
pointer + offset``.
.. note::
This is different from pointer arithmetic in C, which offsets the
pointer by *offset* multiplied by the size of the pointed-to type. In
order to index into a native array in Mars, the index must be manually
multiplied by the size of the type. For example, if *p* points to an
array of floats, element *i* is addressed as ``cptr_add(p, i *
sizeof_cfloat)``.
.. function:: cptr_diff(x :: CPtr, y :: CPtr) :: Num
Subtracts the pointer *y* from the pointer *x*, returning the difference
between them in bytes. This is equivalent to the C expression ``(char*) x -
(char*) y``.
.. warning::
On a 64-bit system, this may result in rounding errors if *x* and *y*
are sufficiently far apart. Therefore, this function should only be used
when *x* and *y* are known to be pointers to the same contiguously
allocated block.
Manual memory management functions
----------------------------------
.. function:: malloc(size :: Num) :: CPtr
As with the :func:`malloc` function in the C standard library, allocates
*size* bytes of memory and returns a pointer to that memory. The memory
will be uninitialised.
A runtime error is triggered if the program is out of memory when
:func:`malloc` is called; this function never returns :const:`nullptr`.
Memory allocated by :func:`malloc` cannot be used by regular Mars code, but
it can be manipulated by other functions in the :mod:`native` module, as
well as being passed to functions written in other languages (which is why
it is provided).
There is no corresponding :func:`free` function. As Mars currently uses the
Boehm garbage collector, memory allocated with :func:`malloc` should
automatically be freed when it is no longer in use.
Pointer dereferencing functions
-------------------------------
These functions read or write values pointed to by a pointer. There is a
separate pair of functions for dereferencing pointers to each native type.
In all of these functions, behaviour is undefined if *pointer* is not a valid
memory address.
.. function:: ccharptr_ref(pointer :: CPtr) :: CChar
Read a :type:`CChar` value from the memory location *pointer*. This is
equivalent to the C expression ``*((char*) pointer)``.
.. function:: ccharptr_set(pointer :: CPtr, value :: CChar) :: CPtr
Write a :type:`CChar` value to the memory location *pointer*. This is
equivalent to the C expression ``*((char*) pointer) = value, pointer``.
.. function:: cshortptr_ref(pointer :: CPtr) :: CShort
Read a :type:`CShort` value from the memory location *pointer*. This is
equivalent to the C expression ``*((short*) pointer)``.
.. function:: cshortptr_set(pointer :: CPtr, value :: CShort) :: CPtr
Write a :type:`CShort` value to the memory location *pointer*. This is
equivalent to the C expression ``*((short*) pointer) = value, pointer``.
.. function:: cintptr_ref(pointer :: CPtr) :: CInt
Read a :type:`CInt` value from the memory location *pointer*. This is
equivalent to the C expression ``*((int*) pointer)``.
.. function:: cintptr_set(pointer :: CPtr, value :: CInt) :: CPtr
Write a :type:`CInt` value to the memory location *pointer*. This is
equivalent to the C expression ``*((int*) pointer) = value, pointer``.
.. function:: cfloatptr_ref(pointer :: CPtr) :: CFloat
Read a :type:`CFloat` value from the memory location *pointer*. This is
equivalent to the C expression ``*((float*) pointer)``.
.. function:: cfloatptr_set(pointer :: CPtr, value :: CFloat) :: CPtr
Write a :type:`CFloat` value to the memory location *pointer*. This is
equivalent to the C expression ``*((float*) pointer) = value, pointer``.
.. function:: cdoubleptr_ref(pointer :: CPtr) :: CDouble
Read a :type:`CDouble` value from the memory location *pointer*. This is
equivalent to the C expression ``*((double*) pointer)``.
.. function:: cdoubleptr_set(pointer :: CPtr, value :: CDouble) :: CPtr
Write a :type:`CDouble` value to the memory location *pointer*. This is
equivalent to the C expression ``*((double*) pointer) = value, pointer``.
.. function:: cptrptr_ref(pointer :: CPtr) :: CPtr
Read a :type:`CPtr` value from the memory location *pointer*. This is
equivalent to the C expression ``*((void**) pointer)``.
.. function:: cptrptr_set(pointer :: CPtr, value :: CPtr) :: CPtr
Write a :type:`CPtr` value to the memory location *pointer*. This is
equivalent to the C expression ``*((void**) pointer) = value, pointer``.
Utility constants and functions
-------------------------------
These functions and constants are written in pure Mars, and their use is
optional. However, they are helpful in dealing with converting data between
Mars and C.
.. constant:: nullptr :: CPtr
The :type:`CPtr` value 0 (``num_cptr(0)``). This is equivalent to the C
expression ``NULL``.
.. constant:: nullbyte :: CChar
The :type:`CChar` value 0 (``num_cuchar('\0')``). This is equivalent to the
C expression ``'\0'``.
.. function:: string_cptr(string :: Array(Num)) :: CPtr
Converts a Mars string into a C string (a pointer to a contiguous array of
bytes, terminated with the byte value 0). This allocates sufficient memory
for the C string using :func:`malloc`, and copies each value into a single
byte of the buffer, also writing the 0 byte at the end. Returns a pointer
to the allocated C string.
It is an error if any element of *string* is non-integral or outside the
range [0, 255].
This returns a new pointer value every time it is called, even if given the
same input.
.. warning::
If any element of the string is 0, it will be copied into the buffer
without error, which will cause any code which expects a null-terminated
string to consider the first 0 byte to be the end of the string. This
can potentially cause security vulnerabilities.
.. function:: cptr_string(cstr :: CPtr) :: Array(Num)
Converts a C string (a pointer to a contiguous array of bytes, terminated
with the byte value 0) into a Mars string. The bytes in the array *cstr*
are read one after another, and copied into a Mars array until a 0 byte is
detected. The 0 byte is not copied into the Mars array.
Behaviour is undefined if *cstr* is not a valid pointer, or if it does not
contain a 0 byte anywhere in its allocated length. :func:`cptr_string` will
keep reading bytes until it detects a 0 byte.