Search code examples
pythondlld

Using a DLL exported from D


I've created a simple encryption program in D, and I had the idea to make a DLL from it and try to import it to, for example, Python.

I've could simply call my main function, becouse it dosn't need any params. But when I get to my encrytion method, it uses dynamic-lenght ubyte[] arrays, but as far as I know, they don't exist in other C/C++ based langs.

For example, there's the first line of one of my funcs:
ubyte[] encode(ubyte[] data, ubyte[] key){

But I can't use an array without fixed lenght in other languages! How can I import that function, for example, in Python?

EDIT:

I know that I can create a wrapper that takes a pointer and the lenght of the array, but isn't there a more elegant solution?
(Where I don't need to use D to use a lib written in D)


Solution

  • Well tbh. there's no real elegant way other than wrapping a pointer with a length or wrapping to C arrays and then to D.

    However you can make a somewhat elegant purpose with the first way using a struct that has a pointer, a length and a property that converts it to a D array.

    Then the function you export takes your struct, all that function should do is call an internal function that takes an actual D array and you'd simply pass the array to it and the conversion would happen at that moment through alias this and the conversion property.

    An example usage is here: module main;

    import core.stdc.stdlib : malloc;
    
    import std.stdio;
    
    struct DArray(T) {
        T* data;
        size_t length;
        /// This field can be removed, only used for testing purpose
        size_t offset;
    
        @property T[] array() {
            T[] arr;
    
            foreach(i; 0 .. length) {
                arr ~= data[i];
            }
    
            return arr;
        }
    
        alias array this;
    
        /// This function can be removed, only used for testing purpose
        void init(size_t size) {
            data = cast(T*)malloc(size * T.sizeof);
            length = size;
        }
    
        /// This function can be removed, only used for testing purpose
        void append(T value) {
            data[offset] = value;
    
            offset++;
        }
    }
    
    // This function is the one exported
    void externalFoo(DArray!int intArray) {
        writeln("Calling extern foo");
    
        internalFoo(intArray);
    }
    
    // This function is the one you use
    private void internalFoo(int[] intArray) {
        writeln("Calling internal foo");
    
        writeln(intArray);
    }
    
    
    void main() {
        // Constructing our test array
        DArray!int arrayTest;
        arrayTest.init(10);
    
        foreach (int i; 0 .. 10) {
            arrayTest.append(i);
        }
    
        // Testing the exported function 
        externalFoo(arrayTest);
    }
    

    Here is an absolute minimum version of how to do it

    struct DArray(T) {
        T* data;
        size_t length;
    
        @property T[] array() {
            T[] arr;
    
            foreach(i; 0 .. length) {
                arr ~= data[i];
            }
    
            return arr;
        }
    
        alias array this;
    
    }
    
    // This function is the one exported
    void externalFoo(DArray!int intArray) {
        writeln("Calling extern foo");
    
        internalFoo(intArray);
    }
    
    // This function is the one you use
    private void internalFoo(int[] intArray) {
        writeln("Calling internal foo");
    
        writeln(intArray);
    }