Writing a Storable instance for a C union

Could anyone explain how to write a Storable instance for MyStruct? (The key field allows to determine the type of a value inside the union.) typedef enum Key_ { ONE = 1, FOUR = 4, TWENTY = 20 } Key; struct MyStruct { Key key; union { Foo one; uint64_t four; void *twenty; }; }; Also, should I use hsc2hs to make the resulting code portable?

On 12/13/2013 05:00 PM, Nikita Karetnikov wrote:
Could anyone explain how to write a Storable instance for MyStruct? (The key field allows to determine the type of a value inside the union.)
You can peek the "key", and then, depending on its value, return a different constructor : data MyStruct = MyStructOne Foo | MyStructFour Integer | MyStructTwenty [Blah]

You can peek the "key", and then, depending on its value, return a different constructor :
data MyStruct = MyStructOne Foo | MyStructFour Integer | MyStructTwenty [Blah]
OK, but how can I pick one of the union fields? Also, I’d rather change MyStruct to Union in the above since I already defined MyStruct, which has a Storable instance that looks like so (omitting sizeOf, alignment, and poke): instance Storable MyStruct where peek p = do v0 <- peekByteOff p 0 return $ MyStruct v0 This allows to get the value of key, and I could change it to get one of the union fields: instance Storable MyStruct where peek p = do v0 <- peekByteOff p 0 v1 <- peekByteOff p 4 return $ MyStruct v0 v1 But that would require to define a Storable instance for the Union type, which is exactly the point of the thread. How can I do so? (Note that Foo, Word64, and (Ptr a) are instances of Storable themselves.) The other question that remains unanswered is how to make such code portable. Should I rely on hsc2hs to determine things like sizeOf and alignment?

On 12/14/2013 12:24 AM, Nikita Karetnikov wrote:
instance Storable MyStruct where peek p = do v0 <- peekByteOff p 0 v1 <- peekByteOff p 4 return $ MyStruct v0 v1
But that would require to define a Storable instance for the Union type, which is exactly the point of the thread. How can I do so? (Note that Foo, Word64, and (Ptr a) are instances of Storable themselves.)
It's as simple as : peek p = do v0 <- peekByteOff p 0 case v0 of 1 -> MyStruct <$> peekByteOff p 4 2 -> FooStruct <$> peek... But this function can only have a single type, hence my suggestion that you should create a union type to represent the C union : type SomeUnion = MyStruct Byte | FooStruct Integer | ...

It's as simple as :
peek p = do v0 <- peekByteOff p 0 case v0 of 1 -> MyStruct <$> peekByteOff p 4 2 -> FooStruct <$> peek...
But this function can only have a single type, hence my suggestion that you should create a union type to represent the C union :
type SomeUnion = MyStruct Byte | FooStruct Integer | ...
Yes, but I also want to poke, so SomeUnion must be an instance of Storable. Could you show how to define it properly or provide a workaround? I’m attaching some code, which is in the public domain, to demonstrate the problem. It was generated using c2hsc and hsc2hs. The lines marked with XXX were either modified or added by me.

On 12/14/2013 05:46 PM, Nikita Karetnikov wrote:
Yes, but I also want to poke, so SomeUnion must be an instance of Storable. Could you show how to define it properly or provide a workaround?
You do not need to store the "key", or have an additional C'MyStruct data type, as you already have this information in Haskell : data SomeUnion = UnionFoo C'Foo | UnionWord64 Word64 | UnionVoid (Ptr ()) deriving (Show, Eq) instance Storable SomeUnion where sizeOf _ = 12 alignment _ = 4 peek p = do v0 <- peekByteOff p 0 case v0 of 1 -> UnionFoo `fmap` peekByteOff p 4 4 -> UnionWord64 `fmap` peekByteOff p 4 20 -> UnionVoid `fmap` peekByteOff p 4 _ -> fail "you should probably handle this case" poke p (UnionFoo v1) = pokeByteOff p 0 1 >> pokeByteOff p 4 v1 poke p (UnionWord64 v1) = pokeByteOff p 4 1 >> pokeByteOff p 4 v1 poke p (UnionVoid v1) = pokeByteOff p 20 1 >> pokeByteOff p 4 v1
participants (2)
-
Nikita Karetnikov
-
Simon Marechal