Given a C-type pointer p to a C-struct and the equivalent Julia struct with the same memory layout T, provide read and write access to the fields. T must be a bits type.

Example: struct T <: Layout a::Cint b::Cdouble end

a = Vector{UInt8}(undef, 100) p = pointer(a) # usually the data are coming from C cs = CStruct{T}(p)

cs.a = 1234 cs.b = 3.5


Abstract vector type for julia objects used to access elements of C-vectors, which are based by plain C memory. Memory layout is described by Layout structs.


Denote a variable length vector with element type T in a template. F is a function, which calculates the length of the vector, given the accessor object containing the vector.

Example: struct A <: Layout len::Int vec::NVarVector{Float64, (x) -> x.len} end



All structs used to describe the memory layout (of a C-data structure) need to be subtypes of this. Some controlling objects used in such templates to describe vectors and pointers have also this type. A Layout structure and a memory pointer are needed to construct an CAccessor object.


get the internal fields of accessors

Cserialize(::Type{T}, source::Any)

Convert the julia object source into a byte vector to be used in C. The process is controlled by the layout type recursively.

The resulting vector contains only data described in T. The field, vector element or bit data required by T are taken from source if available in a corresponding part. Other data are filled with 0-bytes.

If T is a structure, corresponding fields in source are by the same name. If T is a vector, corresponding elements in source are by the same index. If T is a Ptr{S}, the space for a pointer is reserved and filled with the offset integer (of same size), while the S object is appended at the end of the serialization stream.

Finally all offset integers are replaced by actual pointers.

ensure!(buf::Vector, off, size)

Ensure that the size of buf is at least off + size by maybe resizing buf. Added space is filled with zero bytes.


For bits types simply load value, convert to Julia accessor if required. For struct types, create CStruct accessor. For vector types, create CVector accessor.


Has the layout described by type a variable size (for example variable sized vector in last field of a struct)?

pointer_for_field(cs::CStruct{T}, fieldname) where T

For cs return pointer to member field fieldname. The pointer has type Ptr{fieldtype(T, i)} with i the number of the field within struct type T.

p = pointer(a::Vector{T})::Ptr{T}

return pointer to a[1]. The existence of the resulting Ptr will not protect the object from garbage collection, so you must ensure that the object remains referenced for the whole time that the Ptr will be used. The condition a[i] === unsafe_load(p, i) is usually true. Given p it is possible to access arbitrary bits data by byte offset and type S using unsafe_load(Ptr{S}(p + offset)).

This function is mainly used to simulate a C memory in the data area of vector a.

pushall!(relocs::Vector{Int}, ctx::Vector{Tuple}, offset, Type, value}

push! the offset to relocs and the tuple (offset, Type, value) in ctx. The relocs are finally used to replace offset values by pointers. The ctx is used push back processing for later serializing.

relocate!(buffer::Vector, offsets)

In vector buffer, at the byte offsets stored in offsets, offset values (into buffer) are stored as Int values. The are replaced by Ptr values into the data area of buffer.

It is essential, that the data area is not changed after this process, that means no resize!, push!, etc. are allowed after this final fix of pointer values to be used in C-calls.

set_at_pointer(:Ptr, value)

Convert to C primitive or composed object. Store bytes at memory position.