MyNixOS website logo
Description

To make a wrapper for struct of C language.

Please see the README on GitHub at https://github.com/YoshikuniJujo/c-struct#readme

c-struct

C definition

foo.h

#ifndef _FOO_H
#define _FOO_H

typedef struct { int x; int y; } Foo;

#endif

foo.c

#include <stdlib.h>
#include <stdio.h>
#include "foo.h"

Foo *
foo_copy(Foo *src)
{
	Foo *p = malloc(sizeof(Foo));
	p -> x = src -> x;
	p -> y = src -> y;
	return p;
}

void
foo_free(Foo *p)
{
	free(p);
}

void
foo_print(Foo *f)
{
	printf("Foo: x = %d, y = %d\n", f -> x, f -> y);
}

void
foo_scale(Foo *f, int s)
{
	f -> x = f -> x * s;
	f -> y = f -> y * s;
}

Immutable

Foo

Foo.hsc

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

module Foo where

import Foreign.Ptr (Ptr)
import Foreign.ForeignPtr (withForeignPtr)
import Foreign.Storable (peekByteOff, pokeByteOff)
import Foreign.C.Types (CInt(..))
import Foreign.C.Struct (struct)

#include "foo.h"

struct "Foo" #{size Foo} #{alignment Foo}
	[	("x", ''CInt, [| #{peek Foo, x} |], [| #{poke Foo, x} |]),
		("y", ''CInt, [| #{peek Foo, y} |], [| #{poke Foo, y} |]) ]
	[''Show, ''Read, ''Eq, ''Ord, ''Bounded, ''Storable]

fooPrint :: Foo -> IO ()
fooPrint (Foo_ f) = withForeignPtr f c_foo_print

foreign import ccall "foo_print" c_foo_print :: Ptr Foo -> IO ()

You get newtype Foo.

> Foo 123 456
Foo {fooX = 123, fooY = 456}
> it { fooY = 654}
Foo {fooX = 123, fooY = 654}
> f = it
> fooPrint f
Foo: x = 123, y = 654
> g = read "Foo {fooX = 456, fooY = 123}" :: Foo
> g
Foo {fooX = 456, fooY = 123}
> f < g
True
> minBound :: Foo
Foo {fooX = -2147483648, fooY = -2147483648}

FooIx

FooIx.hsc

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

module FooIx where

import Foreign.Storable (Storable, peekByteOff, pokeByteOff)
import Foreign.C.Types (CInt(..))
import Foreign.C.Struct (struct)
import Data.Array (Ix(..))

#include "foo.h"

newtype CIntIx = CIntIx CInt
	deriving (Show, Eq, Ord, Enum, Num, Real, Integral, Storable)

struct "FooIx" #{size Foo} #{alignment Foo}
	[	("x", ''CIntIx, [| #{peek Foo, x} |], [| #{poke Foo, x} |]),
		("y", ''CIntIx, [| #{peek Foo, y} |], [| #{poke Foo, y} |]) ]
	[''Show, ''Eq, ''Ord, ''Ix]

instance Ix CIntIx where
	range (l, u) = [l .. u]
	index (l, _) i = fromIntegral $ i - l
	inRange (l, u) i = l <= i && i <= u

You get newtype FooIx.

> :module + Data.Array
> listArray (FooIx 3 5, FooIx 4 7) [5 ..]
array (FooIx {fooIxX = CIntIx 3, fooIxY = CIntIx 5},FooIx {fooIxX = CIntIx 4, fooIxY = CIntIx 7}) [(FooIx {...
> a = it
> a ! FooIx 4 6
9

Mutable

If you want to change values of a struct, you should use structPrim.

FooPrim.hsc

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

module FooPrim where

import Foreign.Ptr (Ptr)
import Foreign.ForeignPtr (withForeignPtr)
import Foreign.Storable (peekByteOff, pokeByteOff)
import Foreign.C.Types (CInt(..))
import Foreign.C.Struct (struct, structPrim)
import Control.Monad.Primitive (PrimMonad(..), unsafeIOToPrim)

#include "foo.h"

struct "Foo" #{size Foo} #{alignment Foo}
	[	("x", ''CInt, [| #{peek Foo, x} |], [| #{poke Foo, x} |]),
		("y", ''CInt, [| #{peek Foo, y} |], [| #{poke Foo, y} |]) ]
	[''Show, ''Read, ''Eq, ''Ord, ''Bounded]

foreign import ccall "foo_copy" c_foo_copy :: Ptr Foo -> IO (Ptr Foo)
foreign import ccall "foo_free" c_foo_free :: Ptr Foo -> IO ()

structPrim "Foo" 'c_foo_copy 'c_foo_free [''Show]

fooScale :: PtimMonad m => FooPrim (PrimState m) -> CInt -> m ()
fooScale (FooPrim f) s = unsafeIOToPrim $ withForeignPtr f (`c_foo_scale` s)

foreign import ccall "foo_scale" c_foo_scale :: Ptr Foo -> CInt -> IO ()

You get FooPrim, FooST, FooIO, fooFreeze, fooThaw and fooCopy.

> :modu	+ Control.Monad.Primitive
> :type fooFreeze
fooFreeze :: PrimMonad m => FooPrim (PrimState m) -> m Foo
> :type fooThaw
fooThaw :: PrimMonad m => Foo -> m (FooPrim (PrimState m))
> :type FooCopy
fooCopy
  :: PrimMonad m =>
     FooPrim (PrimState m) -> m (FooPrim (PrimState m))
> Foo 123 456
Foo {fooX = 123, fooY = 456}
> fooThaw it
FooPrim 0x00000000002354a60
> fp = it
> fooScale fp 3
> fooFreeze fp
Foo {fooX = 369, fooY = 1368}
Metadata

Version

0.1.3.0

Platforms (77)

    Darwin
    FreeBSD
    Genode
    GHCJS
    Linux
    MMIXware
    NetBSD
    none
    OpenBSD
    Redox
    Solaris
    WASI
    Windows
Show all
  • aarch64-darwin
  • aarch64-freebsd
  • aarch64-genode
  • aarch64-linux
  • aarch64-netbsd
  • aarch64-none
  • aarch64-windows
  • aarch64_be-none
  • arm-none
  • armv5tel-linux
  • armv6l-linux
  • armv6l-netbsd
  • armv6l-none
  • armv7a-darwin
  • armv7a-linux
  • armv7a-netbsd
  • armv7l-linux
  • armv7l-netbsd
  • avr-none
  • i686-cygwin
  • i686-darwin
  • i686-freebsd
  • i686-genode
  • i686-linux
  • i686-netbsd
  • i686-none
  • i686-openbsd
  • i686-windows
  • javascript-ghcjs
  • loongarch64-linux
  • m68k-linux
  • m68k-netbsd
  • m68k-none
  • microblaze-linux
  • microblaze-none
  • microblazeel-linux
  • microblazeel-none
  • mips-linux
  • mips-none
  • mips64-linux
  • mips64-none
  • mips64el-linux
  • mipsel-linux
  • mipsel-netbsd
  • mmix-mmixware
  • msp430-none
  • or1k-none
  • powerpc-netbsd
  • powerpc-none
  • powerpc64-linux
  • powerpc64le-linux
  • powerpcle-none
  • riscv32-linux
  • riscv32-netbsd
  • riscv32-none
  • riscv64-linux
  • riscv64-netbsd
  • riscv64-none
  • rx-none
  • s390-linux
  • s390-none
  • s390x-linux
  • s390x-none
  • vc4-none
  • wasm32-wasi
  • wasm64-wasi
  • x86_64-cygwin
  • x86_64-darwin
  • x86_64-freebsd
  • x86_64-genode
  • x86_64-linux
  • x86_64-netbsd
  • x86_64-none
  • x86_64-openbsd
  • x86_64-redox
  • x86_64-solaris
  • x86_64-windows