.. 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.