Skip to content

Commit 1312180

Browse files
committed
Third attempt
1 parent b24fc07 commit 1312180

14 files changed

Lines changed: 1284 additions & 645 deletions

File tree

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,67 @@
1+
{-# LANGUAGE TypeApplications #-}
2+
13
-- | High-level wrappers around the generated qrcodegen bindings.
4+
--
25
module HighLevel (
36
encodeText
47
, getSize
58
, getModule
69
) where
710

811
import Data.Word (Word8)
9-
import Foreign.Marshal.Utils qualified as Marshal
1012
import Foreign.Ptr (Ptr)
1113

12-
import HsBindgen.Runtime.HighLevel.Refine (OutMarshaller, input, output,
13-
peekIncompleteArrayOut, pureIn,
14-
pureRes, result, scratchOut,
15-
toHighLevel, withCStringIn,
16-
withConstIncompleteArrayIn)
14+
import HsBindgen.Runtime.HighLevel.ToHighLevel (OutMarshaller, input, output,
15+
pureIn, scratchArray,
16+
toHighLevel)
17+
import HsBindgen.Runtime.HighLevel.ToHighLevel.Defaults (defaultIn, defaultRes)
18+
import HsBindgen.Runtime.HighLevel.ToHighLevel.Marshallers (peekIncompleteArrayOut,
19+
withCStringIn,
20+
withConstIncompleteArrayIn)
1721
import HsBindgen.Runtime.IncompleteArray (IncompleteArray)
1822

1923
import QRCodeGenerator.Generated qualified as QR
2024
import QRCodeGenerator.Generated.Safe qualified as QR
2125

22-
-- | Lift @qrcodegen_encodeText@. Destructure the leading scratch @()@ at
23-
-- the call site.
26+
-- | Lift @qrcodegen_encodeText@. @tempBuffer@ is a 'scratchArray', so it adds
27+
-- nothing to the result: only the QR code and the success flag come back. The
28+
-- scalar inputs and the result use default marshallers.
2429
encodeText
2530
:: String
2631
-> QR.Qrcodegen_Ecc
2732
-> Int
2833
-> Int
2934
-> QR.Qrcodegen_Mask
3035
-> Bool
31-
-> IO ((), (IncompleteArray Word8, Bool))
36+
-> IO (IncompleteArray Word8, Bool)
3237
encodeText = toHighLevel
33-
( input withCStringIn
34-
$ output tempScratch
35-
$ output qrCodeOut
36-
$ input (pureIn id)
37-
$ input (pureIn fromIntegral)
38-
$ input (pureIn fromIntegral)
39-
$ input (pureIn id)
40-
$ input (pureIn Marshal.fromBool)
41-
$ result (pureRes Marshal.toBool)
38+
( input withCStringIn
39+
$ scratchArray @Word8 maxLen -- tempBuffer: written, never read
40+
$ output qrCodeOut
41+
$ input (pureIn id) -- ecc level (enum, passthrough)
42+
$ input defaultIn -- minVersion (Int -> CInt)
43+
$ input defaultIn -- maxVersion (Int -> CInt)
44+
$ input (pureIn id) -- mask (enum, passthrough)
45+
$ input defaultIn -- boostEcl (Bool -> CBool)
46+
$ defaultRes -- CBool -> Bool
4247
) QR.qrcodegen_encodeText
4348
where
4449
maxLen :: Int
4550
maxLen = fromIntegral QR.qrcodegen_BUFFER_LEN_MAX
4651

47-
tempScratch :: OutMarshaller (Ptr Word8) ()
48-
tempScratch = scratchOut maxLen
49-
5052
qrCodeOut :: OutMarshaller (Ptr Word8) (IncompleteArray Word8)
5153
qrCodeOut = peekIncompleteArrayOut maxLen
5254

5355
getSize :: IncompleteArray Word8 -> IO Int
5456
getSize = toHighLevel
5557
( input withConstIncompleteArrayIn
56-
$ result (pureRes fromIntegral)
58+
$ defaultRes
5759
) QR.qrcodegen_getSize
5860

5961
getModule :: IncompleteArray Word8 -> Int -> Int -> IO Bool
6062
getModule = toHighLevel
6163
( input withConstIncompleteArrayIn
62-
$ input (pureIn fromIntegral)
63-
$ input (pureIn fromIntegral)
64-
$ result (pureRes Marshal.toBool)
64+
$ input defaultIn -- x (Int -> CInt)
65+
$ input defaultIn -- y (Int -> CInt)
66+
$ defaultRes -- CBool -> Bool
6567
) QR.qrcodegen_getModule

examples/c-qrcode/hs-project/app/Main.hs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
module Main where
44

5-
import Control.Monad (guard)
5+
import Control.Monad (when)
66
import Data.Bool (bool)
77
import Data.Foldable (for_)
88
import Data.Word (Word8)
@@ -46,15 +46,15 @@ printQr qrCode = do
4646
-- }
4747
basicDemo :: IO ()
4848
basicDemo = do
49-
((), (qrCode, ok)) <- HL.encodeText
50-
"Hello, world!"
49+
(qrCode, ok) <- HL.encodeText
50+
"Hello, world!"
5151
QR.Qrcodegen_Ecc_LOW
5252
(fromIntegral QR.qrcodegen_VERSION_MIN)
5353
(fromIntegral QR.qrcodegen_VERSION_MAX)
5454
QR.Qrcodegen_Mask_AUTO
5555
True
56-
guard ok
57-
printQr qrCode
56+
-- Mirror the C original's `if (ok) printQr(qrcode);` — silently skip on failure.
57+
when ok $ printQr qrCode
5858

5959
main :: IO ()
6060
main = basicDemo

examples/libpcap/hs-project/app/HighLevel.hs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{-# LANGUAGE DerivingStrategies #-}
22

33
-- | High-level wrappers around the generated libpcap bindings.
4+
--
45
module HighLevel (
56
PcapError (..)
67
, findAllDevNames
@@ -14,27 +15,28 @@ import Foreign.Marshal.Alloc (alloca)
1415
import Foreign.Ptr (Ptr, nullPtr)
1516
import Foreign.Storable (peek)
1617

17-
import HsBindgen.Runtime.HighLevel.Refine (OutMarshaller (..), output,
18-
peekCStringOut, pureRes, result,
19-
toHighLevel)
18+
import HsBindgen.Runtime.HighLevel.ToHighLevel (OutMarshaller, mkOut, output,
19+
resultPure, toHighLevel)
20+
import HsBindgen.Runtime.HighLevel.ToHighLevel.Marshallers (peekCStringOut)
2021

2122
import Generated.Pcap qualified as Pcap
2223
import Generated.Pcap.Safe qualified as Pcap
2324

2425
-- | Thrown by 'findAllDevNames' when @pcap_findalldevs@ reports failure.
26+
--
2527
data PcapError = PcapError { msg :: String, code :: CInt }
2628
deriving stock (Show)
2729
instance Exception PcapError
2830

2931
-- | Allocate a @pcap_if_t **@, walk the linked list after the call, free it.
32+
--
3033
peekPcapDeviceNames
3134
:: OutMarshaller (Ptr (Ptr Pcap.Pcap_if_t)) [String]
32-
peekPcapDeviceNames = OutMarshaller $ \k -> alloca $ \pp -> do
33-
r <- k pp
35+
peekPcapDeviceNames = mkOut alloca $ \pp -> do
3436
headPtr <- peek pp
3537
names <- collect [] headPtr
3638
Pcap.pcap_freealldevs headPtr
37-
pure (names, r)
39+
pure names
3840
where
3941
collect acc ptr
4042
| ptr == nullPtr = pure (reverse acc)
@@ -46,12 +48,13 @@ peekPcapDeviceNames = OutMarshaller $ \k -> alloca $ \pp -> do
4648
-- | Collect the names of all devices visible to libpcap. The status check
4749
-- runs after the spec rather than inside a 'throwOn' because the error
4850
-- buffer lives in a separate output position.
51+
--
4952
findAllDevNames :: IO [String]
5053
findAllDevNames = do
51-
(names, (errMsg, status)) <- toHighLevel
54+
(names, errMsg, status) <- toHighLevel
5255
( output peekPcapDeviceNames
5356
$ output (peekCStringOut (fromIntegral Pcap.pCAP_ERRBUF_SIZE))
54-
$ result (pureRes id)
57+
$ resultPure id
5558
) Pcap.pcap_findalldevs
5659
when (status /= 0) $ throwIO (PcapError errMsg status)
5760
pure names

hs-bindgen-runtime/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ None
1313
* Add `get`/`set` functions that serve as getters/setters for union values.
1414
These depend `HasField` instances. See [issue #2060][is-2060] and [PR
1515
#2091][pr-2091].
16+
* Add a combinator library for hand-writing high-level wrappers over the
17+
generated low-level FFI bindings.
1618

1719
### Minor changes
1820

hs-bindgen-runtime/hs-bindgen-runtime.cabal

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,10 @@ library
7777
HsBindgen.Runtime.FLAM
7878
HsBindgen.Runtime.HasCBitfield
7979
HsBindgen.Runtime.HasCField
80-
HsBindgen.Runtime.HighLevel.Refine
80+
HsBindgen.Runtime.HighLevel.ToHighLevel
81+
HsBindgen.Runtime.HighLevel.ToHighLevel.Defaults
82+
HsBindgen.Runtime.HighLevel.ToHighLevel.Errors
83+
HsBindgen.Runtime.HighLevel.ToHighLevel.Marshallers
8184
HsBindgen.Runtime.IncompleteArray
8285
HsBindgen.Runtime.Internal.Bitfield
8386
HsBindgen.Runtime.Internal.ByteArray
@@ -133,7 +136,8 @@ test-suite test-hs-bindgen-runtime
133136
Test.HsBindgen.Runtime.CEnum
134137
Test.HsBindgen.Runtime.CEnumArbitrary
135138
Test.HsBindgen.Runtime.ConstantArray
136-
Test.HsBindgen.Runtime.HighLevel.RefineSmoke
139+
Test.HsBindgen.Runtime.HighLevel.CoreDump
140+
Test.HsBindgen.Runtime.HighLevel.Test
137141
Test.HsBindgen.Runtime.IncompleteArray
138142
Test.HsBindgen.Runtime.SizedByteArray
139143
Test.Util.Orphans

0 commit comments

Comments
 (0)