Skip to content

Commit c0322a1

Browse files
committed
WIP Bijective Read/Show instances for patterns
adds helper module Network.Socket.ReadShow for defining bijections between types, to be used for simultaneous read-show equivalence definitions implements read/show instances for SocketOption, SockType, and Family according to this paradigm additionally removes a bug in Network.Socket.Options where the OOBInline pattern name was unintentionally allcaps-ed in one of the CPP ifdef branches
1 parent 82f2fd9 commit c0322a1

File tree

4 files changed

+225
-115
lines changed

4 files changed

+225
-115
lines changed

Network/Socket/Options.hsc

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{-# LANGUAGE CPP #-}
22
{-# LANGUAGE PatternSynonyms #-}
33
{-# LANGUAGE ScopedTypeVariables #-}
4+
{-# LANGUAGE RecordWildCards #-}
45
{-# LANGUAGE ViewPatterns #-}
56

67
#include "HsNet.h"
@@ -25,12 +26,15 @@ module Network.Socket.Options (
2526
, setSockOpt
2627
) where
2728

29+
import qualified Text.Read as P
30+
2831
import Foreign.Marshal.Alloc (alloca)
2932
import Foreign.Marshal.Utils (with)
3033

3134
import Network.Socket.Imports
3235
import Network.Socket.Internal
3336
import Network.Socket.Types
37+
import Network.Socket.ReadShow
3438

3539
-----------------------------------------------------------------------------
3640
-- Socket Properties
@@ -39,10 +43,10 @@ import Network.Socket.Types
3943
--
4044
-- The existence of a constructor does not imply that the relevant option
4145
-- is supported on your system: see 'isSupportedSocketOption'
42-
data SocketOption = SockOpt {
43-
sockOptLevel :: !CInt
44-
, sockOptName :: !CInt
45-
} deriving (Eq, Show)
46+
data SocketOption = SockOpt
47+
!CInt -- ^ Option Level
48+
!CInt -- ^ Option Name
49+
deriving (Eq)
4650

4751
-- | Does the 'SocketOption' exist on this system?
4852
isSupportedSocketOption :: SocketOption -> Bool
@@ -141,7 +145,7 @@ pattern OOBInline :: SocketOption
141145
#ifdef SO_OOBINLINE
142146
pattern OOBInline = SockOpt (#const SOL_SOCKET) (#const SO_OOBINLINE)
143147
#else
144-
pattern OOBINLINE = SockOpt (-1) (-1)
148+
pattern OOBInline = SockOpt (-1) (-1)
145149
#endif
146150
-- | SO_LINGER: timeout in seconds, 0 means disabling/disabled.
147151
pattern Linger :: SocketOption
@@ -376,6 +380,63 @@ getSockOpt s (SockOpt level opt) = do
376380
c_getsockopt fd level opt ptr ptr_sz
377381
peek ptr
378382

383+
384+
socketOptionPairs :: [Pair SocketOption String]
385+
socketOptionPairs =
386+
[ (Debug, "Debug")
387+
, (ReuseAddr, "ReuseAddr")
388+
, (SoDomain, "SoDomain")
389+
, (Type, "Type")
390+
, (SoProtocol, "SoProtocol")
391+
, (SoError, "SoError")
392+
, (DontRoute, "DontRoute")
393+
, (Broadcast, "Broadcast")
394+
, (SendBuffer, "SendBuffer")
395+
, (RecvBuffer, "RecvBuffer")
396+
, (KeepAlive, "KeepAlive")
397+
, (OOBInline, "OOBInline")
398+
, (Linger, "Linger")
399+
, (ReusePort, "ReusePort")
400+
, (RecvLowWater, "RecvLowWater")
401+
, (SendLowWater, "SendLowWater")
402+
, (RecvTimeOut, "RecvTimeOut")
403+
, (SendTimeOut, "SendTimeOut")
404+
, (UseLoopBack, "UseLoopBack")
405+
, (MaxSegment, "MaxSegment")
406+
, (NoDelay, "NoDelay")
407+
, (UserTimeout, "UserTimeout")
408+
, (Cork, "Cork")
409+
, (TimeToLive, "TimeToLive")
410+
, (RecvIPv4TTL, "RecvIPv4TTL")
411+
, (RecvIPv4TOS, "RecvIPv4TOS")
412+
, (RecvIPv4PktInfo, "RecvIPv4PktInfo")
413+
, (IPv6Only, "IPv6Only")
414+
, (RecvIPv6HopLimit, "RecvIPv6HopLimit")
415+
, (RecvIPv6TClass, "RecvIPv6TClass")
416+
, (RecvIPv6PktInfo, "RecvIPv6PktInfo")
417+
]
418+
419+
socketOptionBijection :: Bijection SocketOption String
420+
socketOptionBijection = Bijection{..}
421+
where
422+
cso = "CustomSockOpt"
423+
_parse :: String -> (CInt, CInt)
424+
_parse xy =
425+
let (xs, ('_':ys)) = break (=='_') xy
426+
in (read xs, read ys)
427+
defFwd = \(CustomSockOpt (n,m)) -> cso++show n++"_"++show m
428+
defBwd s = case splitAt (length cso) s of
429+
("CustomSockOpt", nm) -> CustomSockOpt $ _parse nm
430+
_ -> error "socketOptionBijection: exception in WIP ReadShow code"
431+
pairs = socketOptionPairs
432+
433+
instance Show SocketOption where
434+
show = forward socketOptionBijection
435+
436+
instance Read SocketOption where
437+
readPrec = P.lexP >>= \(P.Ident x) -> return $ backward socketOptionBijection x
438+
439+
379440
foreign import CALLCONV unsafe "getsockopt"
380441
c_getsockopt :: CInt -> CInt -> CInt -> Ptr a -> Ptr CInt -> IO CInt
381442
foreign import CALLCONV unsafe "setsockopt"

Network/Socket/ReadShow.hs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{-# LANGUAGE RecordWildCards #-}
2+
3+
module Network.Socket.ReadShow where
4+
5+
-- type alias for individual correspondences of a (possibly partial) bijection
6+
type Pair a b = (a, b)
7+
8+
-- | helper function for equality on first tuple element
9+
{-# INLINE eqFst #-}
10+
eqFst :: Eq a => a -> (a, b) -> Bool
11+
eqFst x = \(x',_) -> x' == x
12+
13+
-- | helper function for equality on snd tuple element
14+
{-# INLINE eqSnd #-}
15+
eqSnd :: Eq b => b -> (a, b) -> Bool
16+
eqSnd y = \(_,y') -> y' == y
17+
18+
-- | Return RHS element that is paired with provided LHS,
19+
-- or apply a default fallback function if the list is partial
20+
lookForward :: Eq a => (a -> b) -> [Pair a b] -> a -> b
21+
lookForward defFwd ps x
22+
= case filter (eqFst x) ps of
23+
(_,y):_ -> y
24+
[] -> defFwd x
25+
26+
-- | Return LHS element that is paired with provided RHS,
27+
-- or apply a default fallback function if the list is partial
28+
lookBackward :: Eq b => (b -> a) -> [Pair a b] -> b -> a
29+
lookBackward defBwd ps y
30+
= case filter (eqSnd y) ps of
31+
(x,_):_ -> x
32+
[] -> defBwd y
33+
34+
data Bijection a b
35+
= Bijection
36+
{ defFwd :: a -> b
37+
, defBwd :: b -> a
38+
, pairs :: [Pair a b]
39+
}
40+
41+
forward :: (Eq a) => Bijection a b -> a -> b
42+
forward Bijection{..} = lookForward defFwd pairs
43+
44+
backward :: (Eq b) => Bijection a b -> b -> a
45+
backward Bijection{..} = lookBackward defBwd pairs

0 commit comments

Comments
 (0)