Hi there! I'm a longtime C developer and I'm brand new to Nim. I'm attempting to get a sequence of objects from Nim from inside my C program. I have two problems: First, the code below doesn't work. While I can get a single object just fine and that works as expected, I'm unable to get a sequence of objects, nor can I find any documentation on how to do this correctly. Second, I'm pretty sure I need to tell...something...here about when Nim is allowed to garbage collect this, right? Or does it matter if all I'm doing is displaying the data once I get the results? Any help would be greatly appreciated. Thanks!
animals.nim
type
Animals* {.exportc.} = seq[Animal]
Animal* {.exportc.} = object
name*, species*: cstring
proc getAnimal(): Animal {.cdecl,exportc.} =
var animal = Animal(name:"Jimmy",species:"ape")
rresult = animal
proc getAnimals(): Animals {.cdecl,exportc.} =
var animal = Animal(name:"Jimmy",species:"ape")
var animals = newSeq[Animal](1)
animals.add(animal);
result = animals;
animals.c
c
#include "animals.h" // nim generated header file
#include <stdio.h>
int main(void)
{
Animal animal = getAnimal(); // Works fine.
printf("Animal name: %s\n",animal.name);
Animals *animals = getAnimals(); // This is surely wrong, it segfaults
/* what to do here to iterate over the animals? */
}
Since you already use cstring you can go all the way and use ptr UncheckedArray[Animal] instead of seq like so:
type
Animal* {.exportc.} = object
name*, species*: cstring
Animals* {.exportc.} = object
data*: ptr UncheckedArray[Animal]
len*, cap*: int
proc freeAnimals*(a: Animals) =
dealloc(a.data)
proc add*(a: var Animals; b: Animal) =
if a.len >= a.cap:
if a.cap == 0: a.cap = 4
else: a.cap = a.cap * 3 div 2
a.data = cast[typeof(a.data)](realloc(a.data, a.cap * sizeof(Animal)))
a.data[a.len] = b
inc a.len
proc getAnimal(): Animal {.cdecl,exportc.} =
result = Animal(name:"Jimmy",species:"ape")
proc getAnimals(): Animals {.cdecl,exportc.} =
var animal = Animal(name:"Jimmy",species:"ape")
result.add animal
You can also access seq directly from the C code but the code depends on whether you used --gc:arc or not, the seq implementation changed for --gc:arc.
But really, use a Nim main program and import from C what you need. It doesn't matter much how much C you've already written.