I'm using the chipmunk7 library bindings, and trying to call the iterator eachShape. The bindings source is here
SpaceShapeIteratorFunc* = proc (shape: Shape; data: pointer) {.cdecl.}
## Space/body iterator callback function type.
[..]
proc eachShape*(space: Space; `func`: SpaceShapeIteratorFunc; data: pointer) {.cdecl, importc: "cpSpaceEachShape".}
## Call `func` for each shape in the space.
And calling like this
import std/math
import chipmunk7
import playdate/api
var gravity = v(0, 100)
var timeStep = 1.0/50.0
var time = 0.0
var space = newSpace()
space.gravity = gravity
[..]
proc drawChipmunkHello*() =
# iterate over all shapes in the space
for shape in eachShape(space):
if shape.shapeType == ShapeType.circle:
let circle = shape as CircleShape
drawCircle(circle.body.position, circle.radius, circle.body.angle, kColorBlack)
elif shape.shapeType == ShapeType.segment:
let segment = shape as SegmentShape
drawSegment(segment, kColorBlack)
elif shape.shapeType == ShapeType.poly:
let poly = shape as PolyShape
for i in 0 ..< poly.count:
let a = poly.getVert(i)
let b = poly.getVert((i + 1) % poly.count)
playdate.graphics.drawLine(a.x.toInt, a.y.toInt, b.x.toInt, b.y.toInt, 1, kColorBlack);
I get the coompiler error
hello.nim(63, 25) Error: type mismatch: got <Space>
but expected one of:
proc eachShape(space: Space; func: SpaceShapeIteratorFunc; data: pointer)
first type mismatch at position: 2
missing parameter: func
1 other mismatching symbols have been suppressed; compile with --showAllMismatches:on to see them
Line 63 being the first line of drawChipmunkHello()
A c-sample of how to call the iterator is here
What is the correct syntax to call the iterator?
What Chipmunk calls an iterator and what Nim calls an iterator are two different things. The way you're trying to call
eachShapeis indeed correct for a Nim iterator with one parameter. But the three-parameter construct that Chipmunk calls an iterator is not callable this way. Let's look at the error message, it say thateachShapewhere given<Space>, i.e. a single argument of typeSpacebut it expected:which is three arguments
Space,SpaceShapeIteratorFunc, and apointer. It also tells us that the type mismatch happened at position 2 and that it failed because it was simply missing thefuncargument, which makes sense, because we only provided oneSpaceargument. Now, let's have a look atSpaceShapeIteratorFunc:As we can see this is simply an alias for a procedure which takes a
Shapeand apointer. It is also defined as being{.cdecl.}which just means that it follows the standard C calling convention. What this means is that we have to convert the body of your loop into a procedure, and then manually pass that procedure to the iterator. Thepointerthat is accepted bySpaceShapeIteratorFuncand required byeachShapeis where we can store any context that we want to have available in the iterator.Let's do a simple rewrite:
As you can see we've now split the body of the iterator body into a new procedure
shapeIterwhich matches the signature ofSpaceShapeIteratorFuncand we pass this along toeachShapetogether with anilpointer because we don't need to pass any context. The reason we don't have to pass any context is because all the variables required live in the global scope of our module. If we indeed needed some context to be passed along into the body of the iterator we would need to pass this via thedata: pointerfield. This is quite common in C, but can be a bit cumbersome to do in Nim. This is a bit more of an advanced topic, but you could use a Nim closure for this and get the procedure and environment pointers withrawProcandrawEnvrespectively. Note thatrawProcstill has a{.nimcall.}calling convention, so a caller helper proc would be required. All of this complexity could be put into a custom for loop macro at which point you would be able to call the iterator like you did in your first example. But this is getting into some quite complex territory.