Как создать хранимый экземпляр для этой структуры без c2hs или других инструментов?
Эта структура:
typedef struct Atom_ {
float x;
float y;
float z;
int col;
} Atom;
соответствует этому типу:
data Atom = Atom { pos :: V3 Float, col :: Int }
Как создать хранимый экземпляр для Atom
так что я могу отправить Atom
S на Haskell к функции C, которая ожидает Atom
?
1 ответ
Решение
В настоящее время я не могу гарантировать, что это будет работать точно так, как показано (у меня не настроена среда на этом компьютере), но это должен быть хороший первый шаг к правильной настройке:
import Foreign.Storable
import Foreign.Ptr
instance Storable Atom where
-- Don't make this static, let the compiler choose depending
-- on the platform
sizeOf _ = 3 * sizeOf (0 :: Float) + sizeOf (0 :: Int)
-- You may need to fiddle with this, and with your corresponding C
-- code if you have the ability to, alignment can be tricky, but
-- in this case you can pretty safely assume it'll be the alignment
-- for `Float`
alignment _ = alignment (0 :: Float)
-- These are pretty straightforward, and obviously order matters here
-- a great deal. I clearly haven't made this the most optimized it
-- could be, I'm going for clarity of code instead
peek ptr = do
let floatSize = sizeOf (0 :: Float)
x <- peek $ ptr `plusPtr` (0 * floatSize)
y <- peek $ ptr `plusPtr` (1 * floatSize)
z <- peek $ ptr `plusPtr` (2 * floatSize)
col <- peek $ ptr `plusPtr` (3 * floatSize)
return $ Atom (V3 x y z) col
poke ptr (Atom (V3 x y z) col) = do
let floatSize = sizeOf (0 :: Float)
poke (ptr `plusPtr` (0 * floatSize)) x
poke (ptr `plusPtr` (1 * floatSize)) y
poke (ptr `plusPtr` (2 * floatSize)) z
poke (ptr `plusPtr` (3 * floatSize)) col
И это должно сработать! Он может сильно зависеть от вашего компилятора C и вашей платформы, однако вам нужно будет провести обширное тестирование, чтобы убедиться, что оно правильно выложено.