Как создать хранимый экземпляр для этой структуры без 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 и вашей платформы, однако, вы захотите сделать некоторое обширное тестирование, чтобы убедиться, что он был правильно составлен.